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