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
47 static int thread_debug = 0;
48 # define dprintf(args) (void)((thread_debug & 1) && printf args)
49 #else
50 # define dprintf(args)
51 #endif
52
53 static int initialized;
54
55 static void PyThread__init_thread(void); /* Forward */
56
57 void
PyThread_init_thread(void)58 PyThread_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
77 void
_PyThread_debug_deprecation(void)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 */
115 size_t
PyThread_get_stacksize(void)116 PyThread_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. */
126 int
PyThread_set_stacksize(size_t size)127 PyThread_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
142 Py_tss_t *
PyThread_tss_alloc(void)143 PyThread_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
153 void
PyThread_tss_free(Py_tss_t * key)154 PyThread_tss_free(Py_tss_t *key)
155 {
156 if (key != NULL) {
157 PyThread_tss_delete(key);
158 PyMem_RawFree((void *)key);
159 }
160 }
161
162 int
PyThread_tss_is_created(Py_tss_t * key)163 PyThread_tss_is_created(Py_tss_t *key)
164 {
165 assert(key != NULL);
166 return key->_is_initialized;
167 }
168
169
170 PyDoc_STRVAR(threadinfo__doc__,
171 "sys.thread_info\n\
172 \n\
173 A named tuple holding information about the thread implementation.");
174
175 static 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
182 static PyStructSequence_Desc threadinfo_desc = {
183 "sys.thread_info", /* name */
184 threadinfo__doc__, /* doc */
185 threadinfo_fields, /* fields */
186 3
187 };
188
189 static PyTypeObject ThreadInfoType;
190
191 PyObject*
PyThread_GetInfo(void)192 PyThread_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
255 void
_PyThread_FiniType(PyInterpreterState * interp)256 _PyThread_FiniType(PyInterpreterState *interp)
257 {
258 if (!_Py_IsMainInterpreter(interp)) {
259 return;
260 }
261
262 _PyStructSequence_FiniType(&ThreadInfoType);
263 }
264