Coverage Report

Created: 2025-08-26 06:26

/src/cpython/Python/thread_pthread.h
Line
Count
Source (jump to first uncovered line)
1
#include "pycore_interp.h"        // _PyInterpreterState.threads.stacksize
2
#include "pycore_pythread.h"      // _POSIX_SEMAPHORES
3
#include "pycore_time.h"          // _PyTime_FromMicrosecondsClamup()
4
5
/* Posix threads interface */
6
7
#include <stdlib.h>
8
#include <string.h>
9
#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)
10
#define destructor xxdestructor
11
#endif
12
#ifndef HAVE_PTHREAD_STUBS
13
#  include <pthread.h>
14
#endif
15
#if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR)
16
#undef destructor
17
#endif
18
#include <signal.h>
19
#include <unistd.h>             /* pause(), also getthrid() on OpenBSD */
20
21
#if defined(__linux__)
22
#   include <sys/syscall.h>     /* syscall(SYS_gettid) */
23
#elif defined(__FreeBSD__)
24
#   include <pthread_np.h>      /* pthread_getthreadid_np() */
25
#elif defined(__FreeBSD_kernel__)
26
#   include <sys/syscall.h>     /* syscall(SYS_thr_self) */
27
#elif defined(_AIX)
28
#   include <sys/thread.h>      /* thread_self() */
29
#elif defined(__NetBSD__)
30
#   include <lwp.h>             /* _lwp_self() */
31
#elif defined(__DragonFly__)
32
#   include <sys/lwp.h>         /* lwp_gettid() */
33
#elif defined(__sun__) && SIZEOF_LONG >= 8
34
#   include <thread.h>
35
#endif
36
37
/* The POSIX spec requires that use of pthread_attr_setstacksize
38
   be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */
39
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
40
#ifndef THREAD_STACK_SIZE
41
0
#define THREAD_STACK_SIZE       0       /* use default stack size */
42
#endif
43
44
/* The default stack size for new threads on BSD is small enough that
45
 * we'll get hard crashes instead of 'maximum recursion depth exceeded'
46
 * exceptions.
47
 *
48
 * The default stack size below is the empirically determined minimal stack
49
 * sizes where a simple recursive function doesn't cause a hard crash.
50
 *
51
 * For macOS the value of THREAD_STACK_SIZE is determined in configure.ac
52
 * as it also depends on the other configure options like chosen sanitizer
53
 * runtimes.
54
 */
55
#if defined(__FreeBSD__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
56
#undef  THREAD_STACK_SIZE
57
#define THREAD_STACK_SIZE       0x400000
58
#endif
59
#if defined(_AIX) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
60
#undef  THREAD_STACK_SIZE
61
#define THREAD_STACK_SIZE       0x200000
62
#endif
63
/* bpo-38852: test_threading.test_recursion_limit() checks that 1000 recursive
64
   Python calls (default recursion limit) doesn't crash, but raise a regular
65
   RecursionError exception. In debug mode, Python function calls allocates
66
   more memory on the stack, so use a stack of 8 MiB. */
67
#if defined(__ANDROID__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
68
#   ifdef Py_DEBUG
69
#   undef  THREAD_STACK_SIZE
70
#   define THREAD_STACK_SIZE    0x800000
71
#   endif
72
#endif
73
#if defined(__VXWORKS__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
74
#undef  THREAD_STACK_SIZE
75
#define THREAD_STACK_SIZE       0x100000
76
#endif
77
/* for safety, ensure a viable minimum stacksize */
78
0
#define THREAD_STACK_MIN        0x8000  /* 32 KiB */
79
#else  /* !_POSIX_THREAD_ATTR_STACKSIZE */
80
#ifdef THREAD_STACK_SIZE
81
#error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined"
82
#endif
83
#endif
84
85
/* The POSIX spec says that implementations supporting the sem_*
86
   family of functions must indicate this by defining
87
   _POSIX_SEMAPHORES. */
88
#ifdef _POSIX_SEMAPHORES
89
/* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so
90
   we need to add 0 to make it work there as well. */
91
#if (_POSIX_SEMAPHORES+0) == -1
92
#  define HAVE_BROKEN_POSIX_SEMAPHORES
93
#else
94
#  include <semaphore.h>
95
#  include <errno.h>
96
#endif
97
#endif
98
99
/* Thread sanitizer doesn't currently support sem_clockwait */
100
#ifdef _Py_THREAD_SANITIZER
101
#undef HAVE_SEM_CLOCKWAIT
102
#endif
103
104
105
/* On platforms that don't use standard POSIX threads pthread_sigmask()
106
 * isn't present.  DEC threads uses sigprocmask() instead as do most
107
 * other UNIX International compliant systems that don't have the full
108
 * pthread implementation.
109
 */
