Coverage Report

Created: 2025-07-04 06:49

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