/src/cpython/Python/thread.c
Line | Count | Source (jump to first uncovered line) |
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_ceval.h" // _PyEval_MakePendingCalls() |
10 | | #include "pycore_pystate.h" // _PyInterpreterState_GET() |
11 | | #include "pycore_pythread.h" // _POSIX_THREADS |
12 | | #include "pycore_runtime.h" // _PyRuntime |
13 | | #include "pycore_structseq.h" // _PyStructSequence_FiniBuiltin() |
14 | | |
15 | | #ifndef DONT_HAVE_STDIO_H |
16 | | # include <stdio.h> |
17 | | #endif |
18 | | |
19 | | #include <stdlib.h> |
20 | | |
21 | | |
22 | | // Define PY_TIMEOUT_MAX constant. |
23 | | #ifdef _POSIX_THREADS |
24 | | // PyThread_acquire_lock_timed() uses (us * 1000) to convert microseconds |
25 | | // to nanoseconds. |
26 | | # define PY_TIMEOUT_MAX_VALUE (LLONG_MAX / 1000) |
27 | | #elif defined (NT_THREADS) |
28 | | // WaitForSingleObject() accepts timeout in milliseconds in the range |
29 | | // [0; 0xFFFFFFFE] (DWORD type). INFINITE value (0xFFFFFFFF) means no |
30 | | // timeout. 0xFFFFFFFE milliseconds is around 49.7 days. |
31 | | # if 0xFFFFFFFELL < LLONG_MAX / 1000 |
32 | | # define PY_TIMEOUT_MAX_VALUE (0xFFFFFFFELL * 1000) |
33 | | # else |
34 | | # define PY_TIMEOUT_MAX_VALUE LLONG_MAX |
35 | | # endif |
36 | | #else |
37 | | # define PY_TIMEOUT_MAX_VALUE LLONG_MAX |
38 | | #endif |
39 | | const long long PY_TIMEOUT_MAX = PY_TIMEOUT_MAX_VALUE; |
40 | | |
41 | | |
42 | | /* Forward declaration */ |
43 | | static void PyThread__init_thread(void); |
44 | | |
45 | 114M | #define initialized _PyRuntime.threads.initialized |
46 | | |
47 | | void |
48 | | PyThread_init_thread(void) |
49 | 48 | { |
50 | 48 | if (initialized) { |
51 | 32 | return; |
52 | 32 | } |
53 | 16 | initialized = 1; |
54 | 16 | PyThread__init_thread(); |
55 | 16 | } |
56 | | |
57 | | #if defined(HAVE_PTHREAD_STUBS) |
58 | | # define PYTHREAD_NAME "pthread-stubs" |
59 | | # include "thread_pthread_stubs.h" |
60 | | #elif defined(_USE_PTHREADS) /* AKA _PTHREADS */ |
61 | | # if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__) |
62 | | # define PYTHREAD_NAME "pthread-stubs" |
63 | | # else |
64 | 16 | # define PYTHREAD_NAME "pthread" |
65 | | # endif |
66 | | # include "thread_pthread.h" |
67 | | #elif defined(NT_THREADS) |
68 | | # define PYTHREAD_NAME "nt" |
69 | | # include "thread_nt.h" |
70 | | #else |
71 | | # error "Require native threads. See https://bugs.python.org/issue31370" |
72 | | #endif |
73 | | |
74 | | |
75 | | /* |
76 | | * Lock support. |
77 | | */ |
78 | | |
79 | | PyThread_type_lock |
80 | | PyThread_allocate_lock(void) |
81 | 996 | { |
82 | 996 | if (!initialized) { |
83 | 0 | PyThread_init_thread(); |
84 | 0 | } |
85 | | |
86 | 996 | PyMutex *lock = (PyMutex *)PyMem_RawMalloc(sizeof(PyMutex)); |
87 | 996 | if (lock) { |
88 | 996 | *lock = (PyMutex){0}; |
89 | 996 | } |
90 | | |
91 | 996 | return (PyThread_type_lock)lock; |
92 | 996 | } |
93 | | |
94 | | void |
95 | | PyThread_free_lock(PyThread_type_lock lock) |
96 | 944 | { |
97 | 944 | PyMem_RawFree(lock); |
98 | 944 | } |
99 | | |
100 | | PyLockStatus |
101 | | PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, |
102 | | int intr_flag) |
103 | 2.83k | { |
104 | 2.83k | PyTime_t timeout; // relative timeout |
105 | 2.83k | if (microseconds >= 0) { |
106 | | // bpo-41710: PyThread_acquire_lock_timed() cannot report timeout |
107 | | // overflow to the caller, so clamp the timeout to |
108 | | // [PyTime_MIN, PyTime_MAX]. |
109 | | // |
110 | | // PyTime_MAX nanoseconds is around 292.3 years. |
111 | | // |
112 | | // _thread.Lock.acquire() and _thread.RLock.acquire() raise an |
113 | | // OverflowError if microseconds is greater than PY_TIMEOUT_MAX. |
114 | 2.83k | timeout = _PyTime_FromMicrosecondsClamp(microseconds); |
115 | 2.83k | } |
116 | 0 | else { |
117 | 0 | timeout = -1; |
118 | 0 | } |
119 | | |
120 | 2.83k | _PyLockFlags flags = _Py_LOCK_DONT_DETACH; |
121 | 2.83k | if (intr_flag) { |
122 | 0 | flags |= _PY_FAIL_IF_INTERRUPTED; |
123 | 0 | } |
124 | | |
125 | 2.83k | return _PyMutex_LockTimed((PyMutex *)lock, timeout, flags); |
126 | 2.83k | } |
127 | | |
128 | | void |
129 | | PyThread_release_lock(PyThread_type_lock lock) |
130 | 2.83k | { |
131 | 2.83k | PyMutex_Unlock((PyMutex *)lock); |
132 | 2.83k | } |
133 | | |
134 | | int |
135 | | _PyThread_at_fork_reinit(PyThread_type_lock *lock) |
136 | 0 | { |
137 | 0 | _PyMutex_at_fork_reinit((PyMutex *)lock); |
138 | 0 | return 0; |
139 | 0 | } |
140 | | |
141 | | int |
142 | | PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) |
143 | 2.83k | { |
144 | 2.83k | return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0); |
145 | 2.83k | } |
146 | | |
147 | | |
148 | | /* return the current thread stack size */ |
149 | | size_t |
150 | | PyThread_get_stacksize(void) |
151 | 0 | { |
152 | 0 | return _PyInterpreterState_GET()->threads.stacksize; |
153 | 0 | } |
154 | | |
155 | | /* Only platforms defining a THREAD_SET_STACKSIZE() macro |
156 | | in thread_<platform>.h support changing the stack size. |
157 | | Return 0 if stack size is valid, |
158 | | -1 if stack size value is invalid, |
159 | | -2 if setting stack size is not supported. */ |
160 | | int |
161 | | PyThread_set_stacksize(size_t size) |
162 | 0 | { |
163 | 0 | #if defined(THREAD_SET_STACKSIZE) |
164 | 0 | return THREAD_SET_STACKSIZE(size); |
165 | | #else |
166 | | return -2; |
167 | | #endif |
168 | 0 | } |
169 | | |
170 | | |
171 | | int |
172 | | PyThread_ParseTimeoutArg(PyObject *arg, int blocking, PY_TIMEOUT_T *timeout_p) |
173 | 0 | { |
174 | 0 | assert(_PyTime_FromSeconds(-1) == PyThread_UNSET_TIMEOUT); |
175 | 0 | if (arg == NULL || arg == Py_None) { |
176 | 0 | *timeout_p = blocking ? PyThread_UNSET_TIMEOUT : 0; |
177 | 0 | return 0; |
178 | 0 | } |
179 | 0 | if (!blocking) { |
180 | 0 | PyErr_SetString(PyExc_ValueError, |
181 | 0 | "can't specify a timeout for a non-blocking call"); |
182 | 0 | return -1; |
183 | 0 | } |
184 | | |
185 | 0 | PyTime_t timeout; |
186 | 0 | if (_PyTime_FromSecondsObject(&timeout, arg, _PyTime_ROUND_TIMEOUT) < 0) { |
187 | 0 | return -1; |
188 | 0 | } |
189 | 0 | if (timeout < 0) { |
190 | 0 | PyErr_SetString(PyExc_ValueError, |
191 | 0 | "timeout value must be a non-negative number"); |
192 | 0 | return -1; |
193 | 0 | } |
194 | | |
195 | 0 | if (_PyTime_AsMicroseconds(timeout, |
196 | 0 | _PyTime_ROUND_TIMEOUT) > PY_TIMEOUT_MAX) { |
197 | 0 | PyErr_SetString(PyExc_OverflowError, |
198 | 0 | "timeout value is too large"); |
199 | 0 | return -1; |
200 | 0 | } |
201 | 0 | *timeout_p = timeout; |
202 | 0 | return 0; |
203 | 0 | } |
204 | | |
205 | | PyLockStatus |
206 | | PyThread_acquire_lock_timed_with_retries(PyThread_type_lock lock, |
207 | | PY_TIMEOUT_T timeout) |
208 | 0 | { |
209 | 0 | PyThreadState *tstate = _PyThreadState_GET(); |
210 | 0 | PyTime_t endtime = 0; |
211 | 0 | if (timeout > 0) { |
212 | 0 | endtime = _PyDeadline_Init(timeout); |
213 | 0 | } |
214 | |
|
215 | 0 | PyLockStatus r; |
216 | 0 | do { |
217 | 0 | PyTime_t microseconds; |
218 | 0 | microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING); |
219 | | |
220 | | /* first a simple non-blocking try without releasing the GIL */ |
221 | 0 | r = PyThread_acquire_lock_timed(lock, 0, 0); |
222 | 0 | if (r == PY_LOCK_FAILURE && microseconds != 0) { |
223 | 0 | Py_BEGIN_ALLOW_THREADS |
224 | 0 | r = PyThread_acquire_lock_timed(lock, microseconds, 1); |
225 | 0 | Py_END_ALLOW_THREADS |
226 | 0 | } |
227 | |
|
228 | 0 | if (r == PY_LOCK_INTR) { |
229 | | /* Run signal handlers if we were interrupted. Propagate |
230 | | * exceptions from signal handlers, such as KeyboardInterrupt, by |
231 | | * passing up PY_LOCK_INTR. */ |
232 | 0 | if (_PyEval_MakePendingCalls(tstate) < 0) { |
233 | 0 | return PY_LOCK_INTR; |
234 | 0 | } |
235 | | |
236 | | /* If we're using a timeout, recompute the timeout after processing |
237 | | * signals, since those can take time. */ |
238 | 0 | if (timeout > 0) { |
239 | 0 | timeout = _PyDeadline_Get(endtime); |
240 | | |
241 | | /* Check for negative values, since those mean block forever. |
242 | | */ |
243 | 0 | if (timeout < 0) { |
244 | 0 | r = PY_LOCK_FAILURE; |
245 | 0 | } |
246 | 0 | } |
247 | 0 | } |
248 | 0 | } while (r == PY_LOCK_INTR); /* Retry if we were interrupted. */ |
249 | | |
250 | 0 | return r; |
251 | 0 | } |
252 | | |
253 | | |
254 | | /* Thread Specific Storage (TSS) API |
255 | | |
256 | | Cross-platform components of TSS API implementation. |
257 | | */ |
258 | | |
259 | | Py_tss_t * |
260 | | PyThread_tss_alloc(void) |
261 | 0 | { |
262 | 0 | Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t)); |
263 | 0 | if (new_key == NULL) { |
264 | 0 | return NULL; |
265 | 0 | } |
266 | 0 | new_key->_is_initialized = 0; |
267 | 0 | return new_key; |
268 | 0 | } |
269 | | |
270 | | void |
271 | | PyThread_tss_free(Py_tss_t *key) |
272 | 0 | { |
273 | 0 | if (key != NULL) { |
274 | 0 | PyThread_tss_delete(key); |
275 | 0 | PyMem_RawFree((void *)key); |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | | int |
280 | | PyThread_tss_is_created(Py_tss_t *key) |
281 | 0 | { |
282 | 0 | assert(key != NULL); |
283 | 0 | return key->_is_initialized; |
284 | 0 | } |
285 | | |
286 | | |
287 | | PyDoc_STRVAR(threadinfo__doc__, |
288 | | "sys.thread_info\n\ |
289 | | \n\ |
290 | | A named tuple holding information about the thread implementation."); |
291 | | |
292 | | static PyStructSequence_Field threadinfo_fields[] = { |
293 | | {"name", "name of the thread implementation"}, |
294 | | {"lock", "name of the lock implementation"}, |
295 | | {"version", "name and version of the thread library"}, |
296 | | {0} |
297 | | }; |
298 | | |
299 | | static PyStructSequence_Desc threadinfo_desc = { |
300 | | "sys.thread_info", /* name */ |
301 | | threadinfo__doc__, /* doc */ |
302 | | threadinfo_fields, /* fields */ |
303 | | 3 |
304 | | }; |
305 | | |
306 | | static PyTypeObject ThreadInfoType; |
307 | | |
308 | | PyObject* |
309 | | PyThread_GetInfo(void) |
310 | 16 | { |
311 | 16 | PyObject *threadinfo, *value; |
312 | 16 | int pos = 0; |
313 | 16 | #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ |
314 | 16 | && defined(_CS_GNU_LIBPTHREAD_VERSION)) |
315 | 16 | char buffer[255]; |
316 | 16 | int len; |
317 | 16 | #endif |
318 | | |
319 | 16 | PyInterpreterState *interp = _PyInterpreterState_GET(); |
320 | 16 | if (_PyStructSequence_InitBuiltin(interp, &ThreadInfoType, &threadinfo_desc) < 0) { |
321 | 0 | return NULL; |
322 | 0 | } |
323 | | |
324 | 16 | threadinfo = PyStructSequence_New(&ThreadInfoType); |
325 | 16 | if (threadinfo == NULL) |
326 | 0 | return NULL; |
327 | | |
328 | 16 | value = PyUnicode_FromString(PYTHREAD_NAME); |
329 | 16 | if (value == NULL) { |
330 | 0 | Py_DECREF(threadinfo); |
331 | 0 | return NULL; |
332 | 0 | } |
333 | 16 | PyStructSequence_SET_ITEM(threadinfo, pos++, value); |
334 | | |
335 | | #ifdef HAVE_PTHREAD_STUBS |
336 | | value = Py_NewRef(Py_None); |
337 | | #elif defined(_POSIX_THREADS) |
338 | | value = PyUnicode_FromString("pymutex"); |
339 | 16 | if (value == NULL) { |
340 | 0 | Py_DECREF(threadinfo); |
341 | 0 | return NULL; |
342 | 0 | } |
343 | | #else |
344 | | value = Py_NewRef(Py_None); |
345 | | #endif |
346 | 16 | PyStructSequence_SET_ITEM(threadinfo, pos++, value); |
347 | | |
348 | 16 | #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \ |
349 | 16 | && defined(_CS_GNU_LIBPTHREAD_VERSION)) |
350 | 16 | value = NULL; |
351 | 16 | len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer)); |
352 | 16 | if (1 < len && (size_t)len < sizeof(buffer)) { |
353 | 16 | value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); |
354 | 16 | if (value == NULL) |
355 | 0 | PyErr_Clear(); |
356 | 16 | } |
357 | 16 | if (value == NULL) |
358 | 0 | #endif |
359 | 0 | { |
360 | 0 | value = Py_NewRef(Py_None); |
361 | 0 | } |
362 | 16 | PyStructSequence_SET_ITEM(threadinfo, pos++, value); |
363 | 16 | return threadinfo; |
364 | 16 | } |
365 | | |
366 | | |
367 | | void |
368 | | _PyThread_FiniType(PyInterpreterState *interp) |
369 | 0 | { |
370 | 0 | _PyStructSequence_FiniBuiltin(interp, &ThreadInfoType); |
371 | 0 | } |