110
#if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
111
#  define SET_THREAD_SIGMASK pthread_sigmask
112
#else
113
#  define SET_THREAD_SIGMASK sigprocmask
114
#endif
115
116
117
/*
118
 * pthread_cond support
119
 */
120
121
48
#define condattr_monotonic _PyRuntime.threads._condattr_monotonic.ptr
122
123
static void
124
init_condattr(void)
125
16
{
126
16
#ifdef CONDATTR_MONOTONIC
127
48
# define ca _PyRuntime.threads._condattr_monotonic.val
128
    // XXX We need to check the return code?
129
16
    pthread_condattr_init(&ca);
130
    // XXX We need to run pthread_condattr_destroy() during runtime fini.
131
16
    if (pthread_condattr_setclock(&ca, CLOCK_MONOTONIC) == 0) {
132
16
        condattr_monotonic = &ca;  // Use monotonic clock
133
16
    }
134
16
# undef ca
135
16
#endif  // CONDATTR_MONOTONIC
136
16
}
137
138
int
139
_PyThread_cond_init(PyCOND_T *cond)
140
32
{
141
32
    return pthread_cond_init(cond, condattr_monotonic);
142
32
}
143
144
145
void
146
_PyThread_cond_after(long long us, struct timespec *abs)
147
0
{
148
0
    PyTime_t timeout = _PyTime_FromMicrosecondsClamp(us);
149
0
    PyTime_t t;
150
0
#ifdef CONDATTR_MONOTONIC
151
0
    if (condattr_monotonic) {
152
        // silently ignore error: cannot report error to the caller
153
0
        (void)PyTime_MonotonicRaw(&t);
154
0
    }
155
0
    else
156
0
#endif
157
0
    {
158
        // silently ignore error: cannot report error to the caller
159
0
        (void)PyTime_TimeRaw(&t);
160
0
    }
161
0
    t = _PyTime_Add(t, timeout);
162
0
    _PyTime_AsTimespec_clamp(t, abs);
163
0
}
164
165
166
/* A pthread mutex isn't sufficient to model the Python lock type
167
 * because, according to Draft 5 of the docs (P1003.4a/D5), both of the
168
 * following are undefined:
169
 *  -> a thread tries to lock a mutex it already has locked
170
 *  -> a thread tries to unlock a mutex locked by a different thread
171
 * pthread mutexes are designed for serializing threads over short pieces
172
 * of code anyway, so wouldn't be an appropriate implementation of
173
 * Python's locks regardless.
174
 *
175
 * The pthread_lock struct implements a Python lock as a "locked?" bit
176
 * and a <condition, mutex> pair.  In general, if the bit can be acquired
177
 * instantly, it is, else the pair is used to block the thread until the
178
 * bit is cleared.     9 May 1994 tim@ksr.com
179
 */
180
181
typedef struct {
182
    char             locked; /* 0=unlocked, 1=locked */
183
    /* a <cond, mutex> pair to handle an acquire of a locked lock */
184
    pthread_cond_t   lock_released;
185
    pthread_mutex_t  mut;
186
} pthread_lock;
187
188
#define CHECK_STATUS(name)  if (status != 0) { perror(name); error = 1; }
189
#define CHECK_STATUS_PTHREAD(name)  if (status != 0) { fprintf(stderr, \
190
    "%s: %s\n", name, strerror(status)); error = 1; }
191
192
/*
193
 * Initialization for the current runtime.
194
 */
195
static void
196
PyThread__init_thread(void)
197
16
{
198
    // The library is only initialized once in the process,
199
    // regardless of how many times the Python runtime is initialized.
200
16
    static int lib_initialized = 0;
201
16
    if (!lib_initialized) {
202
16
        lib_initialized = 1;
203
#if defined(_AIX) && defined(__GNUC__)
204
        extern void pthread_init(void);
205
        pthread_init();
206
#endif
207
16
    }
208
16
    init_condattr();
209
16
}
210
211
/*
212
 * Thread support.
213
 */
