• 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 
45 #ifdef Py_DEBUG
46 static int thread_debug = 0;
47 #define dprintf(args)   (void)((thread_debug & 1) && printf args)
48 #define d2printf(args)  ((thread_debug & 8) && printf args)
49 #else
50 #define dprintf(args)
51 #define d2printf(args)
52 #endif
53 
54 static int initialized;
55 
56 static void PyThread__init_thread(void); /* Forward */
57 
58 void
PyThread_init_thread(void)59 PyThread_init_thread(void)
60 {
61 #ifdef Py_DEBUG
62     const char *p = Py_GETENV("PYTHONTHREADDEBUG");
63 
64     if (p) {
65         if (*p)
66             thread_debug = atoi(p);
67         else
68             thread_debug = 1;
69     }
70 #endif /* Py_DEBUG */
71     if (initialized)
72         return;
73     initialized = 1;
74     dprintf(("PyThread_init_thread called\n"));
75     PyThread__init_thread();
76 }
77 
78 void
_PyThread_debug_deprecation(void)79 _PyThread_debug_deprecation(void)
80 {
81 #ifdef Py_DEBUG
82     if (thread_debug) {
83         // Flush previous dprintf() logs
84         fflush(stdout);
85         if (PyErr_WarnEx(PyExc_DeprecationWarning,
86                          "The threading debug (PYTHONTHREADDEBUG environment "
87                          "variable) is deprecated and will be removed "
88                          "in Python 3.12",
89                          0))
90         {
91             _PyErr_WriteUnraisableMsg("at Python startup", NULL);
92         }
93     }
94 #endif
95 }
96 
97 #if defined(_POSIX_THREADS)
98 #   define PYTHREAD_NAME "pthread"
99 #   include "thread_pthread.h"
100 #elif defined(NT_THREADS)
101 #   define PYTHREAD_NAME "nt"
102 #   include "thread_nt.h"
103 #else
104 #   error "Require native threads. See https://bugs.python.org/issue31370"
105 #endif
106 
107 
108 /* return the current thread stack size */
109 size_t
PyThread_get_stacksize(void)110 PyThread_get_stacksize(void)
111 {
112     return _PyInterpreterState_GET()->pythread_stacksize;
113 }
114 
115 /* Only platforms defining a THREAD_SET_STACKSIZE() macro
116    in thread_<platform>.h support changing the stack size.
117    Return 0 if stack size is valid,
118       -1 if stack size value is invalid,
119       -2 if setting stack size is not supported. */
120 int
PyThread_set_stacksize(size_t size)121 PyThread_set_stacksize(size_t size)
122 {
123 #if defined(THREAD_SET_STACKSIZE)
124     return THREAD_SET_STACKSIZE(size);
125 #else
126     return -2;
127 #endif
128 }
129 
130 
131 /* Thread Specific Storage (TSS) API
132 
133    Cross-platform components of TSS API implementation.
134 */
135 
136 Py_tss_t *
PyThread_tss_alloc(void)137 PyThread_tss_alloc(void)
138 {
139     Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t));
140     if (new_key == NULL) {
141         return NULL;
142     }
143     new_key->_is_initialized = 0;
144     return new_key;
145 }
146 
147 void
PyThread_tss_free(Py_tss_t * key)148 PyThread_tss_free(Py_tss_t *key)
149 {
150     if (key != NULL) {
151         PyThread_tss_delete(key);
152         PyMem_RawFree((void *)key);
153     }
154 }
155 
156 int
PyThread_tss_is_created(Py_tss_t * key)157 PyThread_tss_is_created(Py_tss_t *key)
158 {
159     assert(key != NULL);
160     return key->_is_initialized;
161 }
162 
163 
164 PyDoc_STRVAR(threadinfo__doc__,
165 "sys.thread_info\n\
166 \n\
167 A named tuple holding information about the thread implementation.");
168 
169 static PyStructSequence_Field threadinfo_fields[] = {
170     {"name",    "name of the thread implementation"},
171     {"lock",    "name of the lock implementation"},
172     {"version", "name and version of the thread library"},
173     {0}
174 };
175 
176 static PyStructSequence_Desc threadinfo_desc = {
177     "sys.thread_info",           /* name */
178     threadinfo__doc__,           /* doc */
179     threadinfo_fields,           /* fields */
180     3
181 };
182 
183 static PyTypeObject ThreadInfoType;
184 
185 PyObject*
PyThread_GetInfo(void)186 PyThread_GetInfo(void)
187 {
188     PyObject *threadinfo, *value;
189     int pos = 0;
190 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
191      && defined(_CS_GNU_LIBPTHREAD_VERSION))
192     char buffer[255];
193     int len;
194 #endif
195 
196     if (ThreadInfoType.tp_name == 0) {
197         if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
198             return NULL;
199     }
200 
201     threadinfo = PyStructSequence_New(&ThreadInfoType);
202     if (threadinfo == NULL)
203         return NULL;
204 
205     value = PyUnicode_FromString(PYTHREAD_NAME);
206     if (value == NULL) {
207         Py_DECREF(threadinfo);
208         return NULL;
209     }
210     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
211 
212 #ifdef _POSIX_THREADS
213 #ifdef USE_SEMAPHORES
214     value = PyUnicode_FromString("semaphore");
215 #else
216     value = PyUnicode_FromString("mutex+cond");
217 #endif
218     if (value == NULL) {
219         Py_DECREF(threadinfo);
220         return NULL;
221     }
222 #else
223     Py_INCREF(Py_None);
224     value = Py_None;
225 #endif
226     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
227 
228 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
229      && defined(_CS_GNU_LIBPTHREAD_VERSION))
230     value = NULL;
231     len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
232     if (1 < len && (size_t)len < sizeof(buffer)) {
233         value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
234         if (value == NULL)
235             PyErr_Clear();
236     }
237     if (value == NULL)
238 #endif
239     {
240         Py_INCREF(Py_None);
241         value = Py_None;
242     }
243     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
244     return threadinfo;
245 }
246