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