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