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