@@ -75,61 +75,93 @@ get_thread_state_by_cls(PyTypeObject *cls)
7575 return get_thread_state (module );
7676}
7777
78- // Helper to set the thread name using platform-specific APIs
7978static int
80- set_native_thread_name ( const char * name )
79+ set_thread_name_with_encoding ( PyObject * name_obj , const char * encoding )
8180{
82- int rc ;
81+ PyObject * name_encoded = NULL ;
82+
83+ #ifndef MS_WINDOWS
84+ /* Determine encoding to use. If encoding arg is NULL, use FS codec. */
85+ const char * enc = encoding ;
86+ #ifdef __sun
87+ enc = "utf-8" ; /* Solaris always uses UTF-8 */
88+ #else
89+ if (enc == NULL ) {
90+ PyInterpreterState * interp = _PyInterpreterState_GET ();
91+ enc = interp -> unicode .fs_codec .encoding ;
92+ }
93+ #endif
94+
95+ name_encoded = PyUnicode_AsEncodedString (name_obj , enc , "replace" );
96+ if (name_encoded == NULL ) {
97+ return -1 ; /* Python exception set */
98+ }
99+
100+ #ifdef _PYTHREAD_NAME_MAXLEN
101+ /* Truncate to _PYTHREAD_NAME_MAXLEN bytes if needed */
102+ if (PyBytes_GET_SIZE (name_encoded ) > _PYTHREAD_NAME_MAXLEN ) {
103+ PyObject * truncated = PyBytes_FromStringAndSize (
104+ PyBytes_AS_STRING (name_encoded ),
105+ _PYTHREAD_NAME_MAXLEN );
106+ if (truncated == NULL ) {
107+ Py_DECREF (name_encoded );
108+ return -1 ; /* Python exception set */
109+ }
110+ Py_SETREF (name_encoded , truncated );
111+ }
112+ #endif
113+
114+ const char * name = PyBytes_AS_STRING (name_encoded );
115+
83116#ifdef __APPLE__
84- rc = pthread_setname_np (name );
117+ int rc = pthread_setname_np (name );
85118#elif defined(__NetBSD__ )
86119 pthread_t thread = pthread_self ();
87- rc = pthread_setname_np (thread , "%s" , (void * )name );
120+ int rc = pthread_setname_np (thread , "%s" , (void * )name );
88121#elif defined(HAVE_PTHREAD_SETNAME_NP )
89122 pthread_t thread = pthread_self ();
90- rc = pthread_setname_np (thread , name );
91- #elif defined(HAVE_PTHREAD_SET_NAME_NP )
123+ int rc = pthread_setname_np (thread , name );
124+ #else
125+ /* pthread_set_name_np() (void) on some platforms */
92126 pthread_t thread = pthread_self ();
127+ int rc = 0 ;
93128 pthread_set_name_np (thread , name );
94- rc = 0 ; /* pthread_set_name_np() returns void */
95129#endif
96- return rc ;
97- }
98130
99- // Helper to encode and truncate thread name
100- static PyObject *
101- encode_thread_name (PyObject * name_obj , const char * encoding )
102- {
103- #ifdef __sun
104- // Solaris always uses UTF-8
105- encoding = "utf-8" ;
106- #endif
107- PyObject * name_encoded = PyUnicode_AsEncodedString (name_obj , encoding , "replace" );
108- if (name_encoded == NULL ) {
109- return NULL ;
131+ Py_DECREF (name_encoded );
132+ return rc ; /* 0 on success, errno-style >0 on error */
133+ #else
134+ /* Windows: convert to wide string and call SetThreadDescription */
135+ assert (pSetThreadDescription != NULL );
136+ Py_ssize_t len ;
137+ wchar_t * wname = PyUnicode_AsWideCharString (name_obj , & len );
138+ if (wname == NULL ) {
139+ return -1 ; /* Python exception set */
110140 }
141+
142+ /* Truncate if necessary (len is number of wchar_t characters) */
111143#ifdef _PYTHREAD_NAME_MAXLEN
112- if (PyBytes_GET_SIZE (name_encoded ) > _PYTHREAD_NAME_MAXLEN ) {
113- PyObject * truncated = PyBytes_FromStringAndSize (PyBytes_AS_STRING (name_encoded ), _PYTHREAD_NAME_MAXLEN );
114- Py_DECREF (name_encoded );
115- return truncated ;
144+ if (len > _PYTHREAD_NAME_MAXLEN ) {
145+ /* Ensure we null-terminate safely. Use maxlen as max characters allowed. */
146+ /* If the char at max-1 is a high surrogate, avoid chopping the surrogate pair. */
147+ Py_UCS4 ch = (Py_UCS4 )wname [_PYTHREAD_NAME_MAXLEN - 1 ];
148+ if (Py_UNICODE_IS_HIGH_SURROGATE (ch ) && _PYTHREAD_NAME_MAXLEN >= 2 ) {
149+ wname [_PYTHREAD_NAME_MAXLEN - 1 ] = L'\0' ;
150+ } else {
151+ wname [_PYTHREAD_NAME_MAXLEN ] = L'\0' ;
152+ }
116153 }
117154#endif
118- return name_encoded ;
119- }
120155
121- // Helper to encode, set, and cleanup thread name in one step
122- static int
123- set_thread_name_with_encoding (PyObject * name_obj , const char * encoding )
124- {
125- PyObject * name_encoded = encode_thread_name (name_obj , encoding );
126- if (name_encoded == NULL ) {
127- return -1 ; // error, exception set
156+ HRESULT hr = pSetThreadDescription (GetCurrentThread (), wname );
157+ PyMem_Free (wname );
158+ if (FAILED (hr )) {
159+ /* Convert to a Python exception and return -1 so caller propagates it */
160+ PyErr_SetFromWindowsErr ((int )hr );
161+ return -1 ;
128162 }
129- const char * name = PyBytes_AS_STRING (name_encoded );
130- int rc = set_native_thread_name (name );
131- Py_DECREF (name_encoded );
132- return rc ;
163+ return 0 ;
164+ #endif
133165}
134166
135167#ifdef MS_WINDOWS
0 commit comments