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