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