LCOV - code coverage report
Current view: top level - Modules - _threadmodule.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit 5e6661bce9] Lines: 264 630 41.9 %
Date: 2023-03-20 08:15:36 Functions: 30 51 58.8 %
Branches: 116 362 32.0 %

           Branch data     Line data    Source code
       1                 :            : 
       2                 :            : /* Thread module */
       3                 :            : /* Interface to Sjoerd's portable C thread library */
       4                 :            : 
       5                 :            : #include "Python.h"
       6                 :            : #include "pycore_interp.h"        // _PyInterpreterState.threads.count
       7                 :            : #include "pycore_moduleobject.h"  // _PyModule_GetState()
       8                 :            : #include "pycore_pylifecycle.h"
       9                 :            : #include "pycore_pystate.h"       // _PyThreadState_SetCurrent()
      10                 :            : #include <stddef.h>               // offsetof()
      11                 :            : #include "structmember.h"         // PyMemberDef
      12                 :            : 
      13                 :            : #ifdef HAVE_SIGNAL_H
      14                 :            : #  include <signal.h>             // SIGINT
      15                 :            : #endif
      16                 :            : 
      17                 :            : // ThreadError is just an alias to PyExc_RuntimeError
      18                 :            : #define ThreadError PyExc_RuntimeError
      19                 :            : 
      20                 :            : 
      21                 :            : // Forward declarations
      22                 :            : static struct PyModuleDef thread_module;
      23                 :            : 
      24                 :            : 
      25                 :            : typedef struct {
      26                 :            :     PyTypeObject *excepthook_type;
      27                 :            :     PyTypeObject *lock_type;
      28                 :            :     PyTypeObject *local_type;
      29                 :            :     PyTypeObject *local_dummy_type;
      30                 :            : } thread_module_state;
      31                 :            : 
      32                 :            : static inline thread_module_state*
      33                 :       1383 : get_thread_state(PyObject *module)
      34                 :            : {
      35                 :       1383 :     void *state = _PyModule_GetState(module);
      36                 :            :     assert(state != NULL);
      37                 :       1383 :     return (thread_module_state *)state;
      38                 :            : }
      39                 :            : 
      40                 :            : 
      41                 :            : /* Lock objects */
      42                 :            : 
      43                 :            : typedef struct {
      44                 :            :     PyObject_HEAD
      45                 :            :     PyThread_type_lock lock_lock;
      46                 :            :     PyObject *in_weakreflist;
      47                 :            :     char locked; /* for sanity checking */
      48                 :            : } lockobject;
      49                 :            : 
      50                 :            : static int
      51                 :        756 : lock_traverse(lockobject *self, visitproc visit, void *arg)
      52                 :            : {
      53   [ +  -  -  + ]:        756 :     Py_VISIT(Py_TYPE(self));
      54                 :        756 :     return 0;
      55                 :            : }
      56                 :            : 
      57                 :            : static void
      58                 :       1061 : lock_dealloc(lockobject *self)
      59                 :            : {
      60                 :       1061 :     PyObject_GC_UnTrack(self);
      61         [ +  + ]:       1061 :     if (self->in_weakreflist != NULL) {
      62                 :          4 :         PyObject_ClearWeakRefs((PyObject *) self);
      63                 :            :     }
      64         [ +  - ]:       1061 :     if (self->lock_lock != NULL) {
      65                 :            :         /* Unlock the lock so it's safe to free it */
      66         [ -  + ]:       1061 :         if (self->locked)
      67                 :          0 :             PyThread_release_lock(self->lock_lock);
      68                 :       1061 :         PyThread_free_lock(self->lock_lock);
      69                 :            :     }
      70                 :       1061 :     PyTypeObject *tp = Py_TYPE(self);
      71                 :       1061 :     tp->tp_free((PyObject*)self);
      72                 :       1061 :     Py_DECREF(tp);
      73                 :       1061 : }
      74                 :            : 
      75                 :            : /* Helper to acquire an interruptible lock with a timeout.  If the lock acquire
      76                 :            :  * is interrupted, signal handlers are run, and if they raise an exception,
      77                 :            :  * PY_LOCK_INTR is returned.  Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE
      78                 :            :  * are returned, depending on whether the lock can be acquired within the
      79                 :            :  * timeout.
      80                 :            :  */
      81                 :            : static PyLockStatus
      82                 :       2605 : acquire_timed(PyThread_type_lock lock, _PyTime_t timeout)
      83                 :            : {
      84                 :       2605 :     _PyTime_t endtime = 0;
      85         [ -  + ]:       2605 :     if (timeout > 0) {
      86                 :          0 :         endtime = _PyDeadline_Init(timeout);
      87                 :            :     }
      88                 :            : 
      89                 :            :     PyLockStatus r;
      90                 :            :     do {
      91                 :            :         _PyTime_t microseconds;
      92                 :       2605 :         microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING);
      93                 :            : 
      94                 :            :         /* first a simple non-blocking try without releasing the GIL */
      95                 :       2605 :         r = PyThread_acquire_lock_timed(lock, 0, 0);
      96   [ +  +  -  + ]:       2605 :         if (r == PY_LOCK_FAILURE && microseconds != 0) {
      97                 :          0 :             Py_BEGIN_ALLOW_THREADS
      98                 :          0 :             r = PyThread_acquire_lock_timed(lock, microseconds, 1);
      99                 :          0 :             Py_END_ALLOW_THREADS
     100                 :            :         }
     101                 :            : 
     102         [ -  + ]:       2605 :         if (r == PY_LOCK_INTR) {
     103                 :            :             /* Run signal handlers if we were interrupted.  Propagate
     104                 :            :              * exceptions from signal handlers, such as KeyboardInterrupt, by
     105                 :            :              * passing up PY_LOCK_INTR.  */
     106         [ #  # ]:          0 :             if (Py_MakePendingCalls() < 0) {
     107                 :          0 :                 return PY_LOCK_INTR;
     108                 :            :             }
     109                 :            : 
     110                 :            :             /* If we're using a timeout, recompute the timeout after processing
     111                 :            :              * signals, since those can take time.  */
     112         [ #  # ]:          0 :             if (timeout > 0) {
     113                 :          0 :                 timeout = _PyDeadline_Get(endtime);
     114                 :            : 
     115                 :            :                 /* Check for negative values, since those mean block forever.
     116                 :            :                  */
     117         [ #  # ]:          0 :                 if (timeout < 0) {
     118                 :          0 :                     r = PY_LOCK_FAILURE;
     119                 :            :                 }
     120                 :            :             }
     121                 :            :         }
     122         [ -  + ]:       2605 :     } while (r == PY_LOCK_INTR);  /* Retry if we were interrupted. */
     123                 :            : 
     124                 :       2605 :     return r;
     125                 :            : }
     126                 :            : 
     127                 :            : static int
     128                 :       2611 : lock_acquire_parse_args(PyObject *args, PyObject *kwds,
     129                 :            :                         _PyTime_t *timeout)
     130                 :            : {
     131                 :       2611 :     char *kwlist[] = {"blocking", "timeout", NULL};
     132                 :       2611 :     int blocking = 1;
     133                 :       2611 :     PyObject *timeout_obj = NULL;
     134                 :       2611 :     const _PyTime_t unset_timeout = _PyTime_FromSeconds(-1);
     135                 :            : 
     136                 :       2611 :     *timeout = unset_timeout ;
     137                 :            : 
     138         [ -  + ]:       2611 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|pO:acquire", kwlist,
     139                 :            :                                      &blocking, &timeout_obj))
     140                 :          0 :         return -1;
     141                 :            : 
     142         [ -  + ]:       2611 :     if (timeout_obj
     143         [ #  # ]:          0 :         && _PyTime_FromSecondsObject(timeout,
     144                 :            :                                      timeout_obj, _PyTime_ROUND_TIMEOUT) < 0)
     145                 :          0 :         return -1;
     146                 :            : 
     147   [ +  +  -  + ]:       2611 :     if (!blocking && *timeout != unset_timeout ) {
     148                 :          0 :         PyErr_SetString(PyExc_ValueError,
     149                 :            :                         "can't specify a timeout for a non-blocking call");
     150                 :          0 :         return -1;
     151                 :            :     }
     152   [ +  -  -  + ]:       2611 :     if (*timeout < 0 && *timeout != unset_timeout) {
     153                 :          0 :         PyErr_SetString(PyExc_ValueError,
     154                 :            :                         "timeout value must be positive");
     155                 :          0 :         return -1;
     156                 :            :     }
     157         [ +  + ]:       2611 :     if (!blocking)
     158                 :          4 :         *timeout = 0;
     159         [ -  + ]:       2607 :     else if (*timeout != unset_timeout) {
     160                 :            :         _PyTime_t microseconds;
     161                 :            : 
     162                 :          0 :         microseconds = _PyTime_AsMicroseconds(*timeout, _PyTime_ROUND_TIMEOUT);
     163         [ #  # ]:          0 :         if (microseconds > PY_TIMEOUT_MAX) {
     164                 :          0 :             PyErr_SetString(PyExc_OverflowError,
     165                 :            :                             "timeout value is too large");
     166                 :          0 :             return -1;
     167                 :            :         }
     168                 :            :     }
     169                 :       2611 :     return 0;
     170                 :            : }
     171                 :            : 
     172                 :            : static PyObject *
     173                 :         24 : lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds)
     174                 :            : {
     175                 :            :     _PyTime_t timeout;
     176         [ -  + ]:         24 :     if (lock_acquire_parse_args(args, kwds, &timeout) < 0)
     177                 :          0 :         return NULL;
     178                 :            : 
     179                 :         24 :     PyLockStatus r = acquire_timed(self->lock_lock, timeout);
     180         [ -  + ]:         24 :     if (r == PY_LOCK_INTR) {
     181                 :          0 :         return NULL;
     182                 :            :     }
     183                 :            : 
     184         [ +  + ]:         24 :     if (r == PY_LOCK_ACQUIRED)
     185                 :         20 :         self->locked = 1;
     186                 :         24 :     return PyBool_FromLong(r == PY_LOCK_ACQUIRED);
     187                 :            : }
     188                 :            : 
     189                 :            : PyDoc_STRVAR(acquire_doc,
     190                 :            : "acquire(blocking=True, timeout=-1) -> bool\n\
     191                 :            : (acquire_lock() is an obsolete synonym)\n\
     192                 :            : \n\
     193                 :            : Lock the lock.  Without argument, this blocks if the lock is already\n\
     194                 :            : locked (even by the same thread), waiting for another thread to release\n\
     195                 :            : the lock, and return True once the lock is acquired.\n\
     196                 :            : With an argument, this will only block if the argument is true,\n\
     197                 :            : and the return value reflects whether the lock is acquired.\n\
     198                 :            : The blocking operation is interruptible.");
     199                 :            : 
     200                 :            : static PyObject *
     201                 :         20 : lock_PyThread_release_lock(lockobject *self, PyObject *Py_UNUSED(ignored))
     202                 :            : {
     203                 :            :     /* Sanity check: the lock must be locked */
     204         [ -  + ]:         20 :     if (!self->locked) {
     205                 :          0 :         PyErr_SetString(ThreadError, "release unlocked lock");
     206                 :          0 :         return NULL;
     207                 :            :     }
     208                 :            : 
     209                 :         20 :     PyThread_release_lock(self->lock_lock);
     210                 :         20 :     self->locked = 0;
     211                 :         20 :     Py_RETURN_NONE;
     212                 :            : }
     213                 :            : 
     214                 :            : PyDoc_STRVAR(release_doc,
     215                 :            : "release()\n\
     216                 :            : (release_lock() is an obsolete synonym)\n\
     217                 :            : \n\
     218                 :            : Release the lock, allowing another thread that is blocked waiting for\n\
     219                 :            : the lock to acquire the lock.  The lock must be in the locked state,\n\
     220                 :            : but it needn't be locked by the same thread that unlocks it.");
     221                 :            : 
     222                 :            : static PyObject *
     223                 :         12 : lock_locked_lock(lockobject *self, PyObject *Py_UNUSED(ignored))
     224                 :            : {
     225                 :         12 :     return PyBool_FromLong((long)self->locked);
     226                 :            : }
     227                 :            : 
     228                 :            : PyDoc_STRVAR(locked_doc,
     229                 :            : "locked() -> bool\n\
     230                 :            : (locked_lock() is an obsolete synonym)\n\
     231                 :            : \n\
     232                 :            : Return whether the lock is in the locked state.");
     233                 :            : 
     234                 :            : static PyObject *
     235                 :          0 : lock_repr(lockobject *self)
     236                 :            : {
     237                 :          0 :     return PyUnicode_FromFormat("<%s %s object at %p>",
     238         [ #  # ]:          0 :         self->locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self);
     239                 :            : }
     240                 :            : 
     241                 :            : #ifdef HAVE_FORK
     242                 :            : static PyObject *
     243                 :          0 : lock__at_fork_reinit(lockobject *self, PyObject *Py_UNUSED(args))
     244                 :            : {
     245         [ #  # ]:          0 :     if (_PyThread_at_fork_reinit(&self->lock_lock) < 0) {
     246                 :          0 :         PyErr_SetString(ThreadError, "failed to reinitialize lock at fork");
     247                 :          0 :         return NULL;
     248                 :            :     }
     249                 :            : 
     250                 :          0 :     self->locked = 0;
     251                 :            : 
     252                 :          0 :     Py_RETURN_NONE;
     253                 :            : }
     254                 :            : #endif  /* HAVE_FORK */
     255                 :            : 
     256                 :            : 
     257                 :            : static PyMethodDef lock_methods[] = {
     258                 :            :     {"acquire_lock", _PyCFunction_CAST(lock_PyThread_acquire_lock),
     259                 :            :      METH_VARARGS | METH_KEYWORDS, acquire_doc},
     260                 :            :     {"acquire",      _PyCFunction_CAST(lock_PyThread_acquire_lock),
     261                 :            :      METH_VARARGS | METH_KEYWORDS, acquire_doc},
     262                 :            :     {"release_lock", (PyCFunction)lock_PyThread_release_lock,
     263                 :            :      METH_NOARGS, release_doc},
     264                 :            :     {"release",      (PyCFunction)lock_PyThread_release_lock,
     265                 :            :      METH_NOARGS, release_doc},
     266                 :            :     {"locked_lock",  (PyCFunction)lock_locked_lock,
     267                 :            :      METH_NOARGS, locked_doc},
     268                 :            :     {"locked",       (PyCFunction)lock_locked_lock,
     269                 :            :      METH_NOARGS, locked_doc},
     270                 :            :     {"__enter__",    _PyCFunction_CAST(lock_PyThread_acquire_lock),
     271                 :            :      METH_VARARGS | METH_KEYWORDS, acquire_doc},
     272                 :            :     {"__exit__",    (PyCFunction)lock_PyThread_release_lock,
     273                 :            :      METH_VARARGS, release_doc},
     274                 :            : #ifdef HAVE_FORK
     275                 :            :     {"_at_fork_reinit",    (PyCFunction)lock__at_fork_reinit,
     276                 :            :      METH_NOARGS, NULL},
     277                 :            : #endif
     278                 :            :     {NULL,           NULL}              /* sentinel */
     279                 :            : };
     280                 :            : 
     281                 :            : PyDoc_STRVAR(lock_doc,
     282                 :            : "A lock object is a synchronization primitive.  To create a lock,\n\
     283                 :            : call threading.Lock().  Methods are:\n\
     284                 :            : \n\
     285                 :            : acquire() -- lock the lock, possibly blocking until it can be obtained\n\
     286                 :            : release() -- unlock of the lock\n\
     287                 :            : locked() -- test whether the lock is currently locked\n\
     288                 :            : \n\
     289                 :            : A lock is not owned by the thread that locked it; another thread may\n\
     290                 :            : unlock it.  A thread attempting to lock a lock that it has already locked\n\
     291                 :            : will block until another thread unlocks it.  Deadlocks may ensue.");
     292                 :            : 
     293                 :            : static PyMemberDef lock_type_members[] = {
     294                 :            :     {"__weaklistoffset__", T_PYSSIZET, offsetof(lockobject, in_weakreflist), READONLY},
     295                 :            :     {NULL},
     296                 :            : };
     297                 :            : 
     298                 :            : static PyType_Slot lock_type_slots[] = {
     299                 :            :     {Py_tp_dealloc, (destructor)lock_dealloc},
     300                 :            :     {Py_tp_repr, (reprfunc)lock_repr},
     301                 :            :     {Py_tp_doc, (void *)lock_doc},
     302                 :            :     {Py_tp_methods, lock_methods},
     303                 :            :     {Py_tp_traverse, lock_traverse},
     304                 :            :     {Py_tp_members, lock_type_members},
     305                 :            :     {0, 0}
     306                 :            : };
     307                 :            : 
     308                 :            : static PyType_Spec lock_type_spec = {
     309                 :            :     .name = "_thread.lock",
     310                 :            :     .basicsize = sizeof(lockobject),
     311                 :            :     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
     312                 :            :               Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE),
     313                 :            :     .slots = lock_type_slots,
     314                 :            : };
     315                 :            : 
     316                 :            : /* Recursive lock objects */
     317                 :            : 
     318                 :            : typedef struct {
     319                 :            :     PyObject_HEAD
     320                 :            :     PyThread_type_lock rlock_lock;
     321                 :            :     unsigned long rlock_owner;
     322                 :            :     unsigned long rlock_count;
     323                 :            :     PyObject *in_weakreflist;
     324                 :            : } rlockobject;
     325                 :            : 
     326                 :            : static int
     327                 :        700 : rlock_traverse(rlockobject *self, visitproc visit, void *arg)
     328                 :            : {
     329   [ +  -  -  + ]:        700 :     Py_VISIT(Py_TYPE(self));
     330                 :        700 :     return 0;
     331                 :            : }
     332                 :            : 
     333                 :            : 
     334                 :            : static void
     335                 :       1057 : rlock_dealloc(rlockobject *self)
     336                 :            : {
     337                 :       1057 :     PyObject_GC_UnTrack(self);
     338         [ -  + ]:       1057 :     if (self->in_weakreflist != NULL)
     339                 :          0 :         PyObject_ClearWeakRefs((PyObject *) self);
     340                 :            :     /* self->rlock_lock can be NULL if PyThread_allocate_lock() failed
     341                 :            :        in rlock_new() */
     342         [ +  - ]:       1057 :     if (self->rlock_lock != NULL) {
     343                 :            :         /* Unlock the lock so it's safe to free it */
     344         [ -  + ]:       1057 :         if (self->rlock_count > 0)
     345                 :          0 :             PyThread_release_lock(self->rlock_lock);
     346                 :            : 
     347                 :       1057 :         PyThread_free_lock(self->rlock_lock);
     348                 :            :     }
     349                 :       1057 :     PyTypeObject *tp = Py_TYPE(self);
     350                 :       1057 :     tp->tp_free(self);
     351                 :       1057 :     Py_DECREF(tp);
     352                 :       1057 : }
     353                 :            : 
     354                 :            : static PyObject *
     355                 :       2587 : rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds)
     356                 :            : {
     357                 :            :     _PyTime_t timeout;
     358                 :            :     unsigned long tid;
     359                 :       2587 :     PyLockStatus r = PY_LOCK_ACQUIRED;
     360                 :            : 
     361         [ -  + ]:       2587 :     if (lock_acquire_parse_args(args, kwds, &timeout) < 0)
     362                 :          0 :         return NULL;
     363                 :            : 
     364                 :       2587 :     tid = PyThread_get_thread_ident();
     365   [ +  +  +  - ]:       2587 :     if (self->rlock_count > 0 && tid == self->rlock_owner) {
     366                 :          6 :         unsigned long count = self->rlock_count + 1;
     367         [ -  + ]:          6 :         if (count <= self->rlock_count) {
     368                 :          0 :             PyErr_SetString(PyExc_OverflowError,
     369                 :            :                             "Internal lock count overflowed");
     370                 :          0 :             return NULL;
     371                 :            :         }
     372                 :          6 :         self->rlock_count = count;
     373                 :          6 :         Py_RETURN_TRUE;
     374                 :            :     }
     375                 :       2581 :     r = acquire_timed(self->rlock_lock, timeout);
     376         [ +  - ]:       2581 :     if (r == PY_LOCK_ACQUIRED) {
     377                 :            :         assert(self->rlock_count == 0);
     378                 :       2581 :         self->rlock_owner = tid;
     379                 :       2581 :         self->rlock_count = 1;
     380                 :            :     }
     381         [ #  # ]:          0 :     else if (r == PY_LOCK_INTR) {
     382                 :          0 :         return NULL;
     383                 :            :     }
     384                 :            : 
     385                 :       2581 :     return PyBool_FromLong(r == PY_LOCK_ACQUIRED);
     386                 :            : }
     387                 :            : 
     388                 :            : PyDoc_STRVAR(rlock_acquire_doc,
     389                 :            : "acquire(blocking=True) -> bool\n\
     390                 :            : \n\
     391                 :            : Lock the lock.  `blocking` indicates whether we should wait\n\
     392                 :            : for the lock to be available or not.  If `blocking` is False\n\
     393                 :            : and another thread holds the lock, the method will return False\n\
     394                 :            : immediately.  If `blocking` is True and another thread holds\n\
     395                 :            : the lock, the method will wait for the lock to be released,\n\
     396                 :            : take it and then return True.\n\
     397                 :            : (note: the blocking operation is interruptible.)\n\
     398                 :            : \n\
     399                 :            : In all other cases, the method will return True immediately.\n\
     400                 :            : Precisely, if the current thread already holds the lock, its\n\
     401                 :            : internal counter is simply incremented. If nobody holds the lock,\n\
     402                 :            : the lock is taken and its internal counter initialized to 1.");
     403                 :            : 
     404                 :            : static PyObject *
     405                 :       2587 : rlock_release(rlockobject *self, PyObject *Py_UNUSED(ignored))
     406                 :            : {
     407                 :       2587 :     unsigned long tid = PyThread_get_thread_ident();
     408                 :            : 
     409   [ +  -  -  + ]:       2587 :     if (self->rlock_count == 0 || self->rlock_owner != tid) {
     410                 :          0 :         PyErr_SetString(PyExc_RuntimeError,
     411                 :            :                         "cannot release un-acquired lock");
     412                 :          0 :         return NULL;
     413                 :            :     }
     414         [ +  + ]:       2587 :     if (--self->rlock_count == 0) {
     415                 :       2581 :         self->rlock_owner = 0;
     416                 :       2581 :         PyThread_release_lock(self->rlock_lock);
     417                 :            :     }
     418                 :       2587 :     Py_RETURN_NONE;
     419                 :            : }
     420                 :            : 
     421                 :            : PyDoc_STRVAR(rlock_release_doc,
     422                 :            : "release()\n\
     423                 :            : \n\
     424                 :            : Release the lock, allowing another thread that is blocked waiting for\n\
     425                 :            : the lock to acquire the lock.  The lock must be in the locked state,\n\
     426                 :            : and must be locked by the same thread that unlocks it; otherwise a\n\
     427                 :            : `RuntimeError` is raised.\n\
     428                 :            : \n\
     429                 :            : Do note that if the lock was acquire()d several times in a row by the\n\
     430                 :            : current thread, release() needs to be called as many times for the lock\n\
     431                 :            : to be available for other threads.");
     432                 :            : 
     433                 :            : static PyObject *
     434                 :          0 : rlock_acquire_restore(rlockobject *self, PyObject *args)
     435                 :            : {
     436                 :            :     unsigned long owner;
     437                 :            :     unsigned long count;
     438                 :          0 :     int r = 1;
     439                 :            : 
     440         [ #  # ]:          0 :     if (!PyArg_ParseTuple(args, "(kk):_acquire_restore", &count, &owner))
     441                 :          0 :         return NULL;
     442                 :            : 
     443         [ #  # ]:          0 :     if (!PyThread_acquire_lock(self->rlock_lock, 0)) {
     444                 :          0 :         Py_BEGIN_ALLOW_THREADS
     445                 :          0 :         r = PyThread_acquire_lock(self->rlock_lock, 1);
     446                 :          0 :         Py_END_ALLOW_THREADS
     447                 :            :     }
     448         [ #  # ]:          0 :     if (!r) {
     449                 :          0 :         PyErr_SetString(ThreadError, "couldn't acquire lock");
     450                 :          0 :         return NULL;
     451                 :            :     }
     452                 :            :     assert(self->rlock_count == 0);
     453                 :          0 :     self->rlock_owner = owner;
     454                 :          0 :     self->rlock_count = count;
     455                 :          0 :     Py_RETURN_NONE;
     456                 :            : }
     457                 :            : 
     458                 :            : PyDoc_STRVAR(rlock_acquire_restore_doc,
     459                 :            : "_acquire_restore(state) -> None\n\
     460                 :            : \n\
     461                 :            : For internal use by `threading.Condition`.");
     462                 :            : 
     463                 :            : static PyObject *
     464                 :          0 : rlock_release_save(rlockobject *self, PyObject *Py_UNUSED(ignored))
     465                 :            : {
     466                 :            :     unsigned long owner;
     467                 :            :     unsigned long count;
     468                 :            : 
     469         [ #  # ]:          0 :     if (self->rlock_count == 0) {
     470                 :          0 :         PyErr_SetString(PyExc_RuntimeError,
     471                 :            :                         "cannot release un-acquired lock");
     472                 :          0 :         return NULL;
     473                 :            :     }
     474                 :            : 
     475                 :          0 :     owner = self->rlock_owner;
     476                 :          0 :     count = self->rlock_count;
     477                 :          0 :     self->rlock_count = 0;
     478                 :          0 :     self->rlock_owner = 0;
     479                 :          0 :     PyThread_release_lock(self->rlock_lock);
     480                 :          0 :     return Py_BuildValue("kk", count, owner);
     481                 :            : }
     482                 :            : 
     483                 :            : PyDoc_STRVAR(rlock_release_save_doc,
     484                 :            : "_release_save() -> tuple\n\
     485                 :            : \n\
     486                 :            : For internal use by `threading.Condition`.");
     487                 :            : 
     488                 :            : 
     489                 :            : static PyObject *
     490                 :          0 : rlock_is_owned(rlockobject *self, PyObject *Py_UNUSED(ignored))
     491                 :            : {
     492                 :          0 :     unsigned long tid = PyThread_get_thread_ident();
     493                 :            : 
     494   [ #  #  #  # ]:          0 :     if (self->rlock_count > 0 && self->rlock_owner == tid) {
     495                 :          0 :         Py_RETURN_TRUE;
     496                 :            :     }
     497                 :          0 :     Py_RETURN_FALSE;
     498                 :            : }
     499                 :            : 
     500                 :            : PyDoc_STRVAR(rlock_is_owned_doc,
     501                 :            : "_is_owned() -> bool\n\
     502                 :            : \n\
     503                 :            : For internal use by `threading.Condition`.");
     504                 :            : 
     505                 :            : static PyObject *
     506                 :       1057 : rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     507                 :            : {
     508                 :       1057 :     rlockobject *self = (rlockobject *) type->tp_alloc(type, 0);
     509         [ -  + ]:       1057 :     if (self == NULL) {
     510                 :          0 :         return NULL;
     511                 :            :     }
     512                 :       1057 :     self->in_weakreflist = NULL;
     513                 :       1057 :     self->rlock_owner = 0;
     514                 :       1057 :     self->rlock_count = 0;
     515                 :            : 
     516                 :       1057 :     self->rlock_lock = PyThread_allocate_lock();
     517         [ -  + ]:       1057 :     if (self->rlock_lock == NULL) {
     518                 :          0 :         Py_DECREF(self);
     519                 :          0 :         PyErr_SetString(ThreadError, "can't allocate lock");
     520                 :          0 :         return NULL;
     521                 :            :     }
     522                 :       1057 :     return (PyObject *) self;
     523                 :            : }
     524                 :            : 
     525                 :            : static PyObject *
     526                 :          0 : rlock_repr(rlockobject *self)
     527                 :            : {
     528                 :          0 :     return PyUnicode_FromFormat("<%s %s object owner=%ld count=%lu at %p>",
     529         [ #  # ]:          0 :         self->rlock_count ? "locked" : "unlocked",
     530                 :          0 :         Py_TYPE(self)->tp_name, self->rlock_owner,
     531                 :            :         self->rlock_count, self);
     532                 :            : }
     533                 :            : 
     534                 :            : 
     535                 :            : #ifdef HAVE_FORK
     536                 :            : static PyObject *
     537                 :          0 : rlock__at_fork_reinit(rlockobject *self, PyObject *Py_UNUSED(args))
     538                 :            : {
     539         [ #  # ]:          0 :     if (_PyThread_at_fork_reinit(&self->rlock_lock) < 0) {
     540                 :          0 :         PyErr_SetString(ThreadError, "failed to reinitialize lock at fork");
     541                 :          0 :         return NULL;
     542                 :            :     }
     543                 :            : 
     544                 :          0 :     self->rlock_owner = 0;
     545                 :          0 :     self->rlock_count = 0;
     546                 :            : 
     547                 :          0 :     Py_RETURN_NONE;
     548                 :            : }
     549                 :            : #endif  /* HAVE_FORK */
     550                 :            : 
     551                 :            : 
     552                 :            : static PyMethodDef rlock_methods[] = {
     553                 :            :     {"acquire",      _PyCFunction_CAST(rlock_acquire),
     554                 :            :      METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc},
     555                 :            :     {"release",      (PyCFunction)rlock_release,
     556                 :            :      METH_NOARGS, rlock_release_doc},
     557                 :            :     {"_is_owned",     (PyCFunction)rlock_is_owned,
     558                 :            :      METH_NOARGS, rlock_is_owned_doc},
     559                 :            :     {"_acquire_restore", (PyCFunction)rlock_acquire_restore,
     560                 :            :      METH_VARARGS, rlock_acquire_restore_doc},
     561                 :            :     {"_release_save", (PyCFunction)rlock_release_save,
     562                 :            :      METH_NOARGS, rlock_release_save_doc},
     563                 :            :     {"__enter__",    _PyCFunction_CAST(rlock_acquire),
     564                 :            :      METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc},
     565                 :            :     {"__exit__",    (PyCFunction)rlock_release,
     566                 :            :      METH_VARARGS, rlock_release_doc},
     567                 :            : #ifdef HAVE_FORK
     568                 :            :     {"_at_fork_reinit",    (PyCFunction)rlock__at_fork_reinit,
     569                 :            :      METH_NOARGS, NULL},
     570                 :            : #endif
     571                 :            :     {NULL,           NULL}              /* sentinel */
     572                 :            : };
     573                 :            : 
     574                 :            : 
     575                 :            : static PyMemberDef rlock_type_members[] = {
     576                 :            :     {"__weaklistoffset__", T_PYSSIZET, offsetof(rlockobject, in_weakreflist), READONLY},
     577                 :            :     {NULL},
     578                 :            : };
     579                 :            : 
     580                 :            : static PyType_Slot rlock_type_slots[] = {
     581                 :            :     {Py_tp_dealloc, (destructor)rlock_dealloc},
     582                 :            :     {Py_tp_repr, (reprfunc)rlock_repr},
     583                 :            :     {Py_tp_methods, rlock_methods},
     584                 :            :     {Py_tp_alloc, PyType_GenericAlloc},
     585                 :            :     {Py_tp_new, rlock_new},
     586                 :            :     {Py_tp_members, rlock_type_members},
     587                 :            :     {Py_tp_traverse, rlock_traverse},
     588                 :            :     {0, 0},
     589                 :            : };
     590                 :            : 
     591                 :            : static PyType_Spec rlock_type_spec = {
     592                 :            :     .name = "_thread.RLock",
     593                 :            :     .basicsize = sizeof(rlockobject),
     594                 :            :     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
     595                 :            :               Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
     596                 :            :     .slots = rlock_type_slots,
     597                 :            : };
     598                 :            : 
     599                 :            : static lockobject *
     600                 :       1061 : newlockobject(PyObject *module)
     601                 :            : {
     602                 :       1061 :     thread_module_state *state = get_thread_state(module);
     603                 :            : 
     604                 :       1061 :     PyTypeObject *type = state->lock_type;
     605                 :       1061 :     lockobject *self = (lockobject *)type->tp_alloc(type, 0);
     606         [ -  + ]:       1061 :     if (self == NULL) {
     607                 :          0 :         return NULL;
     608                 :            :     }
     609                 :            : 
     610                 :       1061 :     self->lock_lock = PyThread_allocate_lock();
     611                 :       1061 :     self->locked = 0;
     612                 :       1061 :     self->in_weakreflist = NULL;
     613                 :            : 
     614         [ -  + ]:       1061 :     if (self->lock_lock == NULL) {
     615                 :          0 :         Py_DECREF(self);
     616                 :          0 :         PyErr_SetString(ThreadError, "can't allocate lock");
     617                 :          0 :         return NULL;
     618                 :            :     }
     619                 :       1061 :     return self;
     620                 :            : }
     621                 :            : 
     622                 :            : /* Thread-local objects */
     623                 :            : 
     624                 :            : /* Quick overview:
     625                 :            : 
     626                 :            :    We need to be able to reclaim reference cycles as soon as possible
     627                 :            :    (both when a thread is being terminated, or a thread-local object
     628                 :            :     becomes unreachable from user data).  Constraints:
     629                 :            :    - it must not be possible for thread-state dicts to be involved in
     630                 :            :      reference cycles (otherwise the cyclic GC will refuse to consider
     631                 :            :      objects referenced from a reachable thread-state dict, even though
     632                 :            :      local_dealloc would clear them)
     633                 :            :    - the death of a thread-state dict must still imply destruction of the
     634                 :            :      corresponding local dicts in all thread-local objects.
     635                 :            : 
     636                 :            :    Our implementation uses small "localdummy" objects in order to break
     637                 :            :    the reference chain. These trivial objects are hashable (using the
     638                 :            :    default scheme of identity hashing) and weakrefable.
     639                 :            :    Each thread-state holds a separate localdummy for each local object
     640                 :            :    (as a /strong reference/),
     641                 :            :    and each thread-local object holds a dict mapping /weak references/
     642                 :            :    of localdummies to local dicts.
     643                 :            : 
     644                 :            :    Therefore:
     645                 :            :    - only the thread-state dict holds a strong reference to the dummies
     646                 :            :    - only the thread-local object holds a strong reference to the local dicts
     647                 :            :    - only outside objects (application- or library-level) hold strong
     648                 :            :      references to the thread-local objects
     649                 :            :    - as soon as a thread-state dict is destroyed, the weakref callbacks of all
     650                 :            :      dummies attached to that thread are called, and destroy the corresponding
     651                 :            :      local dicts from thread-local objects
     652                 :            :    - as soon as a thread-local object is destroyed, its local dicts are
     653                 :            :      destroyed and its dummies are manually removed from all thread states
     654                 :            :    - the GC can do its work correctly when a thread-local object is dangling,
     655                 :            :      without any interference from the thread-state dicts
     656                 :            : 
     657                 :            :    As an additional optimization, each localdummy holds a borrowed reference
     658                 :            :    to the corresponding localdict.  This borrowed reference is only used
     659                 :            :    by the thread-local object which has created the localdummy, which should
     660                 :            :    guarantee that the localdict still exists when accessed.
     661                 :            : */
     662                 :            : 
     663                 :            : typedef struct {
     664                 :            :     PyObject_HEAD
     665                 :            :     PyObject *localdict;        /* Borrowed reference! */
     666                 :            :     PyObject *weakreflist;      /* List of weak references to self */
     667                 :            : } localdummyobject;
     668                 :            : 
     669                 :            : static void
     670                 :          1 : localdummy_dealloc(localdummyobject *self)
     671                 :            : {
     672         [ -  + ]:          1 :     if (self->weakreflist != NULL)
     673                 :          0 :         PyObject_ClearWeakRefs((PyObject *) self);
     674                 :          1 :     PyTypeObject *tp = Py_TYPE(self);
     675                 :          1 :     tp->tp_free((PyObject*)self);
     676                 :          1 :     Py_DECREF(tp);
     677                 :          1 : }
     678                 :            : 
     679                 :            : static PyMemberDef local_dummy_type_members[] = {
     680                 :            :     {"__weaklistoffset__", T_PYSSIZET, offsetof(localdummyobject, weakreflist), READONLY},
     681                 :            :     {NULL},
     682                 :            : };
     683                 :            : 
     684                 :            : static PyType_Slot local_dummy_type_slots[] = {
     685                 :            :     {Py_tp_dealloc, (destructor)localdummy_dealloc},
     686                 :            :     {Py_tp_doc, "Thread-local dummy"},
     687                 :            :     {Py_tp_members, local_dummy_type_members},
     688                 :            :     {0, 0}
     689                 :            : };
     690                 :            : 
     691                 :            : static PyType_Spec local_dummy_type_spec = {
     692                 :            :     .name = "_thread._localdummy",
     693                 :            :     .basicsize = sizeof(localdummyobject),
     694                 :            :     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
     695                 :            :               Py_TPFLAGS_IMMUTABLETYPE),
     696                 :            :     .slots = local_dummy_type_slots,
     697                 :            : };
     698                 :            : 
     699                 :            : 
     700                 :            : typedef struct {
     701                 :            :     PyObject_HEAD
     702                 :            :     PyObject *key;
     703                 :            :     PyObject *args;
     704                 :            :     PyObject *kw;
     705                 :            :     PyObject *weakreflist;      /* List of weak references to self */
     706                 :            :     /* A {localdummy weakref -> localdict} dict */
     707                 :            :     PyObject *dummies;
     708                 :            :     /* The callback for weakrefs to localdummies */
     709                 :            :     PyObject *wr_callback;
     710                 :            : } localobject;
     711                 :            : 
     712                 :            : /* Forward declaration */
     713                 :            : static PyObject *_ldict(localobject *self, thread_module_state *state);
     714                 :            : static PyObject *_localdummy_destroyed(PyObject *meth_self, PyObject *dummyweakref);
     715                 :            : 
     716                 :            : /* Create and register the dummy for the current thread.
     717                 :            :    Returns a borrowed reference of the corresponding local dict */
     718                 :            : static PyObject *
     719                 :          1 : _local_create_dummy(localobject *self, thread_module_state *state)
     720                 :            : {
     721                 :          1 :     PyObject *ldict = NULL, *wr = NULL;
     722                 :          1 :     localdummyobject *dummy = NULL;
     723                 :          1 :     PyTypeObject *type = state->local_dummy_type;
     724                 :            : 
     725                 :          1 :     PyObject *tdict = PyThreadState_GetDict();
     726         [ -  + ]:          1 :     if (tdict == NULL) {
     727                 :          0 :         PyErr_SetString(PyExc_SystemError,
     728                 :            :                         "Couldn't get thread-state dictionary");
     729                 :          0 :         goto err;
     730                 :            :     }
     731                 :            : 
     732                 :          1 :     ldict = PyDict_New();
     733         [ -  + ]:          1 :     if (ldict == NULL) {
     734                 :          0 :         goto err;
     735                 :            :     }
     736                 :          1 :     dummy = (localdummyobject *) type->tp_alloc(type, 0);
     737         [ -  + ]:          1 :     if (dummy == NULL) {
     738                 :          0 :         goto err;
     739                 :            :     }
     740                 :          1 :     dummy->localdict = ldict;
     741                 :          1 :     wr = PyWeakref_NewRef((PyObject *) dummy, self->wr_callback);
     742         [ -  + ]:          1 :     if (wr == NULL) {
     743                 :          0 :         goto err;
     744                 :            :     }
     745                 :            : 
     746                 :            :     /* As a side-effect, this will cache the weakref's hash before the
     747                 :            :        dummy gets deleted */
     748                 :          1 :     int r = PyDict_SetItem(self->dummies, wr, ldict);
     749         [ -  + ]:          1 :     if (r < 0) {
     750                 :          0 :         goto err;
     751                 :            :     }
     752         [ +  - ]:          1 :     Py_CLEAR(wr);
     753                 :          1 :     r = PyDict_SetItem(tdict, self->key, (PyObject *) dummy);
     754         [ -  + ]:          1 :     if (r < 0) {
     755                 :          0 :         goto err;
     756                 :            :     }
     757         [ +  - ]:          1 :     Py_CLEAR(dummy);
     758                 :            : 
     759                 :          1 :     Py_DECREF(ldict);
     760                 :          1 :     return ldict;
     761                 :            : 
     762                 :          0 : err:
     763                 :          0 :     Py_XDECREF(ldict);
     764                 :          0 :     Py_XDECREF(wr);
     765                 :          0 :     Py_XDECREF(dummy);
     766                 :          0 :     return NULL;
     767                 :            : }
     768                 :            : 
     769                 :            : static PyObject *
     770                 :          1 : local_new(PyTypeObject *type, PyObject *args, PyObject *kw)
     771                 :            : {
     772                 :            :     static PyMethodDef wr_callback_def = {
     773                 :            :         "_localdummy_destroyed", (PyCFunction) _localdummy_destroyed, METH_O
     774                 :            :     };
     775                 :            : 
     776         [ +  - ]:          1 :     if (type->tp_init == PyBaseObject_Type.tp_init) {
     777                 :          1 :         int rc = 0;
     778         [ +  - ]:          1 :         if (args != NULL)
     779                 :          1 :             rc = PyObject_IsTrue(args);
     780   [ +  -  -  + ]:          1 :         if (rc == 0 && kw != NULL)
     781                 :          0 :             rc = PyObject_IsTrue(kw);
     782         [ -  + ]:          1 :         if (rc != 0) {
     783         [ #  # ]:          0 :             if (rc > 0) {
     784                 :          0 :                 PyErr_SetString(PyExc_TypeError,
     785                 :            :                           "Initialization arguments are not supported");
     786                 :            :             }
     787                 :          0 :             return NULL;
     788                 :            :         }
     789                 :            :     }
     790                 :            : 
     791                 :          1 :     PyObject *module = PyType_GetModuleByDef(type, &thread_module);
     792                 :          1 :     thread_module_state *state = get_thread_state(module);
     793                 :            : 
     794                 :          1 :     localobject *self = (localobject *)type->tp_alloc(type, 0);
     795         [ -  + ]:          1 :     if (self == NULL) {
     796                 :          0 :         return NULL;
     797                 :            :     }
     798                 :            : 
     799                 :          1 :     self->args = Py_XNewRef(args);
     800                 :          1 :     self->kw = Py_XNewRef(kw);
     801                 :          1 :     self->key = PyUnicode_FromFormat("thread.local.%p", self);
     802         [ -  + ]:          1 :     if (self->key == NULL) {
     803                 :          0 :         goto err;
     804                 :            :     }
     805                 :            : 
     806                 :          1 :     self->dummies = PyDict_New();
     807         [ -  + ]:          1 :     if (self->dummies == NULL) {
     808                 :          0 :         goto err;
     809                 :            :     }
     810                 :            : 
     811                 :            :     /* We use a weak reference to self in the callback closure
     812                 :            :        in order to avoid spurious reference cycles */
     813                 :          1 :     PyObject *wr = PyWeakref_NewRef((PyObject *) self, NULL);
     814         [ -  + ]:          1 :     if (wr == NULL) {
     815                 :          0 :         goto err;
     816                 :            :     }
     817                 :          1 :     self->wr_callback = PyCFunction_NewEx(&wr_callback_def, wr, NULL);
     818                 :          1 :     Py_DECREF(wr);
     819         [ -  + ]:          1 :     if (self->wr_callback == NULL) {
     820                 :          0 :         goto err;
     821                 :            :     }
     822         [ -  + ]:          1 :     if (_local_create_dummy(self, state) == NULL) {
     823                 :          0 :         goto err;
     824                 :            :     }
     825                 :          1 :     return (PyObject *)self;
     826                 :            : 
     827                 :          0 :   err:
     828                 :          0 :     Py_DECREF(self);
     829                 :          0 :     return NULL;
     830                 :            : }
     831                 :            : 
     832                 :            : static int
     833                 :          8 : local_traverse(localobject *self, visitproc visit, void *arg)
     834                 :            : {
     835   [ +  -  -  + ]:          8 :     Py_VISIT(Py_TYPE(self));
     836   [ +  -  -  + ]:          8 :     Py_VISIT(self->args);
     837   [ -  +  -  - ]:          8 :     Py_VISIT(self->kw);
     838   [ +  -  -  + ]:          8 :     Py_VISIT(self->dummies);
     839                 :          8 :     return 0;
     840                 :            : }
     841                 :            : 
     842                 :            : static int
     843                 :          1 : local_clear(localobject *self)
     844                 :            : {
     845         [ +  - ]:          1 :     Py_CLEAR(self->args);
     846         [ -  + ]:          1 :     Py_CLEAR(self->kw);
     847         [ +  - ]:          1 :     Py_CLEAR(self->dummies);
     848         [ +  - ]:          1 :     Py_CLEAR(self->wr_callback);
     849                 :            :     /* Remove all strong references to dummies from the thread states */
     850         [ +  - ]:          1 :     if (self->key) {
     851                 :          1 :         PyInterpreterState *interp = _PyInterpreterState_GET();
     852                 :          1 :         _PyRuntimeState *runtime = &_PyRuntime;
     853                 :          1 :         HEAD_LOCK(runtime);
     854                 :          1 :         PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
     855                 :          1 :         HEAD_UNLOCK(runtime);
     856         [ +  + ]:          2 :         while (tstate) {
     857         [ +  - ]:          1 :             if (tstate->dict) {
     858                 :          1 :                 PyObject *v = _PyDict_Pop(tstate->dict, self->key, Py_None);
     859         [ +  - ]:          1 :                 if (v != NULL) {
     860                 :          1 :                     Py_DECREF(v);
     861                 :            :                 }
     862                 :            :                 else {
     863                 :          0 :                     PyErr_Clear();
     864                 :            :                 }
     865                 :            :             }
     866                 :          1 :             HEAD_LOCK(runtime);
     867                 :          1 :             tstate = PyThreadState_Next(tstate);
     868                 :          1 :             HEAD_UNLOCK(runtime);
     869                 :            :         }
     870                 :            :     }
     871                 :          1 :     return 0;
     872                 :            : }
     873                 :            : 
     874                 :            : static void
     875                 :          1 : local_dealloc(localobject *self)
     876                 :            : {
     877                 :            :     /* Weakrefs must be invalidated right now, otherwise they can be used
     878                 :            :        from code called below, which is very dangerous since Py_REFCNT(self) == 0 */
     879         [ +  - ]:          1 :     if (self->weakreflist != NULL) {
     880                 :          1 :         PyObject_ClearWeakRefs((PyObject *) self);
     881                 :            :     }
     882                 :            : 
     883                 :          1 :     PyObject_GC_UnTrack(self);
     884                 :            : 
     885                 :          1 :     local_clear(self);
     886                 :          1 :     Py_XDECREF(self->key);
     887                 :            : 
     888                 :          1 :     PyTypeObject *tp = Py_TYPE(self);
     889                 :          1 :     tp->tp_free((PyObject*)self);
     890                 :          1 :     Py_DECREF(tp);
     891                 :          1 : }
     892                 :            : 
     893                 :            : /* Returns a borrowed reference to the local dict, creating it if necessary */
     894                 :            : static PyObject *
     895                 :          0 : _ldict(localobject *self, thread_module_state *state)
     896                 :            : {
     897                 :          0 :     PyObject *tdict = PyThreadState_GetDict();
     898         [ #  # ]:          0 :     if (tdict == NULL) {
     899                 :          0 :         PyErr_SetString(PyExc_SystemError,
     900                 :            :                         "Couldn't get thread-state dictionary");
     901                 :          0 :         return NULL;
     902                 :            :     }
     903                 :            : 
     904                 :            :     PyObject *ldict;
     905                 :          0 :     PyObject *dummy = PyDict_GetItemWithError(tdict, self->key);
     906         [ #  # ]:          0 :     if (dummy == NULL) {
     907         [ #  # ]:          0 :         if (PyErr_Occurred()) {
     908                 :          0 :             return NULL;
     909                 :            :         }
     910                 :          0 :         ldict = _local_create_dummy(self, state);
     911         [ #  # ]:          0 :         if (ldict == NULL)
     912                 :          0 :             return NULL;
     913                 :            : 
     914   [ #  #  #  # ]:          0 :         if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init &&
     915                 :          0 :             Py_TYPE(self)->tp_init((PyObject*)self,
     916                 :            :                                    self->args, self->kw) < 0) {
     917                 :            :             /* we need to get rid of ldict from thread so
     918                 :            :                we create a new one the next time we do an attr
     919                 :            :                access */
     920                 :          0 :             PyDict_DelItem(tdict, self->key);
     921                 :          0 :             return NULL;
     922                 :            :         }
     923                 :            :     }
     924                 :            :     else {
     925                 :            :         assert(Py_IS_TYPE(dummy, state->local_dummy_type));
     926                 :          0 :         ldict = ((localdummyobject *) dummy)->localdict;
     927                 :            :     }
     928                 :            : 
     929                 :          0 :     return ldict;
     930                 :            : }
     931                 :            : 
     932                 :            : static int
     933                 :          0 : local_setattro(localobject *self, PyObject *name, PyObject *v)
     934                 :            : {
     935                 :          0 :     PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
     936                 :          0 :     thread_module_state *state = get_thread_state(module);
     937                 :            : 
     938                 :          0 :     PyObject *ldict = _ldict(self, state);
     939         [ #  # ]:          0 :     if (ldict == NULL) {
     940                 :          0 :         return -1;
     941                 :            :     }
     942                 :            : 
     943                 :          0 :     int r = PyObject_RichCompareBool(name, &_Py_ID(__dict__), Py_EQ);
     944         [ #  # ]:          0 :     if (r == -1) {
     945                 :          0 :         return -1;
     946                 :            :     }
     947         [ #  # ]:          0 :     if (r == 1) {
     948                 :          0 :         PyErr_Format(PyExc_AttributeError,
     949                 :            :                      "'%.50s' object attribute '%U' is read-only",
     950                 :          0 :                      Py_TYPE(self)->tp_name, name);
     951                 :          0 :         return -1;
     952                 :            :     }
     953                 :            : 
     954                 :          0 :     return _PyObject_GenericSetAttrWithDict((PyObject *)self, name, v, ldict);
     955                 :            : }
     956                 :            : 
     957                 :            : static PyObject *local_getattro(localobject *, PyObject *);
     958                 :            : 
     959                 :            : static PyMemberDef local_type_members[] = {
     960                 :            :     {"__weaklistoffset__", T_PYSSIZET, offsetof(localobject, weakreflist), READONLY},
     961                 :            :     {NULL},
     962                 :            : };
     963                 :            : 
     964                 :            : static PyType_Slot local_type_slots[] = {
     965                 :            :     {Py_tp_dealloc, (destructor)local_dealloc},
     966                 :            :     {Py_tp_getattro, (getattrofunc)local_getattro},
     967                 :            :     {Py_tp_setattro, (setattrofunc)local_setattro},
     968                 :            :     {Py_tp_doc, "Thread-local data"},
     969                 :            :     {Py_tp_traverse, (traverseproc)local_traverse},
     970                 :            :     {Py_tp_clear, (inquiry)local_clear},
     971                 :            :     {Py_tp_new, local_new},
     972                 :            :     {Py_tp_members, local_type_members},
     973                 :            :     {0, 0}
     974                 :            : };
     975                 :            : 
     976                 :            : static PyType_Spec local_type_spec = {
     977                 :            :     .name = "_thread._local",
     978                 :            :     .basicsize = sizeof(localobject),
     979                 :            :     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
     980                 :            :               Py_TPFLAGS_IMMUTABLETYPE),
     981                 :            :     .slots = local_type_slots,
     982                 :            : };
     983                 :            : 
     984                 :            : static PyObject *
     985                 :          0 : local_getattro(localobject *self, PyObject *name)
     986                 :            : {
     987                 :          0 :     PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
     988                 :          0 :     thread_module_state *state = get_thread_state(module);
     989                 :            : 
     990                 :          0 :     PyObject *ldict = _ldict(self, state);
     991         [ #  # ]:          0 :     if (ldict == NULL)
     992                 :          0 :         return NULL;
     993                 :            : 
     994                 :          0 :     int r = PyObject_RichCompareBool(name, &_Py_ID(__dict__), Py_EQ);
     995         [ #  # ]:          0 :     if (r == 1) {
     996                 :          0 :         return Py_NewRef(ldict);
     997                 :            :     }
     998         [ #  # ]:          0 :     if (r == -1) {
     999                 :          0 :         return NULL;
    1000                 :            :     }
    1001                 :            : 
    1002         [ #  # ]:          0 :     if (!Py_IS_TYPE(self, state->local_type)) {
    1003                 :            :         /* use generic lookup for subtypes */
    1004                 :          0 :         return _PyObject_GenericGetAttrWithDict((PyObject *)self, name,
    1005                 :            :                                                 ldict, 0);
    1006                 :            :     }
    1007                 :            : 
    1008                 :            :     /* Optimization: just look in dict ourselves */
    1009                 :          0 :     PyObject *value = PyDict_GetItemWithError(ldict, name);
    1010         [ #  # ]:          0 :     if (value != NULL) {
    1011                 :          0 :         return Py_NewRef(value);
    1012                 :            :     }
    1013         [ #  # ]:          0 :     if (PyErr_Occurred()) {
    1014                 :          0 :         return NULL;
    1015                 :            :     }
    1016                 :            : 
    1017                 :            :     /* Fall back on generic to get __class__ and __dict__ */
    1018                 :          0 :     return _PyObject_GenericGetAttrWithDict(
    1019                 :            :         (PyObject *)self, name, ldict, 0);
    1020                 :            : }
    1021                 :            : 
    1022                 :            : /* Called when a dummy is destroyed. */
    1023                 :            : static PyObject *
    1024                 :          0 : _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref)
    1025                 :            : {
    1026                 :            :     assert(PyWeakref_CheckRef(localweakref));
    1027                 :          0 :     PyObject *obj = PyWeakref_GET_OBJECT(localweakref);
    1028         [ #  # ]:          0 :     if (obj == Py_None) {
    1029                 :          0 :         Py_RETURN_NONE;
    1030                 :            :     }
    1031                 :            : 
    1032                 :            :     /* If the thread-local object is still alive and not being cleared,
    1033                 :            :        remove the corresponding local dict */
    1034                 :          0 :     localobject *self = (localobject *)Py_NewRef(obj);
    1035         [ #  # ]:          0 :     if (self->dummies != NULL) {
    1036                 :            :         PyObject *ldict;
    1037                 :          0 :         ldict = PyDict_GetItemWithError(self->dummies, dummyweakref);
    1038         [ #  # ]:          0 :         if (ldict != NULL) {
    1039                 :          0 :             PyDict_DelItem(self->dummies, dummyweakref);
    1040                 :            :         }
    1041         [ #  # ]:          0 :         if (PyErr_Occurred())
    1042                 :          0 :             PyErr_WriteUnraisable(obj);
    1043                 :            :     }
    1044                 :          0 :     Py_DECREF(obj);
    1045                 :          0 :     Py_RETURN_NONE;
    1046                 :            : }
    1047                 :            : 
    1048                 :            : /* Module functions */
    1049                 :            : 
    1050                 :            : struct bootstate {
    1051                 :            :     PyInterpreterState *interp;
    1052                 :            :     PyObject *func;
    1053                 :            :     PyObject *args;
    1054                 :            :     PyObject *kwargs;
    1055                 :            :     PyThreadState *tstate;
    1056                 :            :     _PyRuntimeState *runtime;
    1057                 :            : };
    1058                 :            : 
    1059                 :            : 
    1060                 :            : static void
    1061                 :          0 : thread_bootstate_free(struct bootstate *boot)
    1062                 :            : {
    1063                 :          0 :     Py_DECREF(boot->func);
    1064                 :          0 :     Py_DECREF(boot->args);
    1065                 :          0 :     Py_XDECREF(boot->kwargs);
    1066                 :          0 :     PyMem_Free(boot);
    1067                 :          0 : }
    1068                 :            : 
    1069                 :            : 
    1070                 :            : static void
    1071                 :          0 : thread_run(void *boot_raw)
    1072                 :            : {
    1073                 :          0 :     struct bootstate *boot = (struct bootstate *) boot_raw;
    1074                 :            :     PyThreadState *tstate;
    1075                 :            : 
    1076                 :          0 :     tstate = boot->tstate;
    1077                 :          0 :     _PyThreadState_Bind(tstate);
    1078                 :          0 :     PyEval_AcquireThread(tstate);
    1079                 :          0 :     tstate->interp->threads.count++;
    1080                 :            : 
    1081                 :          0 :     PyObject *res = PyObject_Call(boot->func, boot->args, boot->kwargs);
    1082         [ #  # ]:          0 :     if (res == NULL) {
    1083         [ #  # ]:          0 :         if (PyErr_ExceptionMatches(PyExc_SystemExit))
    1084                 :            :             /* SystemExit is ignored silently */
    1085                 :          0 :             PyErr_Clear();
    1086                 :            :         else {
    1087                 :          0 :             _PyErr_WriteUnraisableMsg("in thread started by", boot->func);
    1088                 :            :         }
    1089                 :            :     }
    1090                 :            :     else {
    1091                 :          0 :         Py_DECREF(res);
    1092                 :            :     }
    1093                 :            : 
    1094                 :          0 :     thread_bootstate_free(boot);
    1095                 :          0 :     tstate->interp->threads.count--;
    1096                 :          0 :     PyThreadState_Clear(tstate);
    1097                 :          0 :     _PyThreadState_DeleteCurrent(tstate);
    1098                 :            : 
    1099                 :            :     // bpo-44434: Don't call explicitly PyThread_exit_thread(). On Linux with
    1100                 :            :     // the glibc, pthread_exit() can abort the whole process if dlopen() fails
    1101                 :            :     // to open the libgcc_s.so library (ex: EMFILE error).
    1102                 :          0 : }
    1103                 :            : 
    1104                 :            : static PyObject *
    1105                 :          0 : thread_daemon_threads_allowed(PyObject *module, PyObject *Py_UNUSED(ignored))
    1106                 :            : {
    1107                 :          0 :     PyInterpreterState *interp = _PyInterpreterState_Get();
    1108         [ #  # ]:          0 :     if (interp->feature_flags & Py_RTFLAGS_DAEMON_THREADS) {
    1109                 :          0 :         Py_RETURN_TRUE;
    1110                 :            :     }
    1111                 :            :     else {
    1112                 :          0 :         Py_RETURN_FALSE;
    1113                 :            :     }
    1114                 :            : }
    1115                 :            : 
    1116                 :            : PyDoc_STRVAR(daemon_threads_allowed_doc,
    1117                 :            : "daemon_threads_allowed()\n\
    1118                 :            : \n\
    1119                 :            : Return True if daemon threads are allowed in the current interpreter,\n\
    1120                 :            : and False otherwise.\n");
    1121                 :            : 
    1122                 :            : static PyObject *
    1123                 :          0 : thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
    1124                 :            : {
    1125                 :          0 :     _PyRuntimeState *runtime = &_PyRuntime;
    1126                 :          0 :     PyObject *func, *args, *kwargs = NULL;
    1127                 :            : 
    1128         [ #  # ]:          0 :     if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
    1129                 :            :                            &func, &args, &kwargs))
    1130                 :          0 :         return NULL;
    1131         [ #  # ]:          0 :     if (!PyCallable_Check(func)) {
    1132                 :          0 :         PyErr_SetString(PyExc_TypeError,
    1133                 :            :                         "first arg must be callable");
    1134                 :          0 :         return NULL;
    1135                 :            :     }
    1136         [ #  # ]:          0 :     if (!PyTuple_Check(args)) {
    1137                 :          0 :         PyErr_SetString(PyExc_TypeError,
    1138                 :            :                         "2nd arg must be a tuple");
    1139                 :          0 :         return NULL;
    1140                 :            :     }
    1141   [ #  #  #  # ]:          0 :     if (kwargs != NULL && !PyDict_Check(kwargs)) {
    1142                 :          0 :         PyErr_SetString(PyExc_TypeError,
    1143                 :            :                         "optional 3rd arg must be a dictionary");
    1144                 :          0 :         return NULL;
    1145                 :            :     }
    1146                 :            : 
    1147         [ #  # ]:          0 :     if (PySys_Audit("_thread.start_new_thread", "OOO",
    1148         [ #  # ]:          0 :                     func, args, kwargs ? kwargs : Py_None) < 0) {
    1149                 :          0 :         return NULL;
    1150                 :            :     }
    1151                 :            : 
    1152                 :          0 :     PyInterpreterState *interp = _PyInterpreterState_GET();
    1153         [ #  # ]:          0 :     if (!_PyInterpreterState_HasFeature(interp, Py_RTFLAGS_THREADS)) {
    1154                 :          0 :         PyErr_SetString(PyExc_RuntimeError,
    1155                 :            :                         "thread is not supported for isolated subinterpreters");
    1156                 :          0 :         return NULL;
    1157                 :            :     }
    1158                 :            : 
    1159                 :          0 :     struct bootstate *boot = PyMem_NEW(struct bootstate, 1);
    1160         [ #  # ]:          0 :     if (boot == NULL) {
    1161                 :          0 :         return PyErr_NoMemory();
    1162                 :            :     }
    1163                 :          0 :     boot->interp = _PyInterpreterState_GET();
    1164                 :          0 :     boot->tstate = _PyThreadState_New(boot->interp);
    1165         [ #  # ]:          0 :     if (boot->tstate == NULL) {
    1166                 :          0 :         PyMem_Free(boot);
    1167         [ #  # ]:          0 :         if (!PyErr_Occurred()) {
    1168                 :          0 :             return PyErr_NoMemory();
    1169                 :            :         }
    1170                 :          0 :         return NULL;
    1171                 :            :     }
    1172                 :          0 :     boot->runtime = runtime;
    1173                 :          0 :     boot->func = Py_NewRef(func);
    1174                 :          0 :     boot->args = Py_NewRef(args);
    1175                 :          0 :     boot->kwargs = Py_XNewRef(kwargs);
    1176                 :            : 
    1177                 :          0 :     unsigned long ident = PyThread_start_new_thread(thread_run, (void*) boot);
    1178         [ #  # ]:          0 :     if (ident == PYTHREAD_INVALID_THREAD_ID) {
    1179                 :          0 :         PyErr_SetString(ThreadError, "can't start new thread");
    1180                 :          0 :         PyThreadState_Clear(boot->tstate);
    1181                 :          0 :         thread_bootstate_free(boot);
    1182                 :          0 :         return NULL;
    1183                 :            :     }
    1184                 :          0 :     return PyLong_FromUnsignedLong(ident);
    1185                 :            : }
    1186                 :            : 
    1187                 :            : PyDoc_STRVAR(start_new_doc,
    1188                 :            : "start_new_thread(function, args[, kwargs])\n\
    1189                 :            : (start_new() is an obsolete synonym)\n\
    1190                 :            : \n\
    1191                 :            : Start a new thread and return its identifier.  The thread will call the\n\
    1192                 :            : function with positional arguments from the tuple args and keyword arguments\n\
    1193                 :            : taken from the optional dictionary kwargs.  The thread exits when the\n\
    1194                 :            : function returns; the return value is ignored.  The thread will also exit\n\
    1195                 :            : when the function raises an unhandled exception; a stack trace will be\n\
    1196                 :            : printed unless the exception is SystemExit.\n");
    1197                 :            : 
    1198                 :            : static PyObject *
    1199                 :          0 : thread_PyThread_exit_thread(PyObject *self, PyObject *Py_UNUSED(ignored))
    1200                 :            : {
    1201                 :          0 :     PyErr_SetNone(PyExc_SystemExit);
    1202                 :          0 :     return NULL;
    1203                 :            : }
    1204                 :            : 
    1205                 :            : PyDoc_STRVAR(exit_doc,
    1206                 :            : "exit()\n\
    1207                 :            : (exit_thread() is an obsolete synonym)\n\
    1208                 :            : \n\
    1209                 :            : This is synonymous to ``raise SystemExit''.  It will cause the current\n\
    1210                 :            : thread to exit silently unless the exception is caught.");
    1211                 :            : 
    1212                 :            : static PyObject *
    1213                 :          0 : thread_PyThread_interrupt_main(PyObject *self, PyObject *args)
    1214                 :            : {
    1215                 :          0 :     int signum = SIGINT;
    1216         [ #  # ]:          0 :     if (!PyArg_ParseTuple(args, "|i:signum", &signum)) {
    1217                 :          0 :         return NULL;
    1218                 :            :     }
    1219                 :            : 
    1220         [ #  # ]:          0 :     if (PyErr_SetInterruptEx(signum)) {
    1221                 :          0 :         PyErr_SetString(PyExc_ValueError, "signal number out of range");
    1222                 :          0 :         return NULL;
    1223                 :            :     }
    1224                 :          0 :     Py_RETURN_NONE;
    1225                 :            : }
    1226                 :            : 
    1227                 :            : PyDoc_STRVAR(interrupt_doc,
    1228                 :            : "interrupt_main(signum=signal.SIGINT, /)\n\
    1229                 :            : \n\
    1230                 :            : Simulate the arrival of the given signal in the main thread,\n\
    1231                 :            : where the corresponding signal handler will be executed.\n\
    1232                 :            : If *signum* is omitted, SIGINT is assumed.\n\
    1233                 :            : A subthread can use this function to interrupt the main thread.\n\
    1234                 :            : \n\
    1235                 :            : Note: the default signal handler for SIGINT raises ``KeyboardInterrupt``."
    1236                 :            : );
    1237                 :            : 
    1238                 :            : static lockobject *newlockobject(PyObject *module);
    1239                 :            : 
    1240                 :            : static PyObject *
    1241                 :       1057 : thread_PyThread_allocate_lock(PyObject *module, PyObject *Py_UNUSED(ignored))
    1242                 :            : {
    1243                 :       1057 :     return (PyObject *) newlockobject(module);
    1244                 :            : }
    1245                 :            : 
    1246                 :            : PyDoc_STRVAR(allocate_doc,
    1247                 :            : "allocate_lock() -> lock object\n\
    1248                 :            : (allocate() is an obsolete synonym)\n\
    1249                 :            : \n\
    1250                 :            : Create a new lock object. See help(type(threading.Lock())) for\n\
    1251                 :            : information about locks.");
    1252                 :            : 
    1253                 :            : static PyObject *
    1254                 :       2572 : thread_get_ident(PyObject *self, PyObject *Py_UNUSED(ignored))
    1255                 :            : {
    1256                 :       2572 :     unsigned long ident = PyThread_get_thread_ident();
    1257         [ -  + ]:       2572 :     if (ident == PYTHREAD_INVALID_THREAD_ID) {
    1258                 :          0 :         PyErr_SetString(ThreadError, "no current thread ident");
    1259                 :          0 :         return NULL;
    1260                 :            :     }
    1261                 :       2572 :     return PyLong_FromUnsignedLong(ident);
    1262                 :            : }
    1263                 :            : 
    1264                 :            : PyDoc_STRVAR(get_ident_doc,
    1265                 :            : "get_ident() -> integer\n\
    1266                 :            : \n\
    1267                 :            : Return a non-zero integer that uniquely identifies the current thread\n\
    1268                 :            : amongst other threads that exist simultaneously.\n\
    1269                 :            : This may be used to identify per-thread resources.\n\
    1270                 :            : Even though on some platforms threads identities may appear to be\n\
    1271                 :            : allocated consecutive numbers starting at 1, this behavior should not\n\
    1272                 :            : be relied upon, and the number should be seen purely as a magic cookie.\n\
    1273                 :            : A thread's identity may be reused for another thread after it exits.");
    1274                 :            : 
    1275                 :            : #ifdef PY_HAVE_THREAD_NATIVE_ID
    1276                 :            : static PyObject *
    1277                 :          4 : thread_get_native_id(PyObject *self, PyObject *Py_UNUSED(ignored))
    1278                 :            : {
    1279                 :          4 :     unsigned long native_id = PyThread_get_thread_native_id();
    1280                 :          4 :     return PyLong_FromUnsignedLong(native_id);
    1281                 :            : }
    1282                 :            : 
    1283                 :            : PyDoc_STRVAR(get_native_id_doc,
    1284                 :            : "get_native_id() -> integer\n\
    1285                 :            : \n\
    1286                 :            : Return a non-negative integer identifying the thread as reported\n\
    1287                 :            : by the OS (kernel). This may be used to uniquely identify a\n\
    1288                 :            : particular thread within a system.");
    1289                 :            : #endif
    1290                 :            : 
    1291                 :            : static PyObject *
    1292                 :          0 : thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
    1293                 :            : {
    1294                 :          0 :     PyInterpreterState *interp = _PyInterpreterState_GET();
    1295                 :          0 :     return PyLong_FromLong(interp->threads.count);
    1296                 :            : }
    1297                 :            : 
    1298                 :            : PyDoc_STRVAR(_count_doc,
    1299                 :            : "_count() -> integer\n\
    1300                 :            : \n\
    1301                 :            : \
    1302                 :            : Return the number of currently running Python threads, excluding\n\
    1303                 :            : the main thread. The returned number comprises all threads created\n\
    1304                 :            : through `start_new_thread()` as well as `threading.Thread`, and not\n\
    1305                 :            : yet finished.\n\
    1306                 :            : \n\
    1307                 :            : This function is meant for internal and specialized purposes only.\n\
    1308                 :            : In most applications `threading.enumerate()` should be used instead.");
    1309                 :            : 
    1310                 :            : static void
    1311                 :          4 : release_sentinel(void *wr_raw)
    1312                 :            : {
    1313                 :          4 :     PyObject *wr = _PyObject_CAST(wr_raw);
    1314                 :            :     /* Tricky: this function is called when the current thread state
    1315                 :            :        is being deleted.  Therefore, only simple C code can safely
    1316                 :            :        execute here. */
    1317                 :          4 :     PyObject *obj = PyWeakref_GET_OBJECT(wr);
    1318                 :            :     lockobject *lock;
    1319         [ -  + ]:          4 :     if (obj != Py_None) {
    1320                 :          0 :         lock = (lockobject *) obj;
    1321         [ #  # ]:          0 :         if (lock->locked) {
    1322                 :          0 :             PyThread_release_lock(lock->lock_lock);
    1323                 :          0 :             lock->locked = 0;
    1324                 :            :         }
    1325                 :            :     }
    1326                 :            :     /* Deallocating a weakref with a NULL callback only calls
    1327                 :            :        PyObject_GC_Del(), which can't call any Python code. */
    1328                 :          4 :     Py_DECREF(wr);
    1329                 :          4 : }
    1330                 :            : 
    1331                 :            : static PyObject *
    1332                 :          4 : thread__set_sentinel(PyObject *module, PyObject *Py_UNUSED(ignored))
    1333                 :            : {
    1334                 :            :     PyObject *wr;
    1335                 :          4 :     PyThreadState *tstate = _PyThreadState_GET();
    1336                 :            :     lockobject *lock;
    1337                 :            : 
    1338         [ -  + ]:          4 :     if (tstate->on_delete_data != NULL) {
    1339                 :            :         /* We must support the re-creation of the lock from a
    1340                 :            :            fork()ed child. */
    1341                 :            :         assert(tstate->on_delete == &release_sentinel);
    1342                 :          0 :         wr = (PyObject *) tstate->on_delete_data;
    1343                 :          0 :         tstate->on_delete = NULL;
    1344                 :          0 :         tstate->on_delete_data = NULL;
    1345                 :          0 :         Py_DECREF(wr);
    1346                 :            :     }
    1347                 :          4 :     lock = newlockobject(module);
    1348         [ -  + ]:          4 :     if (lock == NULL)
    1349                 :          0 :         return NULL;
    1350                 :            :     /* The lock is owned by whoever called _set_sentinel(), but the weakref
    1351                 :            :        hangs to the thread state. */
    1352                 :          4 :     wr = PyWeakref_NewRef((PyObject *) lock, NULL);
    1353         [ -  + ]:          4 :     if (wr == NULL) {
    1354                 :          0 :         Py_DECREF(lock);
    1355                 :          0 :         return NULL;
    1356                 :            :     }
    1357                 :          4 :     tstate->on_delete_data = (void *) wr;
    1358                 :          4 :     tstate->on_delete = &release_sentinel;
    1359                 :          4 :     return (PyObject *) lock;
    1360                 :            : }
    1361                 :            : 
    1362                 :            : PyDoc_STRVAR(_set_sentinel_doc,
    1363                 :            : "_set_sentinel() -> lock\n\
    1364                 :            : \n\
    1365                 :            : Set a sentinel lock that will be released when the current thread\n\
    1366                 :            : state is finalized (after it is untied from the interpreter).\n\
    1367                 :            : \n\
    1368                 :            : This is a private API for the threading module.");
    1369                 :            : 
    1370                 :            : static PyObject *
    1371                 :          0 : thread_stack_size(PyObject *self, PyObject *args)
    1372                 :            : {
    1373                 :            :     size_t old_size;
    1374                 :          0 :     Py_ssize_t new_size = 0;
    1375                 :            :     int rc;
    1376                 :            : 
    1377         [ #  # ]:          0 :     if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size))
    1378                 :          0 :         return NULL;
    1379                 :            : 
    1380         [ #  # ]:          0 :     if (new_size < 0) {
    1381                 :          0 :         PyErr_SetString(PyExc_ValueError,
    1382                 :            :                         "size must be 0 or a positive value");
    1383                 :          0 :         return NULL;
    1384                 :            :     }
    1385                 :            : 
    1386                 :          0 :     old_size = PyThread_get_stacksize();
    1387                 :            : 
    1388                 :          0 :     rc = PyThread_set_stacksize((size_t) new_size);
    1389         [ #  # ]:          0 :     if (rc == -1) {
    1390                 :          0 :         PyErr_Format(PyExc_ValueError,
    1391                 :            :                      "size not valid: %zd bytes",
    1392                 :            :                      new_size);
    1393                 :          0 :         return NULL;
    1394                 :            :     }
    1395         [ #  # ]:          0 :     if (rc == -2) {
    1396                 :          0 :         PyErr_SetString(ThreadError,
    1397                 :            :                         "setting stack size not supported");
    1398                 :          0 :         return NULL;
    1399                 :            :     }
    1400                 :            : 
    1401                 :          0 :     return PyLong_FromSsize_t((Py_ssize_t) old_size);
    1402                 :            : }
    1403                 :            : 
    1404                 :            : PyDoc_STRVAR(stack_size_doc,
    1405                 :            : "stack_size([size]) -> size\n\
    1406                 :            : \n\
    1407                 :            : Return the thread stack size used when creating new threads.  The\n\
    1408                 :            : optional size argument specifies the stack size (in bytes) to be used\n\
    1409                 :            : for subsequently created threads, and must be 0 (use platform or\n\
    1410                 :            : configured default) or a positive integer value of at least 32,768 (32k).\n\
    1411                 :            : If changing the thread stack size is unsupported, a ThreadError\n\
    1412                 :            : exception is raised.  If the specified size is invalid, a ValueError\n\
    1413                 :            : exception is raised, and the stack size is unmodified.  32k bytes\n\
    1414                 :            :  currently the minimum supported stack size value to guarantee\n\
    1415                 :            : sufficient stack space for the interpreter itself.\n\
    1416                 :            : \n\
    1417                 :            : Note that some platforms may have particular restrictions on values for\n\
    1418                 :            : the stack size, such as requiring a minimum stack size larger than 32 KiB or\n\
    1419                 :            : requiring allocation in multiples of the system memory page size\n\
    1420                 :            : - platform documentation should be referred to for more information\n\
    1421                 :            : (4 KiB pages are common; using multiples of 4096 for the stack size is\n\
    1422                 :            : the suggested approach in the absence of more specific information).");
    1423                 :            : 
    1424                 :            : static int
    1425                 :          0 : thread_excepthook_file(PyObject *file, PyObject *exc_type, PyObject *exc_value,
    1426                 :            :                        PyObject *exc_traceback, PyObject *thread)
    1427                 :            : {
    1428                 :            :     /* print(f"Exception in thread {thread.name}:", file=file) */
    1429         [ #  # ]:          0 :     if (PyFile_WriteString("Exception in thread ", file) < 0) {
    1430                 :          0 :         return -1;
    1431                 :            :     }
    1432                 :            : 
    1433                 :          0 :     PyObject *name = NULL;
    1434         [ #  # ]:          0 :     if (thread != Py_None) {
    1435         [ #  # ]:          0 :         if (_PyObject_LookupAttr(thread, &_Py_ID(name), &name) < 0) {
    1436                 :          0 :             return -1;
    1437                 :            :         }
    1438                 :            :     }
    1439         [ #  # ]:          0 :     if (name != NULL) {
    1440         [ #  # ]:          0 :         if (PyFile_WriteObject(name, file, Py_PRINT_RAW) < 0) {
    1441                 :          0 :             Py_DECREF(name);
    1442                 :          0 :             return -1;
    1443                 :            :         }
    1444                 :          0 :         Py_DECREF(name);
    1445                 :            :     }
    1446                 :            :     else {
    1447                 :          0 :         unsigned long ident = PyThread_get_thread_ident();
    1448                 :          0 :         PyObject *str = PyUnicode_FromFormat("%lu", ident);
    1449         [ #  # ]:          0 :         if (str != NULL) {
    1450         [ #  # ]:          0 :             if (PyFile_WriteObject(str, file, Py_PRINT_RAW) < 0) {
    1451                 :          0 :                 Py_DECREF(str);
    1452                 :          0 :                 return -1;
    1453                 :            :             }
    1454                 :          0 :             Py_DECREF(str);
    1455                 :            :         }
    1456                 :            :         else {
    1457                 :          0 :             PyErr_Clear();
    1458                 :            : 
    1459         [ #  # ]:          0 :             if (PyFile_WriteString("<failed to get thread name>", file) < 0) {
    1460                 :          0 :                 return -1;
    1461                 :            :             }
    1462                 :            :         }
    1463                 :            :     }
    1464                 :            : 
    1465         [ #  # ]:          0 :     if (PyFile_WriteString(":\n", file) < 0) {
    1466                 :          0 :         return -1;
    1467                 :            :     }
    1468                 :            : 
    1469                 :            :     /* Display the traceback */
    1470                 :          0 :     _PyErr_Display(file, exc_type, exc_value, exc_traceback);
    1471                 :            : 
    1472                 :            :     /* Call file.flush() */
    1473                 :          0 :     PyObject *res = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
    1474         [ #  # ]:          0 :     if (!res) {
    1475                 :          0 :         return -1;
    1476                 :            :     }
    1477                 :          0 :     Py_DECREF(res);
    1478                 :            : 
    1479                 :          0 :     return 0;
    1480                 :            : }
    1481                 :            : 
    1482                 :            : 
    1483                 :            : PyDoc_STRVAR(ExceptHookArgs__doc__,
    1484                 :            : "ExceptHookArgs\n\
    1485                 :            : \n\
    1486                 :            : Type used to pass arguments to threading.excepthook.");
    1487                 :            : 
    1488                 :            : static PyStructSequence_Field ExceptHookArgs_fields[] = {
    1489                 :            :     {"exc_type", "Exception type"},
    1490                 :            :     {"exc_value", "Exception value"},
    1491                 :            :     {"exc_traceback", "Exception traceback"},
    1492                 :            :     {"thread", "Thread"},
    1493                 :            :     {0}
    1494                 :            : };
    1495                 :            : 
    1496                 :            : static PyStructSequence_Desc ExceptHookArgs_desc = {
    1497                 :            :     .name = "_thread._ExceptHookArgs",
    1498                 :            :     .doc = ExceptHookArgs__doc__,
    1499                 :            :     .fields = ExceptHookArgs_fields,
    1500                 :            :     .n_in_sequence = 4
    1501                 :            : };
    1502                 :            : 
    1503                 :            : 
    1504                 :            : static PyObject *
    1505                 :          0 : thread_excepthook(PyObject *module, PyObject *args)
    1506                 :            : {
    1507                 :          0 :     thread_module_state *state = get_thread_state(module);
    1508                 :            : 
    1509         [ #  # ]:          0 :     if (!Py_IS_TYPE(args, state->excepthook_type)) {
    1510                 :          0 :         PyErr_SetString(PyExc_TypeError,
    1511                 :            :                         "_thread.excepthook argument type "
    1512                 :            :                         "must be ExceptHookArgs");
    1513                 :          0 :         return NULL;
    1514                 :            :     }
    1515                 :            : 
    1516                 :            :     /* Borrowed reference */
    1517                 :          0 :     PyObject *exc_type = PyStructSequence_GET_ITEM(args, 0);
    1518         [ #  # ]:          0 :     if (exc_type == PyExc_SystemExit) {
    1519                 :            :         /* silently ignore SystemExit */
    1520                 :          0 :         Py_RETURN_NONE;
    1521                 :            :     }
    1522                 :            : 
    1523                 :            :     /* Borrowed references */
    1524                 :          0 :     PyObject *exc_value = PyStructSequence_GET_ITEM(args, 1);
    1525                 :          0 :     PyObject *exc_tb = PyStructSequence_GET_ITEM(args, 2);
    1526                 :          0 :     PyObject *thread = PyStructSequence_GET_ITEM(args, 3);
    1527                 :            : 
    1528                 :          0 :     PyThreadState *tstate = _PyThreadState_GET();
    1529                 :          0 :     PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr));
    1530   [ #  #  #  # ]:          0 :     if (file == NULL || file == Py_None) {
    1531         [ #  # ]:          0 :         if (thread == Py_None) {
    1532                 :            :             /* do nothing if sys.stderr is None and thread is None */
    1533                 :          0 :             Py_RETURN_NONE;
    1534                 :            :         }
    1535                 :            : 
    1536                 :          0 :         file = PyObject_GetAttrString(thread, "_stderr");
    1537         [ #  # ]:          0 :         if (file == NULL) {
    1538                 :          0 :             return NULL;
    1539                 :            :         }
    1540         [ #  # ]:          0 :         if (file == Py_None) {
    1541                 :          0 :             Py_DECREF(file);
    1542                 :            :             /* do nothing if sys.stderr is None and sys.stderr was None
    1543                 :            :                when the thread was created */
    1544                 :          0 :             Py_RETURN_NONE;
    1545                 :            :         }
    1546                 :            :     }
    1547                 :            :     else {
    1548                 :          0 :         Py_INCREF(file);
    1549                 :            :     }
    1550                 :            : 
    1551                 :          0 :     int res = thread_excepthook_file(file, exc_type, exc_value, exc_tb,
    1552                 :            :                                      thread);
    1553                 :          0 :     Py_DECREF(file);
    1554         [ #  # ]:          0 :     if (res < 0) {
    1555                 :          0 :         return NULL;
    1556                 :            :     }
    1557                 :            : 
    1558                 :          0 :     Py_RETURN_NONE;
    1559                 :            : }
    1560                 :            : 
    1561                 :            : PyDoc_STRVAR(excepthook_doc,
    1562                 :            : "excepthook(exc_type, exc_value, exc_traceback, thread)\n\
    1563                 :            : \n\
    1564                 :            : Handle uncaught Thread.run() exception.");
    1565                 :            : 
    1566                 :            : static PyMethodDef thread_methods[] = {
    1567                 :            :     {"start_new_thread",        (PyCFunction)thread_PyThread_start_new_thread,
    1568                 :            :      METH_VARARGS, start_new_doc},
    1569                 :            :     {"start_new",               (PyCFunction)thread_PyThread_start_new_thread,
    1570                 :            :      METH_VARARGS, start_new_doc},
    1571                 :            :     {"daemon_threads_allowed",  (PyCFunction)thread_daemon_threads_allowed,
    1572                 :            :      METH_NOARGS, daemon_threads_allowed_doc},
    1573                 :            :     {"allocate_lock",           thread_PyThread_allocate_lock,
    1574                 :            :      METH_NOARGS, allocate_doc},
    1575                 :            :     {"allocate",                thread_PyThread_allocate_lock,
    1576                 :            :      METH_NOARGS, allocate_doc},
    1577                 :            :     {"exit_thread",             thread_PyThread_exit_thread,
    1578                 :            :      METH_NOARGS, exit_doc},
    1579                 :            :     {"exit",                    thread_PyThread_exit_thread,
    1580                 :            :      METH_NOARGS, exit_doc},
    1581                 :            :     {"interrupt_main",          (PyCFunction)thread_PyThread_interrupt_main,
    1582                 :            :      METH_VARARGS, interrupt_doc},
    1583                 :            :     {"get_ident",               thread_get_ident,
    1584                 :            :      METH_NOARGS, get_ident_doc},
    1585                 :            : #ifdef PY_HAVE_THREAD_NATIVE_ID
    1586                 :            :     {"get_native_id",           thread_get_native_id,
    1587                 :            :      METH_NOARGS, get_native_id_doc},
    1588                 :            : #endif
    1589                 :            :     {"_count",                  thread__count,
    1590                 :            :      METH_NOARGS, _count_doc},
    1591                 :            :     {"stack_size",              (PyCFunction)thread_stack_size,
    1592                 :            :      METH_VARARGS, stack_size_doc},
    1593                 :            :     {"_set_sentinel",           thread__set_sentinel,
    1594                 :            :      METH_NOARGS, _set_sentinel_doc},
    1595                 :            :     {"_excepthook",              thread_excepthook,
    1596                 :            :      METH_O, excepthook_doc},
    1597                 :            :     {NULL,                      NULL}           /* sentinel */
    1598                 :            : };
    1599                 :            : 
    1600                 :            : 
    1601                 :            : /* Initialization function */
    1602                 :            : 
    1603                 :            : static int
    1604                 :         26 : thread_module_exec(PyObject *module)
    1605                 :            : {
    1606                 :         26 :     thread_module_state *state = get_thread_state(module);
    1607                 :         26 :     PyObject *d = PyModule_GetDict(module);
    1608                 :            : 
    1609                 :            :     // Initialize the C thread library
    1610                 :         26 :     PyThread_init_thread();
    1611                 :            : 
    1612                 :            :     // Lock
    1613                 :         26 :     state->lock_type = (PyTypeObject *)PyType_FromSpec(&lock_type_spec);
    1614         [ -  + ]:         26 :     if (state->lock_type == NULL) {
    1615                 :          0 :         return -1;
    1616                 :            :     }
    1617         [ -  + ]:         26 :     if (PyDict_SetItemString(d, "LockType", (PyObject *)state->lock_type) < 0) {
    1618                 :          0 :         return -1;
    1619                 :            :     }
    1620                 :            : 
    1621                 :            :     // RLock
    1622                 :         26 :     PyTypeObject *rlock_type = (PyTypeObject *)PyType_FromSpec(&rlock_type_spec);
    1623         [ -  + ]:         26 :     if (rlock_type == NULL) {
    1624                 :          0 :         return -1;
    1625                 :            :     }
    1626         [ -  + ]:         26 :     if (PyModule_AddType(module, rlock_type) < 0) {
    1627                 :          0 :         Py_DECREF(rlock_type);
    1628                 :          0 :         return -1;
    1629                 :            :     }
    1630                 :         26 :     Py_DECREF(rlock_type);
    1631                 :            : 
    1632                 :            :     // Local dummy
    1633                 :         26 :     state->local_dummy_type = (PyTypeObject *)PyType_FromSpec(&local_dummy_type_spec);
    1634         [ -  + ]:         26 :     if (state->local_dummy_type == NULL) {
    1635                 :          0 :         return -1;
    1636                 :            :     }
    1637                 :            : 
    1638                 :            :     // Local
    1639                 :         26 :     state->local_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &local_type_spec, NULL);
    1640         [ -  + ]:         26 :     if (state->local_type == NULL) {
    1641                 :          0 :         return -1;
    1642                 :            :     }
    1643         [ -  + ]:         26 :     if (PyModule_AddType(module, state->local_type) < 0) {
    1644                 :          0 :         return -1;
    1645                 :            :     }
    1646                 :            : 
    1647                 :            :     // Add module attributes
    1648         [ -  + ]:         26 :     if (PyDict_SetItemString(d, "error", ThreadError) < 0) {
    1649                 :          0 :         return -1;
    1650                 :            :     }
    1651                 :            : 
    1652                 :            :     // _ExceptHookArgs type
    1653                 :         26 :     state->excepthook_type = PyStructSequence_NewType(&ExceptHookArgs_desc);
    1654         [ -  + ]:         26 :     if (state->excepthook_type == NULL) {
    1655                 :          0 :         return -1;
    1656                 :            :     }
    1657         [ -  + ]:         26 :     if (PyModule_AddType(module, state->excepthook_type) < 0) {
    1658                 :          0 :         return -1;
    1659                 :            :     }
    1660                 :            : 
    1661                 :            :     // TIMEOUT_MAX
    1662                 :         26 :     double timeout_max = (double)PY_TIMEOUT_MAX * 1e-6;
    1663                 :         26 :     double time_max = _PyTime_AsSecondsDouble(_PyTime_MAX);
    1664         [ -  + ]:         26 :     timeout_max = Py_MIN(timeout_max, time_max);
    1665                 :            :     // Round towards minus infinity
    1666                 :         26 :     timeout_max = floor(timeout_max);
    1667                 :            : 
    1668         [ -  + ]:         26 :     if (PyModule_AddObject(module, "TIMEOUT_MAX",
    1669                 :            :                            PyFloat_FromDouble(timeout_max)) < 0) {
    1670                 :          0 :         return -1;
    1671                 :            :     }
    1672                 :            : 
    1673                 :         26 :     return 0;
    1674                 :            : }
    1675                 :            : 
    1676                 :            : 
    1677                 :            : static int
    1678                 :        246 : thread_module_traverse(PyObject *module, visitproc visit, void *arg)
    1679                 :            : {
    1680                 :        246 :     thread_module_state *state = get_thread_state(module);
    1681   [ +  -  -  + ]:        246 :     Py_VISIT(state->excepthook_type);
    1682   [ +  -  -  + ]:        246 :     Py_VISIT(state->lock_type);
    1683   [ +  -  -  + ]:        246 :     Py_VISIT(state->local_type);
    1684   [ +  -  -  + ]:        246 :     Py_VISIT(state->local_dummy_type);
    1685                 :        246 :     return 0;
    1686                 :            : }
    1687                 :            : 
    1688                 :            : static int
    1689                 :         49 : thread_module_clear(PyObject *module)
    1690                 :            : {
    1691                 :         49 :     thread_module_state *state = get_thread_state(module);
    1692         [ +  + ]:         49 :     Py_CLEAR(state->excepthook_type);
    1693         [ +  + ]:         49 :     Py_CLEAR(state->lock_type);
    1694         [ +  + ]:         49 :     Py_CLEAR(state->local_type);
    1695         [ +  + ]:         49 :     Py_CLEAR(state->local_dummy_type);
    1696                 :         49 :     return 0;
    1697                 :            : }
    1698                 :            : 
    1699                 :            : static void
    1700                 :         26 : thread_module_free(void *module)
    1701                 :            : {
    1702                 :         26 :     thread_module_clear((PyObject *)module);
    1703                 :         26 : }
    1704                 :            : 
    1705                 :            : 
    1706                 :            : 
    1707                 :            : PyDoc_STRVAR(thread_doc,
    1708                 :            : "This module provides primitive operations to write multi-threaded programs.\n\
    1709                 :            : The 'threading' module provides a more convenient interface.");
    1710                 :            : 
    1711                 :            : static PyModuleDef_Slot thread_module_slots[] = {
    1712                 :            :     {Py_mod_exec, thread_module_exec},
    1713                 :            :     {0, NULL}
    1714                 :            : };
    1715                 :            : 
    1716                 :            : static struct PyModuleDef thread_module = {
    1717                 :            :     PyModuleDef_HEAD_INIT,
    1718                 :            :     .m_name = "_thread",
    1719                 :            :     .m_doc = thread_doc,
    1720                 :            :     .m_size = sizeof(thread_module_state),
    1721                 :            :     .m_methods = thread_methods,
    1722                 :            :     .m_traverse = thread_module_traverse,
    1723                 :            :     .m_clear = thread_module_clear,
    1724                 :            :     .m_free = thread_module_free,
    1725                 :            :     .m_slots = thread_module_slots,
    1726                 :            : };
    1727                 :            : 
    1728                 :            : PyMODINIT_FUNC
    1729                 :         26 : PyInit__thread(void)
    1730                 :            : {
    1731                 :         26 :     return PyModuleDef_Init(&thread_module);
    1732                 :            : }

Generated by: LCOV version 1.14