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