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