Branch data Line data Source code
1 : : #include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
2 : :
3 : : /* Posix threads interface */
4 : :
5 : : #include <stdlib.h>
6 : : #include <string.h>
7 : : #if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)
8 : : #define destructor xxdestructor
9 : : #endif
10 : : #ifndef HAVE_PTHREAD_STUBS
11 : : # include <pthread.h>
12 : : #endif
13 : : #if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)
14 : : #undef destructor
15 : : #endif
16 : : #include <signal.h>
17 : :
18 : : #if defined(__linux__)
19 : : # include <sys/syscall.h> /* syscall(SYS_gettid) */
20 : : #elif defined(__FreeBSD__)
21 : : # include <pthread_np.h> /* pthread_getthreadid_np() */
22 : : #elif defined(__OpenBSD__)
23 : : # include <unistd.h> /* getthrid() */
24 : : #elif defined(_AIX)
25 : : # include <sys/thread.h> /* thread_self() */
26 : : #elif defined(__NetBSD__)
27 : : # include <lwp.h> /* _lwp_self() */
28 : : #elif defined(__DragonFly__)
29 : : # include <sys/lwp.h> /* lwp_gettid() */
30 : : #endif
31 : :
32 : : /* The POSIX spec requires that use of pthread_attr_setstacksize
33 : : be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */
34 : : #ifdef _POSIX_THREAD_ATTR_STACKSIZE
35 : : #ifndef THREAD_STACK_SIZE
36 : : #define THREAD_STACK_SIZE 0 /* use default stack size */
37 : : #endif
38 : :
39 : : /* The default stack size for new threads on BSD is small enough that
40 : : * we'll get hard crashes instead of 'maximum recursion depth exceeded'
41 : : * exceptions.
42 : : *
43 : : * The default stack size below is the empirically determined minimal stack
44 : : * sizes where a simple recursive function doesn't cause a hard crash.
45 : : *
46 : : * For macOS the value of THREAD_STACK_SIZE is determined in configure.ac
47 : : * as it also depends on the other configure options like chosen sanitizer
48 : : * runtimes.
49 : : */
50 : : #if defined(__FreeBSD__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
51 : : #undef THREAD_STACK_SIZE
52 : : #define THREAD_STACK_SIZE 0x400000
53 : : #endif
54 : : #if defined(_AIX) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
55 : : #undef THREAD_STACK_SIZE
56 : : #define THREAD_STACK_SIZE 0x200000
57 : : #endif
58 : : /* bpo-38852: test_threading.test_recursion_limit() checks that 1000 recursive
59 : : Python calls (default recursion limit) doesn't crash, but raise a regular
60 : : RecursionError exception. In debug mode, Python function calls allocates
61 : : more memory on the stack, so use a stack of 8 MiB. */
62 : : #if defined(__ANDROID__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
63 : : # ifdef Py_DEBUG
64 : : # undef THREAD_STACK_SIZE
65 : : # define THREAD_STACK_SIZE 0x800000
66 : : # endif
67 : : #endif
68 : : #if defined(__VXWORKS__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
69 : : #undef THREAD_STACK_SIZE
70 : : #define THREAD_STACK_SIZE 0x100000
71 : : #endif
72 : : /* for safety, ensure a viable minimum stacksize */
73 : : #define THREAD_STACK_MIN 0x8000 /* 32 KiB */
74 : : #else /* !_POSIX_THREAD_ATTR_STACKSIZE */
75 : : #ifdef THREAD_STACK_SIZE
76 : : #error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined"
77 : : #endif
78 : : #endif
79 : :
80 : : /* The POSIX spec says that implementations supporting the sem_*
81 : : family of functions must indicate this by defining
82 : : _POSIX_SEMAPHORES. */
83 : : #ifdef _POSIX_SEMAPHORES
84 : : /* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so
85 : : we need to add 0 to make it work there as well. */
86 : : #if (_POSIX_SEMAPHORES+0) == -1
87 : : #define HAVE_BROKEN_POSIX_SEMAPHORES
88 : : #else
89 : : #include <semaphore.h>
90 : : #include <errno.h>
91 : : #endif
92 : : #endif
93 : :
94 : :
95 : : /* Whether or not to use semaphores directly rather than emulating them with
96 : : * mutexes and condition variables:
97 : : */
98 : : #if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \
99 : : (defined(HAVE_SEM_TIMEDWAIT) || defined(HAVE_SEM_CLOCKWAIT)))
100 : : # define USE_SEMAPHORES
101 : : #else
102 : : # undef USE_SEMAPHORES
103 : : #endif
104 : :
105 : :
106 : : /* On platforms that don't use standard POSIX threads pthread_sigmask()
107 : : * isn't present. DEC threads uses sigprocmask() instead as do most
108 : : * other UNIX International compliant systems that don't have the full
109 : : * pthread implementation.
110 : : */
111 : : #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
112 : : # define SET_THREAD_SIGMASK pthread_sigmask
113 : : #else
114 : : # define SET_THREAD_SIGMASK sigprocmask
115 : : #endif
116 : :
117 : :
118 : : /*
119 : : * pthread_cond support
120 : : */
121 : :
122 : : #define condattr_monotonic _PyRuntime.threads._condattr_monotonic.ptr
123 : :
124 : : static void
125 : 29 : init_condattr(void)
126 : : {
127 : : #ifdef CONDATTR_MONOTONIC
128 : : # define ca _PyRuntime.threads._condattr_monotonic.val
129 : : // XXX We need to check the return code?
130 : 29 : pthread_condattr_init(&ca);
131 : : // XXX We need to run pthread_condattr_destroy() during runtime fini.
132 [ + - ]: 29 : if (pthread_condattr_setclock(&ca, CLOCK_MONOTONIC) == 0) {
133 : 29 : condattr_monotonic = &ca; // Use monotonic clock
134 : : }
135 : : # undef ca
136 : : #endif // CONDATTR_MONOTONIC
137 : 29 : }
138 : :
139 : : int
140 : 58 : _PyThread_cond_init(PyCOND_T *cond)
141 : : {
142 : 58 : return pthread_cond_init(cond, condattr_monotonic);
143 : : }
144 : :
145 : :
146 : : void
147 : 0 : _PyThread_cond_after(long long us, struct timespec *abs)
148 : : {
149 : 0 : _PyTime_t timeout = _PyTime_FromMicrosecondsClamp(us);
150 : : _PyTime_t t;
151 : : #ifdef CONDATTR_MONOTONIC
152 [ # # ]: 0 : if (condattr_monotonic) {
153 : 0 : t = _PyTime_GetMonotonicClock();
154 : : }
155 : : else
156 : : #endif
157 : : {
158 : 0 : t = _PyTime_GetSystemClock();
159 : : }
160 : 0 : t = _PyTime_Add(t, timeout);
161 : 0 : _PyTime_AsTimespec_clamp(t, abs);
162 : 0 : }
163 : :
164 : :
165 : : /* A pthread mutex isn't sufficient to model the Python lock type
166 : : * because, according to Draft 5 of the docs (P1003.4a/D5), both of the
167 : : * following are undefined:
168 : : * -> a thread tries to lock a mutex it already has locked
169 : : * -> a thread tries to unlock a mutex locked by a different thread
170 : : * pthread mutexes are designed for serializing threads over short pieces
171 : : * of code anyway, so wouldn't be an appropriate implementation of
172 : : * Python's locks regardless.
173 : : *
174 : : * The pthread_lock struct implements a Python lock as a "locked?" bit
175 : : * and a <condition, mutex> pair. In general, if the bit can be acquired
176 : : * instantly, it is, else the pair is used to block the thread until the
177 : : * bit is cleared. 9 May 1994 tim@ksr.com
178 : : */
179 : :
180 : : typedef struct {
181 : : char locked; /* 0=unlocked, 1=locked */
182 : : /* a <cond, mutex> pair to handle an acquire of a locked lock */
183 : : pthread_cond_t lock_released;
184 : : pthread_mutex_t mut;
185 : : } pthread_lock;
186 : :
187 : : #define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; }
188 : : #define CHECK_STATUS_PTHREAD(name) if (status != 0) { fprintf(stderr, \
189 : : "%s: %s\n", name, strerror(status)); error = 1; }
190 : :
191 : : /*
192 : : * Initialization for the current runtime.
193 : : */
194 : : static void
195 : 29 : PyThread__init_thread(void)
196 : : {
197 : : // The library is only initialized once in the process,
198 : : // regardless of how many times the Python runtime is initialized.
199 : : static int lib_initialized = 0;
200 [ + - ]: 29 : if (!lib_initialized) {
201 : 29 : lib_initialized = 1;
202 : : #if defined(_AIX) && defined(__GNUC__)
203 : : extern void pthread_init(void);
204 : : pthread_init();
205 : : #endif
206 : : }
207 : 29 : init_condattr();
208 : 29 : }
209 : :
210 : : /*
211 : : * Thread support.
212 : : */
213 : :
214 : : /* bpo-33015: pythread_callback struct and pythread_wrapper() cast
215 : : "void func(void *)" to "void* func(void *)": always return NULL.
216 : :
217 : : PyThread_start_new_thread() uses "void func(void *)" type, whereas
218 : : pthread_create() requires a void* return value. */
219 : : typedef struct {
220 : : void (*func) (void *);
221 : : void *arg;
222 : : } pythread_callback;
223 : :
224 : : static void *
225 : 1 : pythread_wrapper(void *arg)
226 : : {
227 : : /* copy func and func_arg and free the temporary structure */
228 : 1 : pythread_callback *callback = arg;
229 : 1 : void (*func)(void *) = callback->func;
230 : 1 : void *func_arg = callback->arg;
231 : 1 : PyMem_RawFree(arg);
232 : :
233 : 1 : func(func_arg);
234 : 1 : return NULL;
235 : : }
236 : :
237 : : unsigned long
238 : 1 : PyThread_start_new_thread(void (*func)(void *), void *arg)
239 : : {
240 : : pthread_t th;
241 : : int status;
242 : : #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
243 : : pthread_attr_t attrs;
244 : : #endif
245 : : #if defined(THREAD_STACK_SIZE)
246 : : size_t tss;
247 : : #endif
248 : :
249 [ - + ]: 1 : if (!initialized)
250 : 0 : PyThread_init_thread();
251 : :
252 : : #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
253 [ - + ]: 1 : if (pthread_attr_init(&attrs) != 0)
254 : 0 : return PYTHREAD_INVALID_THREAD_ID;
255 : : #endif
256 : : #if defined(THREAD_STACK_SIZE)
257 : 1 : PyThreadState *tstate = _PyThreadState_GET();
258 [ + - ]: 1 : size_t stacksize = tstate ? tstate->interp->threads.stacksize : 0;
259 : 1 : tss = (stacksize != 0) ? stacksize : THREAD_STACK_SIZE;
260 [ - + ]: 1 : if (tss != 0) {
261 [ # # ]: 0 : if (pthread_attr_setstacksize(&attrs, tss) != 0) {
262 : 0 : pthread_attr_destroy(&attrs);
263 : 0 : return PYTHREAD_INVALID_THREAD_ID;
264 : : }
265 : : }
266 : : #endif
267 : : #if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
268 : 1 : pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
269 : : #endif
270 : :
271 : 1 : pythread_callback *callback = PyMem_RawMalloc(sizeof(pythread_callback));
272 : :
273 [ - + ]: 1 : if (callback == NULL) {
274 : 0 : return PYTHREAD_INVALID_THREAD_ID;
275 : : }
276 : :
277 : 1 : callback->func = func;
278 : 1 : callback->arg = arg;
279 : :
280 : 1 : status = pthread_create(&th,
281 : : #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
282 : : &attrs,
283 : : #else
284 : : (pthread_attr_t*)NULL,
285 : : #endif
286 : : pythread_wrapper, callback);
287 : :
288 : : #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
289 : 1 : pthread_attr_destroy(&attrs);
290 : : #endif
291 : :
292 [ - + ]: 1 : if (status != 0) {
293 : 0 : PyMem_RawFree(callback);
294 : 0 : return PYTHREAD_INVALID_THREAD_ID;
295 : : }
296 : :
297 : 1 : pthread_detach(th);
298 : :
299 : : #if SIZEOF_PTHREAD_T <= SIZEOF_LONG
300 : 1 : return (unsigned long) th;
301 : : #else
302 : : return (unsigned long) *(unsigned long *) &th;
303 : : #endif
304 : : }
305 : :
306 : : /* XXX This implementation is considered (to quote Tim Peters) "inherently
307 : : hosed" because:
308 : : - It does not guarantee the promise that a non-zero integer is returned.
309 : : - The cast to unsigned long is inherently unsafe.
310 : : - It is not clear that the 'volatile' (for AIX?) are any longer necessary.
311 : : */
312 : : unsigned long
313 : 4828186 : PyThread_get_thread_ident(void)
314 : : {
315 : : volatile pthread_t threadid;
316 [ - + ]: 4828186 : if (!initialized)
317 : 0 : PyThread_init_thread();
318 : 4828186 : threadid = pthread_self();
319 : 4828186 : return (unsigned long) threadid;
320 : : }
321 : :
322 : : #ifdef PY_HAVE_THREAD_NATIVE_ID
323 : : unsigned long
324 : 33 : PyThread_get_thread_native_id(void)
325 : : {
326 [ - + ]: 33 : if (!initialized)
327 : 0 : PyThread_init_thread();
328 : : #ifdef __APPLE__
329 : : uint64_t native_id;
330 : : (void) pthread_threadid_np(NULL, &native_id);
331 : : #elif defined(__linux__)
332 : : pid_t native_id;
333 : 33 : native_id = syscall(SYS_gettid);
334 : : #elif defined(__FreeBSD__)
335 : : int native_id;
336 : : native_id = pthread_getthreadid_np();
337 : : #elif defined(__OpenBSD__)
338 : : pid_t native_id;
339 : : native_id = getthrid();
340 : : #elif defined(_AIX)
341 : : tid_t native_id;
342 : : native_id = thread_self();
343 : : #elif defined(__NetBSD__)
344 : : lwpid_t native_id;
345 : : native_id = _lwp_self();
346 : : #elif defined(__DragonFly__)
347 : : lwpid_t native_id;
348 : : native_id = lwp_gettid();
349 : : #endif
350 : 33 : return (unsigned long) native_id;
351 : : }
352 : : #endif
353 : :
354 : : void _Py_NO_RETURN
355 : 0 : PyThread_exit_thread(void)
356 : : {
357 [ # # ]: 0 : if (!initialized)
358 : 0 : exit(0);
359 : 0 : pthread_exit(0);
360 : : }
361 : :
362 : : #ifdef USE_SEMAPHORES
363 : :
364 : : /*
365 : : * Lock support.
366 : : */
367 : :
368 : : PyThread_type_lock
369 : 3634 : PyThread_allocate_lock(void)
370 : : {
371 : : sem_t *lock;
372 : 3634 : int status, error = 0;
373 : :
374 [ + + ]: 3634 : if (!initialized)
375 : 29 : PyThread_init_thread();
376 : :
377 : 3634 : lock = (sem_t *)PyMem_RawMalloc(sizeof(sem_t));
378 : :
379 [ + - ]: 3634 : if (lock) {
380 : 3634 : status = sem_init(lock,0,1);
381 [ - + ]: 3634 : CHECK_STATUS("sem_init");
382 : :
383 [ - + ]: 3634 : if (error) {
384 : 0 : PyMem_RawFree((void *)lock);
385 : 0 : lock = NULL;
386 : : }
387 : : }
388 : :
389 : 3634 : return (PyThread_type_lock)lock;
390 : : }
391 : :
392 : : void
393 : 3613 : PyThread_free_lock(PyThread_type_lock lock)
394 : : {
395 : 3613 : sem_t *thelock = (sem_t *)lock;
396 : 3613 : int status, error = 0;
397 : :
398 : : (void) error; /* silence unused-but-set-variable warning */
399 : :
400 [ - + ]: 3613 : if (!thelock)
401 : 0 : return;
402 : :
403 : 3613 : status = sem_destroy(thelock);
404 [ - + ]: 3613 : CHECK_STATUS("sem_destroy");
405 : :
406 : 3613 : PyMem_RawFree((void *)thelock);
407 : : }
408 : :
409 : : /*
410 : : * As of February 2002, Cygwin thread implementations mistakenly report error
411 : : * codes in the return value of the sem_ calls (like the pthread_ functions).
412 : : * Correct implementations return -1 and put the code in errno. This supports
413 : : * either.
414 : : */
415 : : static int
416 : 16014 : fix_status(int status)
417 : : {
418 [ + + ]: 16014 : return (status == -1) ? errno : status;
419 : : }
420 : :
421 : : PyLockStatus
422 : 16014 : PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
423 : : int intr_flag)
424 : : {
425 : : PyLockStatus success;
426 : 16014 : sem_t *thelock = (sem_t *)lock;
427 : 16014 : int status, error = 0;
428 : :
429 : : (void) error; /* silence unused-but-set-variable warning */
430 : :
431 : : _PyTime_t timeout; // relative timeout
432 [ + + ]: 16014 : if (microseconds >= 0) {
433 : : // bpo-41710: PyThread_acquire_lock_timed() cannot report timeout
434 : : // overflow to the caller, so clamp the timeout to
435 : : // [_PyTime_MIN, _PyTime_MAX].
436 : : //
437 : : // _PyTime_MAX nanoseconds is around 292.3 years.
438 : : //
439 : : // _thread.Lock.acquire() and _thread.RLock.acquire() raise an
440 : : // OverflowError if microseconds is greater than PY_TIMEOUT_MAX.
441 : 15711 : timeout = _PyTime_FromMicrosecondsClamp(microseconds);
442 : : }
443 : : else {
444 : 303 : timeout = _PyTime_FromNanoseconds(-1);
445 : : }
446 : :
447 : : #ifdef HAVE_SEM_CLOCKWAIT
448 : : struct timespec abs_timeout;
449 : : // Local scope for deadline
450 : : {
451 : 16014 : _PyTime_t deadline = _PyTime_Add(_PyTime_GetMonotonicClock(), timeout);
452 : 16014 : _PyTime_AsTimespec_clamp(deadline, &abs_timeout);
453 : : }
454 : : #else
455 : : _PyTime_t deadline = 0;
456 : : if (timeout > 0 && !intr_flag) {
457 : : deadline = _PyDeadline_Init(timeout);
458 : : }
459 : : #endif
460 : :
461 : : while (1) {
462 [ + + ]: 16014 : if (timeout > 0) {
463 : : #ifdef HAVE_SEM_CLOCKWAIT
464 : 1 : status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC,
465 : : &abs_timeout));
466 : : #else
467 : : _PyTime_t abs_time = _PyTime_Add(_PyTime_GetSystemClock(),
468 : : timeout);
469 : : struct timespec ts;
470 : : _PyTime_AsTimespec_clamp(abs_time, &ts);
471 : : status = fix_status(sem_timedwait(thelock, &ts));
472 : : #endif
473 : : }
474 [ + + ]: 16013 : else if (timeout == 0) {
475 : 15710 : status = fix_status(sem_trywait(thelock));
476 : : }
477 : : else {
478 : 303 : status = fix_status(sem_wait(thelock));
479 : : }
480 : :
481 : : /* Retry if interrupted by a signal, unless the caller wants to be
482 : : notified. */
483 [ + - - + ]: 16014 : if (intr_flag || status != EINTR) {
484 : : break;
485 : : }
486 : :
487 : : // sem_clockwait() uses an absolute timeout, there is no need
488 : : // to recompute the relative timeout.
489 : : #ifndef HAVE_SEM_CLOCKWAIT
490 : : if (timeout > 0) {
491 : : /* wait interrupted by a signal (EINTR): recompute the timeout */
492 : : timeout = _PyDeadline_Get(deadline);
493 : : if (timeout < 0) {
494 : : status = ETIMEDOUT;
495 : : break;
496 : : }
497 : : }
498 : : #endif
499 : : }
500 : :
501 : : /* Don't check the status if we're stopping because of an interrupt. */
502 [ - + - - ]: 16014 : if (!(intr_flag && status == EINTR)) {
503 [ + + ]: 16014 : if (timeout > 0) {
504 [ + - ]: 1 : if (status != ETIMEDOUT) {
505 : : #ifdef HAVE_SEM_CLOCKWAIT
506 [ - + ]: 1 : CHECK_STATUS("sem_clockwait");
507 : : #else
508 : : CHECK_STATUS("sem_timedwait");
509 : : #endif
510 : : }
511 : : }
512 [ + + ]: 16013 : else if (timeout == 0) {
513 [ + + ]: 15710 : if (status != EAGAIN) {
514 [ - + ]: 15706 : CHECK_STATUS("sem_trywait");
515 : : }
516 : : }
517 : : else {
518 [ - + ]: 303 : CHECK_STATUS("sem_wait");
519 : : }
520 : : }
521 : :
522 [ + + ]: 16014 : if (status == 0) {
523 : 16010 : success = PY_LOCK_ACQUIRED;
524 [ - + - - ]: 4 : } else if (intr_flag && status == EINTR) {
525 : 0 : success = PY_LOCK_INTR;
526 : : } else {
527 : 4 : success = PY_LOCK_FAILURE;
528 : : }
529 : :
530 : 16014 : return success;
531 : : }
532 : :
533 : : void
534 : 16010 : PyThread_release_lock(PyThread_type_lock lock)
535 : : {
536 : 16010 : sem_t *thelock = (sem_t *)lock;
537 : 16010 : int status, error = 0;
538 : :
539 : : (void) error; /* silence unused-but-set-variable warning */
540 : :
541 : 16010 : status = sem_post(thelock);
542 [ - + ]: 16010 : CHECK_STATUS("sem_post");
543 : 16010 : }
544 : :
545 : : #else /* USE_SEMAPHORES */
546 : :
547 : : /*
548 : : * Lock support.
549 : : */
550 : : PyThread_type_lock
551 : : PyThread_allocate_lock(void)
552 : : {
553 : : pthread_lock *lock;
554 : : int status, error = 0;
555 : :
556 : : if (!initialized)
557 : : PyThread_init_thread();
558 : :
559 : : lock = (pthread_lock *) PyMem_RawCalloc(1, sizeof(pthread_lock));
560 : : if (lock) {
561 : : lock->locked = 0;
562 : :
563 : : status = pthread_mutex_init(&lock->mut, NULL);
564 : : CHECK_STATUS_PTHREAD("pthread_mutex_init");
565 : : /* Mark the pthread mutex underlying a Python mutex as
566 : : pure happens-before. We can't simply mark the
567 : : Python-level mutex as a mutex because it can be
568 : : acquired and released in different threads, which
569 : : will cause errors. */
570 : : _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut);
571 : :
572 : : status = _PyThread_cond_init(&lock->lock_released);
573 : : CHECK_STATUS_PTHREAD("pthread_cond_init");
574 : :
575 : : if (error) {
576 : : PyMem_RawFree((void *)lock);
577 : : lock = 0;
578 : : }
579 : : }
580 : :
581 : : return (PyThread_type_lock) lock;
582 : : }
583 : :
584 : : void
585 : : PyThread_free_lock(PyThread_type_lock lock)
586 : : {
587 : : pthread_lock *thelock = (pthread_lock *)lock;
588 : : int status, error = 0;
589 : :
590 : : (void) error; /* silence unused-but-set-variable warning */
591 : :
592 : : /* some pthread-like implementations tie the mutex to the cond
593 : : * and must have the cond destroyed first.
594 : : */
595 : : status = pthread_cond_destroy( &thelock->lock_released );
596 : : CHECK_STATUS_PTHREAD("pthread_cond_destroy");
597 : :
598 : : status = pthread_mutex_destroy( &thelock->mut );
599 : : CHECK_STATUS_PTHREAD("pthread_mutex_destroy");
600 : :
601 : : PyMem_RawFree((void *)thelock);
602 : : }
603 : :
604 : : PyLockStatus
605 : : PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
606 : : int intr_flag)
607 : : {
608 : : PyLockStatus success = PY_LOCK_FAILURE;
609 : : pthread_lock *thelock = (pthread_lock *)lock;
610 : : int status, error = 0;
611 : :
612 : : if (microseconds == 0) {
613 : : status = pthread_mutex_trylock( &thelock->mut );
614 : : if (status != EBUSY) {
615 : : CHECK_STATUS_PTHREAD("pthread_mutex_trylock[1]");
616 : : }
617 : : }
618 : : else {
619 : : status = pthread_mutex_lock( &thelock->mut );
620 : : CHECK_STATUS_PTHREAD("pthread_mutex_lock[1]");
621 : : }
622 : : if (status != 0) {
623 : : goto done;
624 : : }
625 : :
626 : : if (thelock->locked == 0) {
627 : : success = PY_LOCK_ACQUIRED;
628 : : goto unlock;
629 : : }
630 : : if (microseconds == 0) {
631 : : goto unlock;
632 : : }
633 : :
634 : : struct timespec abs_timeout;
635 : : if (microseconds > 0) {
636 : : _PyThread_cond_after(microseconds, &abs_timeout);
637 : : }
638 : : // Continue trying until we get the lock
639 : :
640 : : // mut must be locked by me -- part of the condition protocol
641 : : while (1) {
642 : : if (microseconds > 0) {
643 : : status = pthread_cond_timedwait(&thelock->lock_released,
644 : : &thelock->mut, &abs_timeout);
645 : : if (status == 1) {
646 : : break;
647 : : }
648 : : if (status == ETIMEDOUT) {
649 : : break;
650 : : }
651 : : CHECK_STATUS_PTHREAD("pthread_cond_timedwait");
652 : : }
653 : : else {
654 : : status = pthread_cond_wait(
655 : : &thelock->lock_released,
656 : : &thelock->mut);
657 : : CHECK_STATUS_PTHREAD("pthread_cond_wait");
658 : : }
659 : :
660 : : if (intr_flag && status == 0 && thelock->locked) {
661 : : // We were woken up, but didn't get the lock. We probably received
662 : : // a signal. Return PY_LOCK_INTR to allow the caller to handle
663 : : // it and retry.
664 : : success = PY_LOCK_INTR;
665 : : break;
666 : : }
667 : :
668 : : if (status == 0 && !thelock->locked) {
669 : : success = PY_LOCK_ACQUIRED;
670 : : break;
671 : : }
672 : :
673 : : // Wait got interrupted by a signal: retry
674 : : }
675 : :
676 : : unlock:
677 : : if (success == PY_LOCK_ACQUIRED) {
678 : : thelock->locked = 1;
679 : : }
680 : : status = pthread_mutex_unlock( &thelock->mut );
681 : : CHECK_STATUS_PTHREAD("pthread_mutex_unlock[1]");
682 : :
683 : : done:
684 : : if (error) {
685 : : success = PY_LOCK_FAILURE;
686 : : }
687 : : return success;
688 : : }
689 : :
690 : : void
691 : : PyThread_release_lock(PyThread_type_lock lock)
692 : : {
693 : : pthread_lock *thelock = (pthread_lock *)lock;
694 : : int status, error = 0;
695 : :
696 : : (void) error; /* silence unused-but-set-variable warning */
697 : :
698 : : status = pthread_mutex_lock( &thelock->mut );
699 : : CHECK_STATUS_PTHREAD("pthread_mutex_lock[3]");
700 : :
701 : : thelock->locked = 0;
702 : :
703 : : /* wake up someone (anyone, if any) waiting on the lock */
704 : : status = pthread_cond_signal( &thelock->lock_released );
705 : : CHECK_STATUS_PTHREAD("pthread_cond_signal");
706 : :
707 : : status = pthread_mutex_unlock( &thelock->mut );
708 : : CHECK_STATUS_PTHREAD("pthread_mutex_unlock[3]");
709 : : }
710 : :
711 : : #endif /* USE_SEMAPHORES */
712 : :
713 : : int
714 : 0 : _PyThread_at_fork_reinit(PyThread_type_lock *lock)
715 : : {
716 : 0 : PyThread_type_lock new_lock = PyThread_allocate_lock();
717 [ # # ]: 0 : if (new_lock == NULL) {
718 : 0 : return -1;
719 : : }
720 : :
721 : : /* bpo-6721, bpo-40089: The old lock can be in an inconsistent state.
722 : : fork() can be called in the middle of an operation on the lock done by
723 : : another thread. So don't call PyThread_free_lock(*lock).
724 : :
725 : : Leak memory on purpose. Don't release the memory either since the
726 : : address of a mutex is relevant. Putting two mutexes at the same address
727 : : can lead to problems. */
728 : :
729 : 0 : *lock = new_lock;
730 : 0 : return 0;
731 : : }
732 : :
733 : : int
734 : 13408 : PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
735 : : {
736 [ + + ]: 13408 : return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0);
737 : : }
738 : :
739 : : /* set the thread stack size.
740 : : * Return 0 if size is valid, -1 if size is invalid,
741 : : * -2 if setting stack size is not supported.
742 : : */
743 : : static int
744 : 0 : _pythread_pthread_set_stacksize(size_t size)
745 : : {
746 : : #if defined(THREAD_STACK_SIZE)
747 : : pthread_attr_t attrs;
748 : : size_t tss_min;
749 : 0 : int rc = 0;
750 : : #endif
751 : :
752 : : /* set to default */
753 [ # # ]: 0 : if (size == 0) {
754 : 0 : _PyInterpreterState_GET()->threads.stacksize = 0;
755 : 0 : return 0;
756 : : }
757 : :
758 : : #if defined(THREAD_STACK_SIZE)
759 : : #if defined(PTHREAD_STACK_MIN)
760 : 0 : tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN
761 : : : THREAD_STACK_MIN;
762 : : #else
763 : : tss_min = THREAD_STACK_MIN;
764 : : #endif
765 [ # # ]: 0 : if (size >= tss_min) {
766 : : /* validate stack size by setting thread attribute */
767 [ # # ]: 0 : if (pthread_attr_init(&attrs) == 0) {
768 : 0 : rc = pthread_attr_setstacksize(&attrs, size);
769 : 0 : pthread_attr_destroy(&attrs);
770 [ # # ]: 0 : if (rc == 0) {
771 : 0 : _PyInterpreterState_GET()->threads.stacksize = size;
772 : 0 : return 0;
773 : : }
774 : : }
775 : : }
776 : 0 : return -1;
777 : : #else
778 : : return -2;
779 : : #endif
780 : : }
781 : :
782 : : #define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x)
783 : :
784 : :
785 : : /* Thread Local Storage (TLS) API
786 : :
787 : : This API is DEPRECATED since Python 3.7. See PEP 539 for details.
788 : : */
789 : :
790 : : /* Issue #25658: On platforms where native TLS key is defined in a way that
791 : : cannot be safely cast to int, PyThread_create_key returns immediately a
792 : : failure status and other TLS functions all are no-ops. This indicates
793 : : clearly that the old API is not supported on platforms where it cannot be
794 : : used reliably, and that no effort will be made to add such support.
795 : :
796 : : Note: PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT will be unnecessary after
797 : : removing this API.
798 : : */
799 : :
800 : : int
801 : 0 : PyThread_create_key(void)
802 : : {
803 : : #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
804 : : pthread_key_t key;
805 : 0 : int fail = pthread_key_create(&key, NULL);
806 [ # # ]: 0 : if (fail)
807 : 0 : return -1;
808 [ # # ]: 0 : if (key > INT_MAX) {
809 : : /* Issue #22206: handle integer overflow */
810 : 0 : pthread_key_delete(key);
811 : 0 : errno = ENOMEM;
812 : 0 : return -1;
813 : : }
814 : 0 : return (int)key;
815 : : #else
816 : : return -1; /* never return valid key value. */
817 : : #endif
818 : : }
819 : :
820 : : void
821 : 0 : PyThread_delete_key(int key)
822 : : {
823 : : #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
824 : 0 : pthread_key_delete(key);
825 : : #endif
826 : 0 : }
827 : :
828 : : void
829 : 0 : PyThread_delete_key_value(int key)
830 : : {
831 : : #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
832 : 0 : pthread_setspecific(key, NULL);
833 : : #endif
834 : 0 : }
835 : :
836 : : int
837 : 0 : PyThread_set_key_value(int key, void *value)
838 : : {
839 : : #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
840 : 0 : int fail = pthread_setspecific(key, value);
841 [ # # ]: 0 : return fail ? -1 : 0;
842 : : #else
843 : : return -1;
844 : : #endif
845 : : }
846 : :
847 : : void *
848 : 0 : PyThread_get_key_value(int key)
849 : : {
850 : : #ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
851 : 0 : return pthread_getspecific(key);
852 : : #else
853 : : return NULL;
854 : : #endif
855 : : }
856 : :
857 : :
858 : : void
859 : 0 : PyThread_ReInitTLS(void)
860 : : {
861 : 0 : }
862 : :
863 : :
864 : : /* Thread Specific Storage (TSS) API
865 : :
866 : : Platform-specific components of TSS API implementation.
867 : : */
868 : :
869 : : int
870 : 59 : PyThread_tss_create(Py_tss_t *key)
871 : : {
872 : : assert(key != NULL);
873 : : /* If the key has been created, function is silently skipped. */
874 [ - + ]: 59 : if (key->_is_initialized) {
875 : 0 : return 0;
876 : : }
877 : :
878 : 59 : int fail = pthread_key_create(&(key->_key), NULL);
879 [ - + ]: 59 : if (fail) {
880 : 0 : return -1;
881 : : }
882 : 59 : key->_is_initialized = 1;
883 : 59 : return 0;
884 : : }
885 : :
886 : : void
887 : 51 : PyThread_tss_delete(Py_tss_t *key)
888 : : {
889 : : assert(key != NULL);
890 : : /* If the key has not been created, function is silently skipped. */
891 [ - + ]: 51 : if (!key->_is_initialized) {
892 : 0 : return;
893 : : }
894 : :
895 : 51 : pthread_key_delete(key->_key);
896 : : /* pthread has not provided the defined invalid value for the key. */
897 : 51 : key->_is_initialized = 0;
898 : : }
899 : :
900 : : int
901 : 54 : PyThread_tss_set(Py_tss_t *key, void *value)
902 : : {
903 : : assert(key != NULL);
904 : 54 : int fail = pthread_setspecific(key->_key, value);
905 [ - + ]: 54 : return fail ? -1 : 0;
906 : : }
907 : :
908 : : void *
909 : 58 : PyThread_tss_get(Py_tss_t *key)
910 : : {
911 : : assert(key != NULL);
912 : 58 : return pthread_getspecific(key->_key);
913 : : }
|