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 |
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 |
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 |
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 |
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 * |
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 |
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 |
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* |
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 | |