214
215
/* bpo-33015: pythread_callback struct and pythread_wrapper() cast
216
   "void func(void *)" to "void* func(void *)": always return NULL.
217
218
   PyThread_start_new_thread() uses "void func(void *)" type, whereas
219
   pthread_create() requires a void* return value. */
220
typedef struct {
221
    void (*func) (void *);
222
    void *arg;
223
} pythread_callback;
224
225
static void *
226
pythread_wrapper(void *arg)
227
0
{
228
    /* copy func and func_arg and free the temporary structure */
229
0
    pythread_callback *callback = arg;
230
0
    void (*func)(void *) = callback->func;
231
0
    void *func_arg = callback->arg;
232
0
    PyMem_RawFree(arg);
233
234
0
    func(func_arg);
235
0
    return NULL;
236
0
}
237
238
static int
239
do_start_joinable_thread(void (*func)(void *), void *arg, pthread_t* out_id)
240
0
{
241
0
    pthread_t th;
242
0
    int status;
243
0
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
244
0
    pthread_attr_t attrs;
245
0
#endif
246
0
#if defined(THREAD_STACK_SIZE)
247
0
    size_t      tss;
248
0
#endif
249
250
0
    if (!initialized)
251
0
        PyThread_init_thread();
252
253
0
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
254
0
    if (pthread_attr_init(&attrs) != 0)
255
0
        return -1;
256
0
#endif
257
0
#if defined(THREAD_STACK_SIZE)
258
0
    PyThreadState *tstate = _PyThreadState_GET();
259
0
    size_t stacksize = tstate ? tstate->interp->threads.stacksize : 0;
260
0
    tss = (stacksize != 0) ? stacksize : THREAD_STACK_SIZE;
261
0
    if (tss != 0) {
262
0
        if (pthread_attr_setstacksize(&attrs, tss) != 0) {
263
0
            pthread_attr_destroy(&attrs);
264
0
            return -1;
265
0
        }
266
0
    }
267
0
#endif
268
0
#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
269
0
    pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
270
0
#endif
271
272
0
    pythread_callback *callback = PyMem_RawMalloc(sizeof(pythread_callback));
273
274
0
    if (callback == NULL) {
275
0
      return -1;
276
0
    }
277
278
0
    callback->func = func;
279
0
    callback->arg = arg;
280
281
0
    status = pthread_create(&th,
282
0
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
283
0
                             &attrs,
284
#else
285
                             (pthread_attr_t*)NULL,
286
#endif
287
0
                             pythread_wrapper, callback);
288
289
0
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
290
0
    pthread_attr_destroy(&attrs);
291
0
#endif
292
293
0
    if (status != 0) {
294
0
        PyMem_RawFree(callback);
295
0
        return -1;
296
0
    }
297
0
    *out_id = th;
298
0
    return 0;
299
0
}
300
301
/* Helper to convert pthread_t to PyThread_ident_t. POSIX allows pthread_t to be
302
   non-arithmetic, e.g., musl typedefs it as a pointer. */
