1 2 /* Thread package. 3 This is intended to be usable independently from Python. 4 The implementation for system foobar is in a file thread_foobar.h 5 which is included by this file dependent on config settings. 6 Stuff shared by all thread_*.h files is collected here. */ 7 8 #include "Python.h" 9 #include "pycore_pystate.h" // _PyInterpreterState_GET() 10 11 #ifndef _POSIX_THREADS 12 /* This means pthreads are not implemented in libc headers, hence the macro 13 not present in unistd.h. But they still can be implemented as an external 14 library (e.g. gnu pth in pthread emulation) */ 15 # ifdef HAVE_PTHREAD_H 16 # include <pthread.h> /* _POSIX_THREADS */ 17 # endif 18 #endif 19 20 #ifndef DONT_HAVE_STDIO_H 21 #include <stdio.h> 22 #endif 23 24 #include <stdlib.h> 25 26 #ifndef _POSIX_THREADS 27 28 /* Check if we're running on HP-UX and _SC_THREADS is defined. If so, then 29 enough of the Posix threads package is implemented to support python 30 threads. 31 32 This is valid for HP-UX 11.23 running on an ia64 system. If needed, add 33 a check of __ia64 to verify that we're running on an ia64 system instead 34 of a pa-risc system. 35 */ 36 #ifdef __hpux 37 #ifdef _SC_THREADS 38 #define _POSIX_THREADS 39 #endif 40 #endif 41 42 #endif /* _POSIX_THREADS */ 43 44 45 #ifdef Py_DEBUG 46 static int thread_debug = 0; 47 #define dprintf(args) (void)((thread_debug & 1) && printf args) 48 #define d2printf(args) ((thread_debug & 8) && printf args) 49 #else 50 #define dprintf(args) 51 #define d2printf(args) 52 #endif 53 54 static int initialized; 55 56 static void PyThread__init_thread(void); /* Forward */ 57 58 void PyThread_init_thread(void)59 PyThread_init_thread(void) 60 { 61 #ifdef Py_DEBUG 62 const char *p = Py_GETENV("PYTHONTHREADDEBUG"); 63 64 if (p) { 65 if (*p) 66 thread_debug = atoi(p); 67 else 68 thread_debug = 1; 69 } 70 #endif /* Py_DEBUG */ 71 if (initialized) 72 return; 73 initialized = 1; 74 dprintf(("PyThread_init_thread called\n")); 75 PyThread__init_thread(); 76 } 77 78 void _PyThread_debug_deprecation(void)79 _PyThread_debug_deprecation(void) 80 { 81 #ifdef Py_DEBUG 82 if (thread_debug) { 83 // Flush previous dprintf() logs 84 fflush(stdout); 85 if (PyErr_WarnEx(PyExc_DeprecationWarning, 86 "The threading debug (PYTHONTHREADDEBUG environment " 87 "variable) is deprecated and will be removed " 88 "in Python 3.12", 89 0)) 90 { 91 _PyErr_WriteUnraisableMsg("at Python startup", NULL); 92 } 93 } 94 #endif 95 } 96 97 #if defined(_POSIX_THREADS) 98 # define PYTHREAD_NAME "pthread" 99 # include "thread_pthread.h" 100 #elif defined(NT_THREADS) 101 # define PYTHREAD_NAME "nt" 102 # include "thread_nt.h" 103 #else 104 # error "Require native threads. See https://bugs.python.org/issue31370" 105 #endif 106 107 108 /* return the current thread stack size */ 109 size_t PyThread_get_stacksize(void)110 PyThread_get_stacksize(void) 111 { 112 return _PyInterpreterState_GET()->pythread_stacksize; 113 } 114 115 /* Only platforms defining a THREAD_SET_STACKSIZE() macro 116 in thread_<platform>.h support changing the stack size. 117 Return 0 if stack size is valid, 118 -1 if stack size value is invalid, 119 -2 if setting stack size is not supported. */ 120 int PyThread_set_stacksize(size_t size)121 PyThread_set_stacksize(size_t size) 122 { 123 #if defined(THREAD_SET_STACKSIZE) 124 return THREAD_SET_STACKSIZE(size); 125 #else 126 return -2; 127 #endif 128 } 129 130 131 /* Thread Specific Storage (TSS) API 132 133 Cross-platform components of TSS API implementation. 134 */ 135 136 Py_tss_t * PyThread_tss_alloc(void)137 PyThread_tss_alloc(void) 138 { 139 Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t)); 140 if (new_key == NULL) { 141 return NULL; 142 } 143 new_key->_is_initialized = 0; 144 return new_key; 145 } 146 147 void PyThread_tss_free(Py_tss_t * key)148 PyThread_tss_free(Py_tss_t *key) 149 { 150 if (key != NULL) { 151 PyThread_tss_delete(key); 152 PyMem_RawFree((void *)key); 153 } 154 } 155 156 int PyThread_tss_is_created(Py_tss_t * key)157 PyThread_tss_is_created(Py_tss_t *key) 158 { 159 assert(key != NULL); 160 return key->_is_initialized; 161 } 162 163 164 PyDoc_STRVAR(threadinfo__doc__, 165 "sys.thread_info\n\ 166 \n\ 167 A named tuple holding information about the thread implementation."); 168 169 static PyStructSequence_Field threadinfo_fields[] = { 170 {"name", "name of the thread implementation"}, 171 {"lock", "name of the lock implementation"}, 172 {"version", "name and version of the thread library"}, 173 {0} 174 }; 175 176 static PyStructSequence_Desc threadinfo_desc = { 177 "sys.thread_info", /* name */ 178 threadinfo__doc__, /* doc */ 179 threadinfo_fields, /* fields */ 180 3 181 }; 182 183 static PyTypeObject ThreadInfoType; 184 185 PyObject* PyThread_GetInfo(void)186 PyThread_GetInfo(void) 187 { 188 PyObject *threadinfo, *value; 189 int pos = 0; 190 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ 191 && defined(_CS_GNU_LIBPTHREAD_VERSION)) 192 char buffer[255]; 193 int len; 194 #endif 195 196 if (ThreadInfoType.tp_name == 0) { 197 if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0) 198 return NULL; 199 } 200 201 threadinfo = PyStructSequence_New(&ThreadInfoType); 202 if (threadinfo == NULL) 203 return NULL; 204 205 value = PyUnicode_FromString(PYTHREAD_NAME); 206 if (value == NULL) { 207 Py_DECREF(threadinfo); 208 return NULL; 209 } 210 PyStructSequence_SET_ITEM(threadinfo, pos++, value); 211 212 #ifdef _POSIX_THREADS 213 #ifdef USE_SEMAPHORES 214 value = PyUnicode_FromString("semaphore"); 215 #else 216 value = PyUnicode_FromString("mutex+cond"); 217 #endif 218 if (value == NULL) { 219 Py_DECREF(threadinfo); 220 return NULL; 221 } 222 #else 223 Py_INCREF(Py_None); 224 value = Py_None; 225 #endif 226 PyStructSequence_SET_ITEM(threadinfo, pos++, value); 227 228 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ 229 && defined(_CS_GNU_LIBPTHREAD_VERSION)) 230 value = NULL; 231 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer)); 232 if (1 < len && (size_t)len < sizeof(buffer)) { 233 value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); 234 if (value == NULL) 235 PyErr_Clear(); 236 } 237 if (value == NULL) 238 #endif 239 { 240 Py_INCREF(Py_None); 241 value = Py_None; 242 } 243 PyStructSequence_SET_ITEM(threadinfo, pos++, value); 244 return threadinfo; 245 } 246