@@ -71,14 +71,17 @@ get_thread_state_by_cls(PyTypeObject *cls)
7171    return  get_thread_state (module );
7272}
7373
74- 
7574#ifdef  MS_WINDOWS 
7675typedef  HRESULT  (WINAPI  * PF_GET_THREAD_DESCRIPTION )(HANDLE , PCWSTR * );
7776typedef  HRESULT  (WINAPI  * PF_SET_THREAD_DESCRIPTION )(HANDLE , PCWSTR );
7877static  PF_GET_THREAD_DESCRIPTION  pGetThreadDescription  =  NULL ;
7978static  PF_SET_THREAD_DESCRIPTION  pSetThreadDescription  =  NULL ;
8079#endif 
8180
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+ 
8285
8386/*[clinic input] 
8487module _thread 
@@ -2576,24 +2579,12 @@ _thread.set_name
25762579Set the name of the current thread. 
25772580[clinic start generated code]*/ 
25782581
2582+ 
2583+ #ifndef  MS_WINDOWS 
2584+ // Helper to set the thread name using platform-specific APIs (POSIX only) 
25792585static  int 
2580- _set_thread_name_encoded ( PyObject   * name_obj ,  const  char  * encoding ,  int   * perrno )
2586+ _set_thread_name ( const  char  * name )
25812587{
2582-     PyObject  * name_encoded  =  PyUnicode_AsEncodedString (name_obj , encoding , "replace" );
2583-     if  (name_encoded  ==  NULL ) {
2584-         return  -1 ;
2585-     }
2586- #ifdef  _PYTHREAD_NAME_MAXLEN 
2587-     if  (PyBytes_GET_SIZE (name_encoded ) >  _PYTHREAD_NAME_MAXLEN ) {
2588-         PyObject  * truncated  =  PyBytes_FromStringAndSize (PyBytes_AS_STRING (name_encoded ), _PYTHREAD_NAME_MAXLEN );
2589-         if  (truncated  ==  NULL ) {
2590-             Py_DECREF (name_encoded );
2591-             return  -1 ;
2592-         }
2593-         Py_SETREF (name_encoded , truncated );
2594-     }
2595- #endif 
2596-     const  char  * name  =  PyBytes_AS_STRING (name_encoded );
25972588    int  rc ;
25982589#ifdef  __APPLE__ 
25992590    rc  =  pthread_setname_np (name );
@@ -2608,32 +2599,66 @@ _set_thread_name_encoded(PyObject *name_obj, const char *encoding, int *perrno)
26082599    rc  =  0 ; /* pthread_set_name_np() returns void */ 
26092600    pthread_set_name_np (thread , name );
26102601#endif 
2611-     Py_DECREF (name_encoded );
2612-     if  (perrno ) {
2613-         * perrno  =  rc ;
2614-     }
26152602    return  rc ;
26162603}
2604+ #endif  // !MS_WINDOWS 
2605+ 
26172606
26182607static  PyObject  * 
26192608_thread_set_name_impl (PyObject  * module , PyObject  * name_obj )
26202609/*[clinic end generated code: output=402b0c68e0c0daed input=7e7acd98261be82f]*/ 
26212610{
26222611#ifndef  MS_WINDOWS 
2612+     // POSIX and non-Windows platforms 
26232613#ifdef  __sun 
26242614    const  char  * encoding  =  "utf-8" ;
26252615#else 
26262616    PyInterpreterState  * interp  =  _PyInterpreterState_GET ();
26272617    const  char  * encoding  =  interp -> unicode .fs_codec .encoding ;
26282618#endif 
2629-     int  rc  =  _set_thread_name_encoded (name_obj , encoding , NULL );
2619+     PyObject  * name_encoded ;
2620+     int  rc ;
2621+ 
2622+     name_encoded  =  PyUnicode_AsEncodedString (name_obj , encoding , "replace" );
2623+     if  (name_encoded  ==  NULL ) {
2624+         return  NULL ;
2625+     }
2626+ #ifdef  _PYTHREAD_NAME_MAXLEN 
2627+     if  (PyBytes_GET_SIZE (name_encoded ) >  _PYTHREAD_NAME_MAXLEN ) {
2628+         PyObject  * truncated  =  PyBytes_FromStringAndSize (PyBytes_AS_STRING (name_encoded ), _PYTHREAD_NAME_MAXLEN );
2629+         if  (truncated  ==  NULL ) {
2630+             Py_DECREF (name_encoded );
2631+             return  NULL ;
2632+         }
2633+         Py_SETREF (name_encoded , truncated );
2634+     }
2635+ #endif 
2636+     const  char  * name  =  PyBytes_AS_STRING (name_encoded );
2637+     rc  =  _set_thread_name (name );
2638+     Py_DECREF (name_encoded );
2639+ 
2640+     // Fallback: If EINVAL, try ASCII encoding with "replace" 
26302641    if  (rc  ==  EINVAL ) {
2631-         int  rc2  =  _set_thread_name_encoded (name_obj , "ascii" , NULL );
2632-         if  (rc2  !=  0 ) {
2633-             errno  =  rc2 ;
2634-             return  PyErr_SetFromErrno (PyExc_OSError );
2642+         name_encoded  =  PyUnicode_AsEncodedString (name_obj , "ascii" , "replace" );
2643+         if  (name_encoded  ==  NULL ) {
2644+             return  NULL ;
26352645        }
2636-     } else  if  (rc  !=  0 ) {
2646+ #ifdef  _PYTHREAD_NAME_MAXLEN 
2647+         if  (PyBytes_GET_SIZE (name_encoded ) >  _PYTHREAD_NAME_MAXLEN ) {
2648+             PyObject  * truncated  =  PyBytes_FromStringAndSize (PyBytes_AS_STRING (name_encoded ), _PYTHREAD_NAME_MAXLEN );
2649+             if  (truncated  ==  NULL ) {
2650+                 Py_DECREF (name_encoded );
2651+                 return  NULL ;
2652+             }
2653+             Py_SETREF (name_encoded , truncated );
2654+         }
2655+ #endif 
2656+         name  =  PyBytes_AS_STRING (name_encoded );
2657+         rc  =  _set_thread_name (name );
2658+         Py_DECREF (name_encoded );
2659+     }
2660+ 
2661+     if  (rc ) {
26372662        errno  =  rc ;
26382663        return  PyErr_SetFromErrno (PyExc_OSError );
26392664    }
@@ -2670,6 +2695,19 @@ _thread_set_name_impl(PyObject *module, PyObject *name_obj)
26702695}
26712696#endif   // HAVE_PTHREAD_SETNAME_NP || HAVE_PTHREAD_SET_NAME_NP || MS_WINDOWS 
26722697
2698+ /* Fallback no-op implementation for builds that didn't compile the 
2699+  * platform-specific _set_thread_name. This prevents undefined-reference 
2700+  * linker errors on CI images that don't compile the native helper. 
2701+  */ 
2702+ #if  !defined(HAVE_PTHREAD_SETNAME_NP ) &&  !defined(HAVE_PTHREAD_SET_NAME_NP ) &&  !defined(MS_WINDOWS )
2703+ static  int 
2704+ _set_thread_name (const  char  * name )
2705+ {
2706+     /* name is unused for the no-op fallback */ 
2707+     (void )name ;
2708+     return  0 ;   /* indicate success (no-op) */ 
2709+ }
2710+ #endif 
26732711
26742712static  PyMethodDef  thread_methods [] =  {
26752713    {"start_new_thread" ,        thread_PyThread_start_new_thread ,
0 commit comments