303
static PyThread_ident_t
304
105M
_pthread_t_to_ident(pthread_t value) {
305
// Cast through an integer type of the same size to avoid sign-extension.
306
105M
#if SIZEOF_PTHREAD_T == SIZEOF_VOID_P
307
105M
    return (uintptr_t) value;
308
#elif SIZEOF_PTHREAD_T == SIZEOF_LONG
309
    return (unsigned long) value;
310
#elif SIZEOF_PTHREAD_T == SIZEOF_INT
311
    return (unsigned int) value;
312
#elif SIZEOF_PTHREAD_T == SIZEOF_LONG_LONG
313
    return (unsigned long long) value;
314
#else
315
#error "Unsupported SIZEOF_PTHREAD_T value"
316
#endif
317
105M
}
318
319
int
320
PyThread_start_joinable_thread(void (*func)(void *), void *arg,
321
0
                               PyThread_ident_t* ident, PyThread_handle_t* handle) {
322
0
    pthread_t th = (pthread_t) 0;
323
0
    if (do_start_joinable_thread(func, arg, &th)) {
324
0
        return -1;
325
0
    }
326
0
    *ident = _pthread_t_to_ident(th);
327
0
    *handle = (PyThread_handle_t) th;
328
0
    assert(th == (pthread_t) *handle);
329
0
    return 0;
330
0
}
331
332
unsigned long
333
PyThread_start_new_thread(void (*func)(void *), void *arg)
334
0
{
335
0
    pthread_t th = (pthread_t) 0;
336
0
    if (do_start_joinable_thread(func, arg, &th)) {
337
0
        return PYTHREAD_INVALID_THREAD_ID;
338
0
    }
339
0
    pthread_detach(th);
340
0
    return (unsigned long) _pthread_t_to_ident(th);;
341
0
}
342
343
int
344
0
PyThread_join_thread(PyThread_handle_t th) {
345
0
    return pthread_join((pthread_t) th, NULL);
346
0
}
347
348
int
349
0
PyThread_detach_thread(PyThread_handle_t th) {
350
0
    return pthread_detach((pthread_t) th);
351
0
}
352
353
/* XXX This implementation is considered (to quote Tim Peters) "inherently
354
   hosed" because:
355
     - It does not guarantee the promise that a non-zero integer is returned.
356
     - The cast to unsigned long is inherently unsafe.
357
     - It is not clear that the 'volatile' (for AIX?) are any longer necessary.
358
*/
359
PyThread_ident_t
360
105M
PyThread_get_thread_ident_ex(void) {
361
105M
    volatile pthread_t threadid;
362
105M
    if (!initialized)
363
16
        PyThread_init_thread();
364
105M
    threadid = pthread_self();
365
105M
    return _pthread_t_to_ident(threadid);
366
105M
}
367
368
unsigned long
369
PyThread_get_thread_ident(void)
370
105M
{
371
105M
    return (unsigned long) PyThread_get_thread_ident_ex();
372
105M
}
373
374
#ifdef PY_HAVE_THREAD_NATIVE_ID
375
unsigned long
376
PyThread_get_thread_native_id(void)
377
16
{
378
16
    if (!initialized)
379
0
        PyThread_init_thread();
380
#ifdef __APPLE__
381
    uint64_t native_id;
382
    (void) pthread_threadid_np(NULL, &native_id);
383
#elif defined(__linux__)
384
    pid_t native_id;
385
16
    native_id = syscall(SYS_gettid);
386
#elif defined(__FreeBSD__)
387
    int native_id;
388
    native_id = pthread_getthreadid_np();
389
#elif defined(__FreeBSD_kernel__)
390
    long native_id;
391
    syscall(SYS_thr_self, &native_id);
392
#elif defined(__OpenBSD__)
393
    pid_t native_id;
394
    native_id = getthrid();
395
#elif defined(_AIX)
396
    tid_t native_id;
397
    native_id = thread_self();
398
#elif defined(__NetBSD__)
399
    lwpid_t native_id;
400
    native_id = _lwp_self();
401
#elif defined(__DragonFly__)
402
    lwpid_t native_id;
403
    native_id = lwp_gettid();
404
#elif defined(__sun__) && SIZEOF_LONG >= 8
405
    unsigned long native_id = (unsigned long)getpid() << 32 | thr_self();
406
#endif
407
16
    return (unsigned long) native_id;
408
16
}
409
#endif
410
411
void _Py_NO_RETURN
412
PyThread_exit_thread(void)
413
0
{
414
0
    if (!initialized)
415
0
        exit(0);
416
#if defined(__wasi__)
417
    /*
418
     * wasi-threads doesn't have pthread_exit right now
419
     * cf. https://github.com/WebAssembly/wasi-threads/issues/7
420
     */
421
    abort();
422
#else
423
0
    pthread_exit(0);
424
0
#endif
425
0
}
426
427
void _Py_NO_RETURN
428
PyThread_hang_thread(void)
429
0
{
430
0
    while (1) {
431
#if defined(__wasi__)
432
        sleep(9999999);  // WASI doesn't have pause() ?!
433
#else
434
0
        pause();
435
0
#endif
436
0
    }
437
0
}
438
439
440
/* set the thread stack size.
441
 * Return 0 if size is valid, -1 if size is invalid,
442
 * -2 if setting stack size is not supported.
443
 */
