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