• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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