444
static int
445
_pythread_pthread_set_stacksize(size_t size)
446
0
{
447
0
#if defined(THREAD_STACK_SIZE)
448
0
    pthread_attr_t attrs;
449
0
    size_t tss_min;
450
0
    int rc = 0;
451
0
#endif
452
453
    /* set to default */
454
0
    if (size == 0) {
455
0
        _PyInterpreterState_GET()->threads.stacksize = 0;
456
0
        return 0;
457
0
    }
458
459
0
#if defined(THREAD_STACK_SIZE)
460
0
#if defined(PTHREAD_STACK_MIN)
461
0
    tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN
462
0
                                                   : THREAD_STACK_MIN;
463
#else
464
    tss_min = THREAD_STACK_MIN;
465
#endif
466
0
    if (size >= tss_min) {
467
        /* validate stack size by setting thread attribute */
468
0
        if (pthread_attr_init(&attrs) == 0) {
469
0
            rc = pthread_attr_setstacksize(&attrs, size);
470
0
            pthread_attr_destroy(&attrs);
471
0
            if (rc == 0) {
472
0
                _PyInterpreterState_GET()->threads.stacksize = size;
473
0
                return 0;
474
0
            }
475
0
        }
476
0
    }
477
0
    return -1;
478
#else
479
    return -2;
480
#endif
481
0
}
482
483
0
#define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x)
484
485
486
/* Thread Local Storage (TLS) API
487
488
   This API is DEPRECATED since Python 3.7.  See PEP 539 for details.
489
*/
490
491
/* Issue #25658: On platforms where native TLS key is defined in a way that
492
   cannot be safely cast to int, PyThread_create_key returns immediately a
493
   failure status and other TLS functions all are no-ops.  This indicates
494
   clearly that the old API is not supported on platforms where it cannot be
495
   used reliably, and that no effort will be made to add such support.
496
497
   Note: PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT will be unnecessary after
498
   removing this API.
499
*/
500
501
int
502
PyThread_create_key(void)
503
0
{
504
0
#ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
505
0
    pthread_key_t key;
506
0
    int fail = pthread_key_create(&key, NULL);
507
0
    if (fail)
508
0
        return -1;
509
0
    if (key > INT_MAX) {
510
        /* Issue #22206: handle integer overflow */
511
0
        pthread_key_delete(key);
512
0
        errno = ENOMEM;
513
0
        return -1;
514
0
    }
515
0
    return (int)key;
516
#else
517
    return -1;  /* never return valid key value. */
518
#endif
519
0
}
520
521
void
522
PyThread_delete_key(int key)
523
0
{
524
0
#ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
525
0
    pthread_key_delete(key);
526
0
#endif
527
0
}
528
529
void
530
PyThread_delete_key_value(int key)
531
0
{
532
0
#ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
533
0
    pthread_setspecific(key, NULL);
534
0
#endif
535
0
}
536
537
int
538
PyThread_set_key_value(int key, void *value)
539
0
{
540
0
#ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
541
0
    int fail = pthread_setspecific(key, value);
542
0
    return fail ? -1 : 0;
543
#else
544
    return -1;
545
#endif
546
0
}
547
548
void *
549
PyThread_get_key_value(int key)
550
0
{
551
0
#ifdef PTHREAD_KEY_T_IS_COMPATIBLE_WITH_INT
552
0
    return pthread_getspecific(key);
553
#else
554
    return NULL;
555
#endif
556
0
}
557
558
559
void
560
PyThread_ReInitTLS(void)
561
0
{
562
0
}
563
564
565
/* Thread Specific Storage (TSS) API
566
567
   Platform-specific components of TSS API implementation.
568
*/
569
570
int
571
PyThread_tss_create(Py_tss_t *key)
572
16
{
573
16
    assert(key != NULL);
574
    /* If the key has been created, function is silently skipped. */
575
16
    if (key->_is_initialized) {
576
0
        return 0;
577
0
    }
578
579
16
    int fail = pthread_key_create(&(key->_key), NULL);
580
16
    if (fail) {
581
0
        return -1;
582
0
    }
583
16
    key->_is_initialized = 1;
584
16
    return 0;
585
16
}
586
587
void
588
PyThread_tss_delete(Py_tss_t *key)
589
0
{
590
0
    assert(key != NULL);
591
    /* If the key has not been created, function is silently skipped. */
592
0
    if (!key->_is_initialized) {
593
0
        return;
594
0
    }
595
596
0
    pthread_key_delete(key->_key);
597
    /* pthread has not provided the defined invalid value for the key. */
598
0
    key->_is_initialized = 0;
599
0
}
600
601
int
602
PyThread_tss_set(Py_tss_t *key, void *value)
603
0
{
604
0
    assert(key != NULL);
605
0
    int fail = pthread_setspecific(key->_key, value);
606
0
    return fail ? -1 : 0;
607
0
}
608
609
void *
610
PyThread_tss_get(Py_tss_t *key)
611
0
{
612
0
    assert(key != NULL);
613
0
    return pthread_getspecific(key->_key);
614
0
}