LCOV - code coverage report
Current view: | top level - Python - thread_pthread.h (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 113 | 184 | 61.4 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 17 | 27 | 63.0 %
|  |  | Branches: | 48 | 102 | 47.1 %

               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                 :            : }

Generated by: LCOV version 1.14