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 #if defined(_POSIX_THREADS)
83 #   define PYTHREAD_NAME "pthread"
84 #   include "thread_pthread.h"
85 #elif defined(NT_THREADS)
86 #   define PYTHREAD_NAME "nt"
87 #   include "thread_nt.h"
88 #else
89 #   error "Require native threads. See https://bugs.python.org/issue31370"
90 #endif
91 
92 
93 /* return the current thread stack size */
94 size_t
PyThread_get_stacksize(void)95 PyThread_get_stacksize(void)
96 {
97     return _PyInterpreterState_GET()->pythread_stacksize;
98 }
99 
100 /* Only platforms defining a THREAD_SET_STACKSIZE() macro
101    in thread_<platform>.h support changing the stack size.
102    Return 0 if stack size is valid,
103       -1 if stack size value is invalid,
104       -2 if setting stack size is not supported. */
105 int
PyThread_set_stacksize(size_t size)106 PyThread_set_stacksize(size_t size)
107 {
108 #if defined(THREAD_SET_STACKSIZE)
109     return THREAD_SET_STACKSIZE(size);
110 #else
111     return -2;
112 #endif
113 }
114 
115 
116 /* Thread Specific Storage (TSS) API
117 
118    Cross-platform components of TSS API implementation.
119 */
120 
121 Py_tss_t *
PyThread_tss_alloc(void)122 PyThread_tss_alloc(void)
123 {
124     Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t));
125     if (new_key == NULL) {
126         return NULL;
127     }
128     new_key->_is_initialized = 0;
129     return new_key;
130 }
131 
132 void
PyThread_tss_free(Py_tss_t * key)133 PyThread_tss_free(Py_tss_t *key)
134 {
135     if (key != NULL) {
136         PyThread_tss_delete(key);
137         PyMem_RawFree((void *)key);
138     }
139 }
140 
141 int
PyThread_tss_is_created(Py_tss_t * key)142 PyThread_tss_is_created(Py_tss_t *key)
143 {
144     assert(key != NULL);
145     return key->_is_initialized;
146 }
147 
148 
149 PyDoc_STRVAR(threadinfo__doc__,
150 "sys.thread_info\n\
151 \n\
152 A named tuple holding information about the thread implementation.");
153 
154 static PyStructSequence_Field threadinfo_fields[] = {
155     {"name",    "name of the thread implementation"},
156     {"lock",    "name of the lock implementation"},
157     {"version", "name and version of the thread library"},
158     {0}
159 };
160 
161 static PyStructSequence_Desc threadinfo_desc = {
162     "sys.thread_info",           /* name */
163     threadinfo__doc__,           /* doc */
164     threadinfo_fields,           /* fields */
165     3
166 };
167 
168 static PyTypeObject ThreadInfoType;
169 
170 PyObject*
PyThread_GetInfo(void)171 PyThread_GetInfo(void)
172 {
173     PyObject *threadinfo, *value;
174     int pos = 0;
175 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
176      && defined(_CS_GNU_LIBPTHREAD_VERSION))
177     char buffer[255];
178     int len;
179 #endif
180 
181     if (ThreadInfoType.tp_name == 0) {
182         if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
183             return NULL;
184     }
185 
186     threadinfo = PyStructSequence_New(&ThreadInfoType);
187     if (threadinfo == NULL)
188         return NULL;
189 
190     value = PyUnicode_FromString(PYTHREAD_NAME);
191     if (value == NULL) {
192         Py_DECREF(threadinfo);
193         return NULL;
194     }
195     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
196 
197 #ifdef _POSIX_THREADS
198 #ifdef USE_SEMAPHORES
199     value = PyUnicode_FromString("semaphore");
200 #else
201     value = PyUnicode_FromString("mutex+cond");
202 #endif
203     if (value == NULL) {
204         Py_DECREF(threadinfo);
205         return NULL;
206     }
207 #else
208     Py_INCREF(Py_None);
209     value = Py_None;
210 #endif
211     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
212 
213 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
214      && defined(_CS_GNU_LIBPTHREAD_VERSION))
215     value = NULL;
216     len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
217     if (1 < len && (size_t)len < sizeof(buffer)) {
218         value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
219         if (value == NULL)
220             PyErr_Clear();
221     }
222     if (value == NULL)
223 #endif
224     {
225         Py_INCREF(Py_None);
226         value = Py_None;
227     }
228     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
229     return threadinfo;
230 }
231