1717#ifdef  HAVE_SIGNAL_H 
1818#  include  <signal.h>              // SIGINT 
1919#endif 
20+ #ifdef  HAVE_PTHREAD_H 
21+ #  include  <pthread.h> 
22+ #endif 
23+ #include  <errno.h> 
2024
2125// ThreadError is just an alias to PyExc_RuntimeError 
2226#define  ThreadError  PyExc_RuntimeError
@@ -71,22 +75,59 @@ get_thread_state_by_cls(PyTypeObject *cls)
7175    return  get_thread_state (module );
7276}
7377
78+ // Helper to set the thread name using platform-specific APIs 
79+ static  int 
80+ set_native_thread_name (const  char  * name )
81+ {
82+ #ifdef  __APPLE__ 
83+     return  pthread_setname_np (name );
84+ #elif  defined(__NetBSD__ )
85+     pthread_t  thread  =  pthread_self ();
86+     return  pthread_setname_np (thread , "%s" , (void  * )name );
87+ #elif  defined(HAVE_PTHREAD_SETNAME_NP )
88+     pthread_t  thread  =  pthread_self ();
89+     return  pthread_setname_np (thread , name );
90+ #elif  defined(HAVE_PTHREAD_SET_NAME_NP )
91+     pthread_t  thread  =  pthread_self ();
92+     pthread_set_name_np (thread , name );
93+     return  0 ; /* pthread_set_name_np() returns void */ 
94+ #else 
95+     return  0 ;
96+ #endif 
97+ }
98+ 
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 ;
110+     }
111+ #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+         if  (truncated  ==  NULL ) {
115+             Py_DECREF (name_encoded );
116+             return  NULL ;
117+         }
118+         Py_SETREF (name_encoded , truncated );
119+     }
120+ #endif 
121+     return  name_encoded ;
122+ }
123+ 
74124#ifdef  MS_WINDOWS 
75125typedef  HRESULT  (WINAPI  * PF_GET_THREAD_DESCRIPTION )(HANDLE , PCWSTR * );
76126typedef  HRESULT  (WINAPI  * PF_SET_THREAD_DESCRIPTION )(HANDLE , PCWSTR );
77127static  PF_GET_THREAD_DESCRIPTION  pGetThreadDescription  =  NULL ;
78128static  PF_SET_THREAD_DESCRIPTION  pSetThreadDescription  =  NULL ;
79129#endif 
80130
81- #if  defined(HAVE_PTHREAD_SETNAME_NP ) ||  defined(HAVE_PTHREAD_SET_NAME_NP )
82- static  int  _set_thread_name (const  char  * name );
83- #endif 
84- 
85- // Fallback: Provides a no-op implementation if neither pthread naming API is available. This avoids linker errors and provides a portable stub. 
86- #if  !defined(HAVE_PTHREAD_SETNAME_NP ) &&  !defined(HAVE_PTHREAD_SET_NAME_NP )
87- static  int  _set_thread_name (const  char  * name ) { return  0 ; }
88- #endif 
89- 
90131
91132/*[clinic input] 
92133module _thread 
@@ -2584,100 +2625,52 @@ _thread.set_name
25842625Set the name of the current thread. 
25852626[clinic start generated code]*/ 
25862627
2587- 
2588- #ifndef  MS_WINDOWS 
2589- // Helper to set the thread name using platform-specific APIs (POSIX only) 
2590- static  int 
2591- _set_thread_name (const  char  * name )
2592- {
2593-     int  rc ;
2594- #ifdef  __APPLE__ 
2595-     rc  =  pthread_setname_np (name );
2596- #elif  defined(__NetBSD__ )
2597-     pthread_t  thread  =  pthread_self ();
2598-     rc  =  pthread_setname_np (thread , "%s" , (void  * )name );
2599- #elif  defined(HAVE_PTHREAD_SETNAME_NP )
2600-     pthread_t  thread  =  pthread_self ();
2601-     rc  =  pthread_setname_np (thread , name );
2602- #else  /* defined(HAVE_PTHREAD_SET_NAME_NP) */ 
2603-     pthread_t  thread  =  pthread_self ();
2604-     rc  =  0 ; /* pthread_set_name_np() returns void */ 
2605-     pthread_set_name_np (thread , name );
2606- #endif 
2607-     return  rc ;
2608- }
2609- #endif  // !MS_WINDOWS 
2610- 
2611- 
26122628static  PyObject  * 
26132629_thread_set_name_impl (PyObject  * module , PyObject  * name_obj )
26142630/*[clinic end generated code: output=402b0c68e0c0daed input=7e7acd98261be82f]*/ 
26152631{
26162632#ifndef  MS_WINDOWS 
2617-     // POSIX and non-Windows platforms 
2618- #ifdef  __sun 
2619-     const  char  * encoding  =  "utf-8" ;
2620- #else 
26212633    PyInterpreterState  * interp  =  _PyInterpreterState_GET ();
26222634    const  char  * encoding  =  interp -> unicode .fs_codec .encoding ;
2623- #endif 
2624-     PyObject  * name_encoded ;
2625-     int  rc ;
2626- 
2627-     name_encoded  =  PyUnicode_AsEncodedString (name_obj , encoding , "replace" );
2635+     PyObject  * name_encoded  =  encode_thread_name (name_obj , encoding );
26282636    if  (name_encoded  ==  NULL ) {
26292637        return  NULL ;
26302638    }
2631- #ifdef  _PYTHREAD_NAME_MAXLEN 
2632-     if  (PyBytes_GET_SIZE (name_encoded ) >  _PYTHREAD_NAME_MAXLEN ) {
2633-         PyObject  * truncated  =  PyBytes_FromStringAndSize (PyBytes_AS_STRING (name_encoded ), _PYTHREAD_NAME_MAXLEN );
2634-         if  (truncated  ==  NULL ) {
2635-             Py_DECREF (name_encoded );
2636-             return  NULL ;
2637-         }
2638-         Py_SETREF (name_encoded , truncated );
2639-     }
2640- #endif 
26412639    const  char  * name  =  PyBytes_AS_STRING (name_encoded );
2642-     rc  =  _set_thread_name (name );
2643-     Py_DECREF (name_encoded );
2644- 
2645-     // Fallback: If EINVAL, try ASCII encoding with "replace" 
2646-     if  (rc  ==  EINVAL ) {
2647-         name_encoded  =  PyUnicode_AsEncodedString (name_obj , "ascii" , "replace" );
2648-         if  (name_encoded  ==  NULL ) {
2649-             return  NULL ;
2650-         }
2651- #ifdef  _PYTHREAD_NAME_MAXLEN 
2652-         if  (PyBytes_GET_SIZE (name_encoded ) >  _PYTHREAD_NAME_MAXLEN ) {
2653-             PyObject  * truncated  =  PyBytes_FromStringAndSize (PyBytes_AS_STRING (name_encoded ), _PYTHREAD_NAME_MAXLEN );
2654-             if  (truncated  ==  NULL ) {
2655-                 Py_DECREF (name_encoded );
2640+     int  rc  =  set_native_thread_name (name );
2641+     if  (rc ) {
2642+         int  err  =  rc ;
2643+         Py_DECREF (name_encoded );
2644+         if  (err  ==  EINVAL  &&  strcmp (encoding , "ascii" ) !=  0 ) {
2645+             // Retry with ASCII encoding and 'replace' if not already ASCII 
2646+             name_encoded  =  encode_thread_name (name_obj , "ascii" );
2647+             if  (name_encoded  ==  NULL ) {
26562648                return  NULL ;
26572649            }
2658-             Py_SETREF (name_encoded , truncated );
2650+             name  =  PyBytes_AS_STRING (name_encoded );
2651+             rc  =  set_native_thread_name (name );
2652+             if  (rc ) {
2653+                 err  =  rc ;
2654+                 Py_DECREF (name_encoded );
2655+                 errno  =  err ;
2656+                 return  PyErr_SetFromErrno (PyExc_OSError );
2657+             }
2658+             Py_DECREF (name_encoded );
2659+             Py_RETURN_NONE ;
26592660        }
2660- #endif 
2661-         name  =  PyBytes_AS_STRING (name_encoded );
2662-         rc  =  _set_thread_name (name );
2663-         Py_DECREF (name_encoded );
2664-     }
2665- 
2666-     if  (rc ) {
2667-         errno  =  rc ;
2661+         errno  =  err ;
26682662        return  PyErr_SetFromErrno (PyExc_OSError );
26692663    }
2664+     Py_DECREF (name_encoded );
26702665    Py_RETURN_NONE ;
26712666#else 
26722667    // Windows implementation 
26732668    assert (pSetThreadDescription  !=  NULL );
2674- 
26752669    Py_ssize_t  len ;
26762670    wchar_t  * name  =  PyUnicode_AsWideCharString (name_obj , & len );
26772671    if  (name  ==  NULL ) {
26782672        return  NULL ;
26792673    }
2680- 
26812674    if  (len  >  _PYTHREAD_NAME_MAXLEN ) {
26822675        // Truncate the name 
26832676        Py_UCS4  ch  =  name [_PYTHREAD_NAME_MAXLEN - 1 ];
@@ -2688,7 +2681,6 @@ _thread_set_name_impl(PyObject *module, PyObject *name_obj)
26882681            name [_PYTHREAD_NAME_MAXLEN ] =  0 ;
26892682        }
26902683    }
2691- 
26922684    HRESULT  hr  =  pSetThreadDescription (GetCurrentThread (), name );
26932685    PyMem_Free (name );
26942686    if  (FAILED (hr )) {
@@ -2932,4 +2924,4 @@ PyMODINIT_FUNC
29322924PyInit__thread (void )
29332925{
29342926    return  PyModuleDef_Init (& thread_module );
2935- }
2927+ }
0 commit comments