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*
get_thread_state(PyObject * module)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
lock_traverse(lockobject * self,visitproc visit,void * arg)51 lock_traverse(lockobject *self, visitproc visit, void *arg)
52 {
53     Py_VISIT(Py_TYPE(self));
54     return 0;
55 }
56 
57 static void
lock_dealloc(lockobject * self)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
acquire_timed(PyThread_type_lock lock,_PyTime_t timeout)82 acquire_timed(PyThread_type_lock lock, _PyTime_t timeout)
83 {
84     _PyTime_t endtime = 0;
85     if (timeout > 0) {
86         endtime = _PyDeadline_Init(timeout);
87     }
88 
89     PyLockStatus r;
90     do {
91         _PyTime_t microseconds;
92         microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING);
93 
94         /* first a simple non-blocking try without releasing the GIL */
95         r = PyThread_acquire_lock_timed(lock, 0, 0);
96         if (r == PY_LOCK_FAILURE && microseconds != 0) {
97             Py_BEGIN_ALLOW_THREADS
98             r = PyThread_acquire_lock_timed(lock, microseconds, 1);
99             Py_END_ALLOW_THREADS
100         }
101 
102         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             if (Py_MakePendingCalls() < 0) {
107                 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             if (timeout > 0) {
113                 timeout = _PyDeadline_Get(endtime);
114 
115                 /* Check for negative values, since those mean block forever.
116                  */
117                 if (timeout < 0) {
118                     r = PY_LOCK_FAILURE;
119                 }
120             }
121         }
122     } while (r == PY_LOCK_INTR);  /* Retry if we were interrupted. */
123 
124     return r;
125 }
126 
127 static int
lock_acquire_parse_args(PyObject * args,PyObject * kwds,_PyTime_t * timeout)128 lock_acquire_parse_args(PyObject *args, PyObject *kwds,
129                         _PyTime_t *timeout)
130 {
131     char *kwlist[] = {"blocking", "timeout", NULL};
132     int blocking = 1;
133     PyObject *timeout_obj = NULL;
134     const _PyTime_t unset_timeout = _PyTime_FromSeconds(-1);
135 
136     *timeout = unset_timeout ;
137 
138     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO:acquire", kwlist,
139                                      &blocking, &timeout_obj))
140         return -1;
141 
142     if (timeout_obj
143         && _PyTime_FromSecondsObject(timeout,
144                                      timeout_obj, _PyTime_ROUND_TIMEOUT) < 0)
145         return -1;
146 
147     if (!blocking && *timeout != unset_timeout ) {
148         PyErr_SetString(PyExc_ValueError,
149                         "can't specify a timeout for a non-blocking call");
150         return -1;
151     }
152     if (*timeout < 0 && *timeout != unset_timeout) {
153         PyErr_SetString(PyExc_ValueError,
154                         "timeout value must be positive");
155         return -1;
156     }
157     if (!blocking)
158         *timeout = 0;
159     else if (*timeout != unset_timeout) {
160         _PyTime_t microseconds;
161 
162         microseconds = _PyTime_AsMicroseconds(*timeout, _PyTime_ROUND_TIMEOUT);
163         if (microseconds > PY_TIMEOUT_MAX) {
164             PyErr_SetString(PyExc_OverflowError,
165                             "timeout value is too large");
166             return -1;
167         }
168     }
169     return 0;
170 }
171 
172 static PyObject *
lock_PyThread_acquire_lock(lockobject * self,PyObject * args,PyObject * kwds)173 lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds)
174 {
175     _PyTime_t timeout;
176     if (lock_acquire_parse_args(args, kwds, &timeout) < 0)
177         return NULL;
178 
179     PyLockStatus r = acquire_timed(self->lock_lock, timeout);
180     if (r == PY_LOCK_INTR) {
181         return NULL;
182     }
183 
184     if (r == PY_LOCK_ACQUIRED)
185         self->locked = 1;
186     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 *
lock_PyThread_release_lock(lockobject * self,PyObject * Py_UNUSED (ignored))201 lock_PyThread_release_lock(lockobject *self, PyObject *Py_UNUSED(ignored))
202 {
203     /* Sanity check: the lock must be locked */
204     if (!self->locked) {
205         PyErr_SetString(ThreadError, "release unlocked lock");
206         return NULL;
207     }
208 
209     PyThread_release_lock(self->lock_lock);
210     self->locked = 0;
211     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 *
lock_locked_lock(lockobject * self,PyObject * Py_UNUSED (ignored))223 lock_locked_lock(lockobject *self, PyObject *Py_UNUSED(ignored))
224 {
225     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 *
lock_repr(lockobject * self)235 lock_repr(lockobject *self)
236 {
237     return PyUnicode_FromFormat("<%s %s object at %p>",
238         self->locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self);
239 }
240 
241 #ifdef HAVE_FORK
242 static PyObject *
lock__at_fork_reinit(lockobject * self,PyObject * Py_UNUSED (args))243 lock__at_fork_reinit(lockobject *self, PyObject *Py_UNUSED(args))
244 {
245     if (_PyThread_at_fork_reinit(&self->lock_lock) < 0) {
246         PyErr_SetString(ThreadError, "failed to reinitialize lock at fork");
247         return NULL;
248     }
249 
250     self->locked = 0;
251 
252     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
rlock_traverse(rlockobject * self,visitproc visit,void * arg)327 rlock_traverse(rlockobject *self, visitproc visit, void *arg)
328 {
329     Py_VISIT(Py_TYPE(self));
330     return 0;
331 }
332 
333 
334 static void
rlock_dealloc(rlockobject * self)335 rlock_dealloc(rlockobject *self)
336 {
337     PyObject_GC_UnTrack(self);
338     if (self->in_weakreflist != NULL)
339         PyObject_ClearWeakRefs((PyObject *) self);
340     /* self->rlock_lock can be NULL if PyThread_allocate_lock() failed
341        in rlock_new() */
342     if (self->rlock_lock != NULL) {
343         /* Unlock the lock so it's safe to free it */
344         if (self->rlock_count > 0)
345             PyThread_release_lock(self->rlock_lock);
346 
347         PyThread_free_lock(self->rlock_lock);
348     }
349     PyTypeObject *tp = Py_TYPE(self);
350     tp->tp_free(self);
351     Py_DECREF(tp);
352 }
353 
354 static PyObject *
rlock_acquire(rlockobject * self,PyObject * args,PyObject * kwds)355 rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds)
356 {
357     _PyTime_t timeout;
358     unsigned long tid;
359     PyLockStatus r = PY_LOCK_ACQUIRED;
360 
361     if (lock_acquire_parse_args(args, kwds, &timeout) < 0)
362         return NULL;
363 
364     tid = PyThread_get_thread_ident();
365     if (self->rlock_count > 0 && tid == self->rlock_owner) {
366         unsigned long count = self->rlock_count + 1;
367         if (count <= self->rlock_count) {
368             PyErr_SetString(PyExc_OverflowError,
369                             "Internal lock count overflowed");
370             return NULL;
371         }
372         self->rlock_count = count;
373         Py_RETURN_TRUE;
374     }
375     r = acquire_timed(self->rlock_lock, timeout);
376     if (r == PY_LOCK_ACQUIRED) {
377         assert(self->rlock_count == 0);
378         self->rlock_owner = tid;
379         self->rlock_count = 1;
380     }
381     else if (r == PY_LOCK_INTR) {
382         return NULL;
383     }
384 
385     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 *
rlock_release(rlockobject * self,PyObject * Py_UNUSED (ignored))405 rlock_release(rlockobject *self, PyObject *Py_UNUSED(ignored))
406 {
407     unsigned long tid = PyThread_get_thread_ident();
408 
409     if (self->rlock_count == 0 || self->rlock_owner != tid) {
410         PyErr_SetString(PyExc_RuntimeError,
411                         "cannot release un-acquired lock");
412         return NULL;
413     }
414     if (--self->rlock_count == 0) {
415         self->rlock_owner = 0;
416         PyThread_release_lock(self->rlock_lock);
417     }
418     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 *
rlock_acquire_restore(rlockobject * self,PyObject * args)434 rlock_acquire_restore(rlockobject *self, PyObject *args)
435 {
436     unsigned long owner;
437     unsigned long count;
438     int r = 1;
439 
440     if (!PyArg_ParseTuple(args, "(kk):_acquire_restore", &count, &owner))
441         return NULL;
442 
443     if (!PyThread_acquire_lock(self->rlock_lock, 0)) {
444         Py_BEGIN_ALLOW_THREADS
445         r = PyThread_acquire_lock(self->rlock_lock, 1);
446         Py_END_ALLOW_THREADS
447     }
448     if (!r) {
449         PyErr_SetString(ThreadError, "couldn't acquire lock");
450         return NULL;
451     }
452     assert(self->rlock_count == 0);
453     self->rlock_owner = owner;
454     self->rlock_count = count;
455     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 *
rlock_release_save(rlockobject * self,PyObject * Py_UNUSED (ignored))464 rlock_release_save(rlockobject *self, PyObject *Py_UNUSED(ignored))
465 {
466     unsigned long owner;
467     unsigned long count;
468 
469     if (self->rlock_count == 0) {
470         PyErr_SetString(PyExc_RuntimeError,
471                         "cannot release un-acquired lock");
472         return NULL;
473     }
474 
475     owner = self->rlock_owner;
476     count = self->rlock_count;
477     self->rlock_count = 0;
478     self->rlock_owner = 0;
479     PyThread_release_lock(self->rlock_lock);
480     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 *
rlock_is_owned(rlockobject * self,PyObject * Py_UNUSED (ignored))490 rlock_is_owned(rlockobject *self, PyObject *Py_UNUSED(ignored))
491 {
492     unsigned long tid = PyThread_get_thread_ident();
493 
494     if (self->rlock_count > 0 && self->rlock_owner == tid) {
495         Py_RETURN_TRUE;
496     }
497     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 *
rlock_new(PyTypeObject * type,PyObject * args,PyObject * kwds)506 rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
507 {
508     rlockobject *self = (rlockobject *) type->tp_alloc(type, 0);
509     if (self == NULL) {
510         return NULL;
511     }
512     self->in_weakreflist = NULL;
513     self->rlock_owner = 0;
514     self->rlock_count = 0;
515 
516     self->rlock_lock = PyThread_allocate_lock();
517     if (self->rlock_lock == NULL) {
518         Py_DECREF(self);
519         PyErr_SetString(ThreadError, "can't allocate lock");
520         return NULL;
521     }
522     return (PyObject *) self;
523 }
524 
525 static PyObject *
rlock_repr(rlockobject * self)526 rlock_repr(rlockobject *self)
527 {
528     return PyUnicode_FromFormat("<%s %s object owner=%ld count=%lu at %p>",
529         self->rlock_count ? "locked" : "unlocked",
530         Py_TYPE(self)->tp_name, self->rlock_owner,
531         self->rlock_count, self);
532 }
533 
534 
535 #ifdef HAVE_FORK
536 static PyObject *
rlock__at_fork_reinit(rlockobject * self,PyObject * Py_UNUSED (args))537 rlock__at_fork_reinit(rlockobject *self, PyObject *Py_UNUSED(args))
538 {
539     if (_PyThread_at_fork_reinit(&self->rlock_lock) < 0) {
540         PyErr_SetString(ThreadError, "failed to reinitialize lock at fork");
541         return NULL;
542     }
543 
544     self->rlock_owner = 0;
545     self->rlock_count = 0;
546 
547     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 *
newlockobject(PyObject * module)600 newlockobject(PyObject *module)
601 {
602     thread_module_state *state = get_thread_state(module);
603 
604     PyTypeObject *type = state->lock_type;
605     lockobject *self = (lockobject *)type->tp_alloc(type, 0);
606     if (self == NULL) {
607         return NULL;
608     }
609 
610     self->lock_lock = PyThread_allocate_lock();
611     self->locked = 0;
612     self->in_weakreflist = NULL;
613 
614     if (self->lock_lock == NULL) {
615         Py_DECREF(self);
616         PyErr_SetString(ThreadError, "can't allocate lock");
617         return NULL;
618     }
619     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
localdummy_dealloc(localdummyobject * self)670 localdummy_dealloc(localdummyobject *self)
671 {
672     if (self->weakreflist != NULL)
673         PyObject_ClearWeakRefs((PyObject *) self);
674     PyTypeObject *tp = Py_TYPE(self);
675     tp->tp_free((PyObject*)self);
676     Py_DECREF(tp);
677 }
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 *
_local_create_dummy(localobject * self,thread_module_state * state)719 _local_create_dummy(localobject *self, thread_module_state *state)
720 {
721     PyObject *ldict = NULL, *wr = NULL;
722     localdummyobject *dummy = NULL;
723     PyTypeObject *type = state->local_dummy_type;
724 
725     PyObject *tdict = PyThreadState_GetDict();
726     if (tdict == NULL) {
727         PyErr_SetString(PyExc_SystemError,
728                         "Couldn't get thread-state dictionary");
729         goto err;
730     }
731 
732     ldict = PyDict_New();
733     if (ldict == NULL) {
734         goto err;
735     }
736     dummy = (localdummyobject *) type->tp_alloc(type, 0);
737     if (dummy == NULL) {
738         goto err;
739     }
740     dummy->localdict = ldict;
741     wr = PyWeakref_NewRef((PyObject *) dummy, self->wr_callback);
742     if (wr == NULL) {
743         goto err;
744     }
745 
746     /* As a side-effect, this will cache the weakref's hash before the
747        dummy gets deleted */
748     int r = PyDict_SetItem(self->dummies, wr, ldict);
749     if (r < 0) {
750         goto err;
751     }
752     Py_CLEAR(wr);
753     r = PyDict_SetItem(tdict, self->key, (PyObject *) dummy);
754     if (r < 0) {
755         goto err;
756     }
757     Py_CLEAR(dummy);
758 
759     Py_DECREF(ldict);
760     return ldict;
761 
762 err:
763     Py_XDECREF(ldict);
764     Py_XDECREF(wr);
765     Py_XDECREF(dummy);
766     return NULL;
767 }
768 
769 static PyObject *
local_new(PyTypeObject * type,PyObject * args,PyObject * kw)770 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     if (type->tp_init == PyBaseObject_Type.tp_init) {
777         int rc = 0;
778         if (args != NULL)
779             rc = PyObject_IsTrue(args);
780         if (rc == 0 && kw != NULL)
781             rc = PyObject_IsTrue(kw);
782         if (rc != 0) {
783             if (rc > 0) {
784                 PyErr_SetString(PyExc_TypeError,
785                           "Initialization arguments are not supported");
786             }
787             return NULL;
788         }
789     }
790 
791     PyObject *module = PyType_GetModuleByDef(type, &thread_module);
792     thread_module_state *state = get_thread_state(module);
793 
794     localobject *self = (localobject *)type->tp_alloc(type, 0);
795     if (self == NULL) {
796         return NULL;
797     }
798 
799     self->args = Py_XNewRef(args);
800     self->kw = Py_XNewRef(kw);
801     self->key = PyUnicode_FromFormat("thread.local.%p", self);
802     if (self->key == NULL) {
803         goto err;
804     }
805 
806     self->dummies = PyDict_New();
807     if (self->dummies == NULL) {
808         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     PyObject *wr = PyWeakref_NewRef((PyObject *) self, NULL);
814     if (wr == NULL) {
815         goto err;
816     }
817     self->wr_callback = PyCFunction_NewEx(&wr_callback_def, wr, NULL);
818     Py_DECREF(wr);
819     if (self->wr_callback == NULL) {
820         goto err;
821     }
822     if (_local_create_dummy(self, state) == NULL) {
823         goto err;
824     }
825     return (PyObject *)self;
826 
827   err:
828     Py_DECREF(self);
829     return NULL;
830 }
831 
832 static int
local_traverse(localobject * self,visitproc visit,void * arg)833 local_traverse(localobject *self, visitproc visit, void *arg)
834 {
835     Py_VISIT(Py_TYPE(self));
836     Py_VISIT(self->args);
837     Py_VISIT(self->kw);
838     Py_VISIT(self->dummies);
839     return 0;
840 }
841 
842 #define HEAD_LOCK(runtime) \
843     PyThread_acquire_lock((runtime)->interpreters.mutex, WAIT_LOCK)
844 #define HEAD_UNLOCK(runtime) \
845     PyThread_release_lock((runtime)->interpreters.mutex)
846 
847 static int
local_clear(localobject * self)848 local_clear(localobject *self)
849 {
850     Py_CLEAR(self->args);
851     Py_CLEAR(self->kw);
852     Py_CLEAR(self->dummies);
853     Py_CLEAR(self->wr_callback);
854     /* Remove all strong references to dummies from the thread states */
855     if (self->key) {
856         PyInterpreterState *interp = _PyInterpreterState_GET();
857         _PyRuntimeState *runtime = &_PyRuntime;
858         HEAD_LOCK(runtime);
859         PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
860         HEAD_UNLOCK(runtime);
861         while (tstate) {
862             if (tstate->dict) {
863                 PyObject *v = _PyDict_Pop(tstate->dict, self->key, Py_None);
864                 if (v != NULL) {
865                     Py_DECREF(v);
866                 }
867                 else {
868                     PyErr_Clear();
869                 }
870             }
871             HEAD_LOCK(runtime);
872             tstate = PyThreadState_Next(tstate);
873             HEAD_UNLOCK(runtime);
874         }
875     }
876     return 0;
877 }
878 
879 static void
local_dealloc(localobject * self)880 local_dealloc(localobject *self)
881 {
882     /* Weakrefs must be invalidated right now, otherwise they can be used
883        from code called below, which is very dangerous since Py_REFCNT(self) == 0 */
884     if (self->weakreflist != NULL) {
885         PyObject_ClearWeakRefs((PyObject *) self);
886     }
887 
888     PyObject_GC_UnTrack(self);
889 
890     local_clear(self);
891     Py_XDECREF(self->key);
892 
893     PyTypeObject *tp = Py_TYPE(self);
894     tp->tp_free((PyObject*)self);
895     Py_DECREF(tp);
896 }
897 
898 /* Returns a borrowed reference to the local dict, creating it if necessary */
899 static PyObject *
_ldict(localobject * self,thread_module_state * state)900 _ldict(localobject *self, thread_module_state *state)
901 {
902     PyObject *tdict = PyThreadState_GetDict();
903     if (tdict == NULL) {
904         PyErr_SetString(PyExc_SystemError,
905                         "Couldn't get thread-state dictionary");
906         return NULL;
907     }
908 
909     PyObject *ldict;
910     PyObject *dummy = PyDict_GetItemWithError(tdict, self->key);
911     if (dummy == NULL) {
912         if (PyErr_Occurred()) {
913             return NULL;
914         }
915         ldict = _local_create_dummy(self, state);
916         if (ldict == NULL)
917             return NULL;
918 
919         if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init &&
920             Py_TYPE(self)->tp_init((PyObject*)self,
921                                    self->args, self->kw) < 0) {
922             /* we need to get rid of ldict from thread so
923                we create a new one the next time we do an attr
924                access */
925             PyDict_DelItem(tdict, self->key);
926             return NULL;
927         }
928     }
929     else {
930         assert(Py_IS_TYPE(dummy, state->local_dummy_type));
931         ldict = ((localdummyobject *) dummy)->localdict;
932     }
933 
934     return ldict;
935 }
936 
937 static int
local_setattro(localobject * self,PyObject * name,PyObject * v)938 local_setattro(localobject *self, PyObject *name, PyObject *v)
939 {
940     PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
941     thread_module_state *state = get_thread_state(module);
942 
943     PyObject *ldict = _ldict(self, state);
944     if (ldict == NULL) {
945         return -1;
946     }
947 
948     int r = PyObject_RichCompareBool(name, &_Py_ID(__dict__), Py_EQ);
949     if (r == -1) {
950         return -1;
951     }
952     if (r == 1) {
953         PyErr_Format(PyExc_AttributeError,
954                      "'%.50s' object attribute '%U' is read-only",
955                      Py_TYPE(self)->tp_name, name);
956         return -1;
957     }
958 
959     return _PyObject_GenericSetAttrWithDict((PyObject *)self, name, v, ldict);
960 }
961 
962 static PyObject *local_getattro(localobject *, PyObject *);
963 
964 static PyMemberDef local_type_members[] = {
965     {"__weaklistoffset__", T_PYSSIZET, offsetof(localobject, weakreflist), READONLY},
966     {NULL},
967 };
968 
969 static PyType_Slot local_type_slots[] = {
970     {Py_tp_dealloc, (destructor)local_dealloc},
971     {Py_tp_getattro, (getattrofunc)local_getattro},
972     {Py_tp_setattro, (setattrofunc)local_setattro},
973     {Py_tp_doc, "Thread-local data"},
974     {Py_tp_traverse, (traverseproc)local_traverse},
975     {Py_tp_clear, (inquiry)local_clear},
976     {Py_tp_new, local_new},
977     {Py_tp_members, local_type_members},
978     {0, 0}
979 };
980 
981 static PyType_Spec local_type_spec = {
982     .name = "_thread._local",
983     .basicsize = sizeof(localobject),
984     .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
985               Py_TPFLAGS_IMMUTABLETYPE),
986     .slots = local_type_slots,
987 };
988 
989 static PyObject *
local_getattro(localobject * self,PyObject * name)990 local_getattro(localobject *self, PyObject *name)
991 {
992     PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &thread_module);
993     thread_module_state *state = get_thread_state(module);
994 
995     PyObject *ldict = _ldict(self, state);
996     if (ldict == NULL)
997         return NULL;
998 
999     int r = PyObject_RichCompareBool(name, &_Py_ID(__dict__), Py_EQ);
1000     if (r == 1) {
1001         return Py_NewRef(ldict);
1002     }
1003     if (r == -1) {
1004         return NULL;
1005     }
1006 
1007     if (!Py_IS_TYPE(self, state->local_type)) {
1008         /* use generic lookup for subtypes */
1009         return _PyObject_GenericGetAttrWithDict((PyObject *)self, name,
1010                                                 ldict, 0);
1011     }
1012 
1013     /* Optimization: just look in dict ourselves */
1014     PyObject *value = PyDict_GetItemWithError(ldict, name);
1015     if (value != NULL) {
1016         return Py_NewRef(value);
1017     }
1018     if (PyErr_Occurred()) {
1019         return NULL;
1020     }
1021 
1022     /* Fall back on generic to get __class__ and __dict__ */
1023     return _PyObject_GenericGetAttrWithDict(
1024         (PyObject *)self, name, ldict, 0);
1025 }
1026 
1027 /* Called when a dummy is destroyed. */
1028 static PyObject *
_localdummy_destroyed(PyObject * localweakref,PyObject * dummyweakref)1029 _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref)
1030 {
1031     assert(PyWeakref_CheckRef(localweakref));
1032     PyObject *obj = PyWeakref_GET_OBJECT(localweakref);
1033     if (obj == Py_None) {
1034         Py_RETURN_NONE;
1035     }
1036 
1037     /* If the thread-local object is still alive and not being cleared,
1038        remove the corresponding local dict */
1039     localobject *self = (localobject *)Py_NewRef(obj);
1040     if (self->dummies != NULL) {
1041         PyObject *ldict;
1042         ldict = PyDict_GetItemWithError(self->dummies, dummyweakref);
1043         if (ldict != NULL) {
1044             PyDict_DelItem(self->dummies, dummyweakref);
1045         }
1046         if (PyErr_Occurred())
1047             PyErr_WriteUnraisable(obj);
1048     }
1049     Py_DECREF(obj);
1050     Py_RETURN_NONE;
1051 }
1052 
1053 /* Module functions */
1054 
1055 struct bootstate {
1056     PyInterpreterState *interp;
1057     PyObject *func;
1058     PyObject *args;
1059     PyObject *kwargs;
1060     PyThreadState *tstate;
1061     _PyRuntimeState *runtime;
1062 };
1063 
1064 
1065 static void
thread_bootstate_free(struct bootstate * boot)1066 thread_bootstate_free(struct bootstate *boot)
1067 {
1068     Py_DECREF(boot->func);
1069     Py_DECREF(boot->args);
1070     Py_XDECREF(boot->kwargs);
1071     PyMem_Free(boot);
1072 }
1073 
1074 
1075 static void
thread_run(void * boot_raw)1076 thread_run(void *boot_raw)
1077 {
1078     struct bootstate *boot = (struct bootstate *) boot_raw;
1079     PyThreadState *tstate;
1080 
1081     tstate = boot->tstate;
1082     tstate->thread_id = PyThread_get_thread_ident();
1083 #ifdef PY_HAVE_THREAD_NATIVE_ID
1084     tstate->native_thread_id = PyThread_get_thread_native_id();
1085 #else
1086     tstate->native_thread_id = 0;
1087 #endif
1088     _PyThreadState_SetCurrent(tstate);
1089     PyEval_AcquireThread(tstate);
1090     tstate->interp->threads.count++;
1091 
1092     PyObject *res = PyObject_Call(boot->func, boot->args, boot->kwargs);
1093     if (res == NULL) {
1094         if (PyErr_ExceptionMatches(PyExc_SystemExit))
1095             /* SystemExit is ignored silently */
1096             PyErr_Clear();
1097         else {
1098             _PyErr_WriteUnraisableMsg("in thread started by", boot->func);
1099         }
1100     }
1101     else {
1102         Py_DECREF(res);
1103     }
1104 
1105     thread_bootstate_free(boot);
1106     tstate->interp->threads.count--;
1107     PyThreadState_Clear(tstate);
1108     _PyThreadState_DeleteCurrent(tstate);
1109 
1110     // bpo-44434: Don't call explicitly PyThread_exit_thread(). On Linux with
1111     // the glibc, pthread_exit() can abort the whole process if dlopen() fails
1112     // to open the libgcc_s.so library (ex: EMFILE error).
1113 }
1114 
1115 static PyObject *
thread_PyThread_start_new_thread(PyObject * self,PyObject * fargs)1116 thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
1117 {
1118     _PyRuntimeState *runtime = &_PyRuntime;
1119     PyObject *func, *args, *kwargs = NULL;
1120 
1121     if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
1122                            &func, &args, &kwargs))
1123         return NULL;
1124     if (!PyCallable_Check(func)) {
1125         PyErr_SetString(PyExc_TypeError,
1126                         "first arg must be callable");
1127         return NULL;
1128     }
1129     if (!PyTuple_Check(args)) {
1130         PyErr_SetString(PyExc_TypeError,
1131                         "2nd arg must be a tuple");
1132         return NULL;
1133     }
1134     if (kwargs != NULL && !PyDict_Check(kwargs)) {
1135         PyErr_SetString(PyExc_TypeError,
1136                         "optional 3rd arg must be a dictionary");
1137         return NULL;
1138     }
1139 
1140     PyInterpreterState *interp = _PyInterpreterState_GET();
1141     if (interp->config._isolated_interpreter) {
1142         PyErr_SetString(PyExc_RuntimeError,
1143                         "thread is not supported for isolated subinterpreters");
1144         return NULL;
1145     }
1146 
1147     struct bootstate *boot = PyMem_NEW(struct bootstate, 1);
1148     if (boot == NULL) {
1149         return PyErr_NoMemory();
1150     }
1151     boot->interp = _PyInterpreterState_GET();
1152     boot->tstate = _PyThreadState_Prealloc(boot->interp);
1153     if (boot->tstate == NULL) {
1154         PyMem_Free(boot);
1155         return PyErr_NoMemory();
1156     }
1157     boot->runtime = runtime;
1158     boot->func = Py_NewRef(func);
1159     boot->args = Py_NewRef(args);
1160     boot->kwargs = Py_XNewRef(kwargs);
1161 
1162     unsigned long ident = PyThread_start_new_thread(thread_run, (void*) boot);
1163     if (ident == PYTHREAD_INVALID_THREAD_ID) {
1164         PyErr_SetString(ThreadError, "can't start new thread");
1165         PyThreadState_Clear(boot->tstate);
1166         thread_bootstate_free(boot);
1167         return NULL;
1168     }
1169     return PyLong_FromUnsignedLong(ident);
1170 }
1171 
1172 PyDoc_STRVAR(start_new_doc,
1173 "start_new_thread(function, args[, kwargs])\n\
1174 (start_new() is an obsolete synonym)\n\
1175 \n\
1176 Start a new thread and return its identifier.  The thread will call the\n\
1177 function with positional arguments from the tuple args and keyword arguments\n\
1178 taken from the optional dictionary kwargs.  The thread exits when the\n\
1179 function returns; the return value is ignored.  The thread will also exit\n\
1180 when the function raises an unhandled exception; a stack trace will be\n\
1181 printed unless the exception is SystemExit.\n");
1182 
1183 static PyObject *
thread_PyThread_exit_thread(PyObject * self,PyObject * Py_UNUSED (ignored))1184 thread_PyThread_exit_thread(PyObject *self, PyObject *Py_UNUSED(ignored))
1185 {
1186     PyErr_SetNone(PyExc_SystemExit);
1187     return NULL;
1188 }
1189 
1190 PyDoc_STRVAR(exit_doc,
1191 "exit()\n\
1192 (exit_thread() is an obsolete synonym)\n\
1193 \n\
1194 This is synonymous to ``raise SystemExit''.  It will cause the current\n\
1195 thread to exit silently unless the exception is caught.");
1196 
1197 static PyObject *
thread_PyThread_interrupt_main(PyObject * self,PyObject * args)1198 thread_PyThread_interrupt_main(PyObject *self, PyObject *args)
1199 {
1200     int signum = SIGINT;
1201     if (!PyArg_ParseTuple(args, "|i:signum", &signum)) {
1202         return NULL;
1203     }
1204 
1205     if (PyErr_SetInterruptEx(signum)) {
1206         PyErr_SetString(PyExc_ValueError, "signal number out of range");
1207         return NULL;
1208     }
1209     Py_RETURN_NONE;
1210 }
1211 
1212 PyDoc_STRVAR(interrupt_doc,
1213 "interrupt_main(signum=signal.SIGINT, /)\n\
1214 \n\
1215 Simulate the arrival of the given signal in the main thread,\n\
1216 where the corresponding signal handler will be executed.\n\
1217 If *signum* is omitted, SIGINT is assumed.\n\
1218 A subthread can use this function to interrupt the main thread.\n\
1219 \n\
1220 Note: the default signal handler for SIGINT raises ``KeyboardInterrupt``."
1221 );
1222 
1223 static lockobject *newlockobject(PyObject *module);
1224 
1225 static PyObject *
thread_PyThread_allocate_lock(PyObject * module,PyObject * Py_UNUSED (ignored))1226 thread_PyThread_allocate_lock(PyObject *module, PyObject *Py_UNUSED(ignored))
1227 {
1228     return (PyObject *) newlockobject(module);
1229 }
1230 
1231 PyDoc_STRVAR(allocate_doc,
1232 "allocate_lock() -> lock object\n\
1233 (allocate() is an obsolete synonym)\n\
1234 \n\
1235 Create a new lock object. See help(type(threading.Lock())) for\n\
1236 information about locks.");
1237 
1238 static PyObject *
thread_get_ident(PyObject * self,PyObject * Py_UNUSED (ignored))1239 thread_get_ident(PyObject *self, PyObject *Py_UNUSED(ignored))
1240 {
1241     unsigned long ident = PyThread_get_thread_ident();
1242     if (ident == PYTHREAD_INVALID_THREAD_ID) {
1243         PyErr_SetString(ThreadError, "no current thread ident");
1244         return NULL;
1245     }
1246     return PyLong_FromUnsignedLong(ident);
1247 }
1248 
1249 PyDoc_STRVAR(get_ident_doc,
1250 "get_ident() -> integer\n\
1251 \n\
1252 Return a non-zero integer that uniquely identifies the current thread\n\
1253 amongst other threads that exist simultaneously.\n\
1254 This may be used to identify per-thread resources.\n\
1255 Even though on some platforms threads identities may appear to be\n\
1256 allocated consecutive numbers starting at 1, this behavior should not\n\
1257 be relied upon, and the number should be seen purely as a magic cookie.\n\
1258 A thread's identity may be reused for another thread after it exits.");
1259 
1260 #ifdef PY_HAVE_THREAD_NATIVE_ID
1261 static PyObject *
thread_get_native_id(PyObject * self,PyObject * Py_UNUSED (ignored))1262 thread_get_native_id(PyObject *self, PyObject *Py_UNUSED(ignored))
1263 {
1264     unsigned long native_id = PyThread_get_thread_native_id();
1265     return PyLong_FromUnsignedLong(native_id);
1266 }
1267 
1268 PyDoc_STRVAR(get_native_id_doc,
1269 "get_native_id() -> integer\n\
1270 \n\
1271 Return a non-negative integer identifying the thread as reported\n\
1272 by the OS (kernel). This may be used to uniquely identify a\n\
1273 particular thread within a system.");
1274 #endif
1275 
1276 static PyObject *
thread__count(PyObject * self,PyObject * Py_UNUSED (ignored))1277 thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
1278 {
1279     PyInterpreterState *interp = _PyInterpreterState_GET();
1280     return PyLong_FromLong(interp->threads.count);
1281 }
1282 
1283 PyDoc_STRVAR(_count_doc,
1284 "_count() -> integer\n\
1285 \n\
1286 \
1287 Return the number of currently running Python threads, excluding\n\
1288 the main thread. The returned number comprises all threads created\n\
1289 through `start_new_thread()` as well as `threading.Thread`, and not\n\
1290 yet finished.\n\
1291 \n\
1292 This function is meant for internal and specialized purposes only.\n\
1293 In most applications `threading.enumerate()` should be used instead.");
1294 
1295 static void
release_sentinel(void * wr_raw)1296 release_sentinel(void *wr_raw)
1297 {
1298     PyObject *wr = _PyObject_CAST(wr_raw);
1299     /* Tricky: this function is called when the current thread state
1300        is being deleted.  Therefore, only simple C code can safely
1301        execute here. */
1302     PyObject *obj = PyWeakref_GET_OBJECT(wr);
1303     lockobject *lock;
1304     if (obj != Py_None) {
1305         lock = (lockobject *) obj;
1306         if (lock->locked) {
1307             PyThread_release_lock(lock->lock_lock);
1308             lock->locked = 0;
1309         }
1310     }
1311     /* Deallocating a weakref with a NULL callback only calls
1312        PyObject_GC_Del(), which can't call any Python code. */
1313     Py_DECREF(wr);
1314 }
1315 
1316 static PyObject *
thread__set_sentinel(PyObject * module,PyObject * Py_UNUSED (ignored))1317 thread__set_sentinel(PyObject *module, PyObject *Py_UNUSED(ignored))
1318 {
1319     PyObject *wr;
1320     PyThreadState *tstate = _PyThreadState_GET();
1321     lockobject *lock;
1322 
1323     if (tstate->on_delete_data != NULL) {
1324         /* We must support the re-creation of the lock from a
1325            fork()ed child. */
1326         assert(tstate->on_delete == &release_sentinel);
1327         wr = (PyObject *) tstate->on_delete_data;
1328         tstate->on_delete = NULL;
1329         tstate->on_delete_data = NULL;
1330         Py_DECREF(wr);
1331     }
1332     lock = newlockobject(module);
1333     if (lock == NULL)
1334         return NULL;
1335     /* The lock is owned by whoever called _set_sentinel(), but the weakref
1336        hangs to the thread state. */
1337     wr = PyWeakref_NewRef((PyObject *) lock, NULL);
1338     if (wr == NULL) {
1339         Py_DECREF(lock);
1340         return NULL;
1341     }
1342     tstate->on_delete_data = (void *) wr;
1343     tstate->on_delete = &release_sentinel;
1344     return (PyObject *) lock;
1345 }
1346 
1347 PyDoc_STRVAR(_set_sentinel_doc,
1348 "_set_sentinel() -> lock\n\
1349 \n\
1350 Set a sentinel lock that will be released when the current thread\n\
1351 state is finalized (after it is untied from the interpreter).\n\
1352 \n\
1353 This is a private API for the threading module.");
1354 
1355 static PyObject *
thread_stack_size(PyObject * self,PyObject * args)1356 thread_stack_size(PyObject *self, PyObject *args)
1357 {
1358     size_t old_size;
1359     Py_ssize_t new_size = 0;
1360     int rc;
1361 
1362     if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size))
1363         return NULL;
1364 
1365     if (new_size < 0) {
1366         PyErr_SetString(PyExc_ValueError,
1367                         "size must be 0 or a positive value");
1368         return NULL;
1369     }
1370 
1371     old_size = PyThread_get_stacksize();
1372 
1373     rc = PyThread_set_stacksize((size_t) new_size);
1374     if (rc == -1) {
1375         PyErr_Format(PyExc_ValueError,
1376                      "size not valid: %zd bytes",
1377                      new_size);
1378         return NULL;
1379     }
1380     if (rc == -2) {
1381         PyErr_SetString(ThreadError,
1382                         "setting stack size not supported");
1383         return NULL;
1384     }
1385 
1386     return PyLong_FromSsize_t((Py_ssize_t) old_size);
1387 }
1388 
1389 PyDoc_STRVAR(stack_size_doc,
1390 "stack_size([size]) -> size\n\
1391 \n\
1392 Return the thread stack size used when creating new threads.  The\n\
1393 optional size argument specifies the stack size (in bytes) to be used\n\
1394 for subsequently created threads, and must be 0 (use platform or\n\
1395 configured default) or a positive integer value of at least 32,768 (32k).\n\
1396 If changing the thread stack size is unsupported, a ThreadError\n\
1397 exception is raised.  If the specified size is invalid, a ValueError\n\
1398 exception is raised, and the stack size is unmodified.  32k bytes\n\
1399  currently the minimum supported stack size value to guarantee\n\
1400 sufficient stack space for the interpreter itself.\n\
1401 \n\
1402 Note that some platforms may have particular restrictions on values for\n\
1403 the stack size, such as requiring a minimum stack size larger than 32 KiB or\n\
1404 requiring allocation in multiples of the system memory page size\n\
1405 - platform documentation should be referred to for more information\n\
1406 (4 KiB pages are common; using multiples of 4096 for the stack size is\n\
1407 the suggested approach in the absence of more specific information).");
1408 
1409 static int
thread_excepthook_file(PyObject * file,PyObject * exc_type,PyObject * exc_value,PyObject * exc_traceback,PyObject * thread)1410 thread_excepthook_file(PyObject *file, PyObject *exc_type, PyObject *exc_value,
1411                        PyObject *exc_traceback, PyObject *thread)
1412 {
1413     /* print(f"Exception in thread {thread.name}:", file=file) */
1414     if (PyFile_WriteString("Exception in thread ", file) < 0) {
1415         return -1;
1416     }
1417 
1418     PyObject *name = NULL;
1419     if (thread != Py_None) {
1420         if (_PyObject_LookupAttr(thread, &_Py_ID(name), &name) < 0) {
1421             return -1;
1422         }
1423     }
1424     if (name != NULL) {
1425         if (PyFile_WriteObject(name, file, Py_PRINT_RAW) < 0) {
1426             Py_DECREF(name);
1427             return -1;
1428         }
1429         Py_DECREF(name);
1430     }
1431     else {
1432         unsigned long ident = PyThread_get_thread_ident();
1433         PyObject *str = PyUnicode_FromFormat("%lu", ident);
1434         if (str != NULL) {
1435             if (PyFile_WriteObject(str, file, Py_PRINT_RAW) < 0) {
1436                 Py_DECREF(str);
1437                 return -1;
1438             }
1439             Py_DECREF(str);
1440         }
1441         else {
1442             PyErr_Clear();
1443 
1444             if (PyFile_WriteString("<failed to get thread name>", file) < 0) {
1445                 return -1;
1446             }
1447         }
1448     }
1449 
1450     if (PyFile_WriteString(":\n", file) < 0) {
1451         return -1;
1452     }
1453 
1454     /* Display the traceback */
1455     _PyErr_Display(file, exc_type, exc_value, exc_traceback);
1456 
1457     /* Call file.flush() */
1458     PyObject *res = PyObject_CallMethodNoArgs(file, &_Py_ID(flush));
1459     if (!res) {
1460         return -1;
1461     }
1462     Py_DECREF(res);
1463 
1464     return 0;
1465 }
1466 
1467 
1468 PyDoc_STRVAR(ExceptHookArgs__doc__,
1469 "ExceptHookArgs\n\
1470 \n\
1471 Type used to pass arguments to threading.excepthook.");
1472 
1473 static PyStructSequence_Field ExceptHookArgs_fields[] = {
1474     {"exc_type", "Exception type"},
1475     {"exc_value", "Exception value"},
1476     {"exc_traceback", "Exception traceback"},
1477     {"thread", "Thread"},
1478     {0}
1479 };
1480 
1481 static PyStructSequence_Desc ExceptHookArgs_desc = {
1482     .name = "_thread._ExceptHookArgs",
1483     .doc = ExceptHookArgs__doc__,
1484     .fields = ExceptHookArgs_fields,
1485     .n_in_sequence = 4
1486 };
1487 
1488 
1489 static PyObject *
thread_excepthook(PyObject * module,PyObject * args)1490 thread_excepthook(PyObject *module, PyObject *args)
1491 {
1492     thread_module_state *state = get_thread_state(module);
1493 
1494     if (!Py_IS_TYPE(args, state->excepthook_type)) {
1495         PyErr_SetString(PyExc_TypeError,
1496                         "_thread.excepthook argument type "
1497                         "must be ExceptHookArgs");
1498         return NULL;
1499     }
1500 
1501     /* Borrowed reference */
1502     PyObject *exc_type = PyStructSequence_GET_ITEM(args, 0);
1503     if (exc_type == PyExc_SystemExit) {
1504         /* silently ignore SystemExit */
1505         Py_RETURN_NONE;
1506     }
1507 
1508     /* Borrowed references */
1509     PyObject *exc_value = PyStructSequence_GET_ITEM(args, 1);
1510     PyObject *exc_tb = PyStructSequence_GET_ITEM(args, 2);
1511     PyObject *thread = PyStructSequence_GET_ITEM(args, 3);
1512 
1513     PyThreadState *tstate = _PyThreadState_GET();
1514     PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr));
1515     if (file == NULL || file == Py_None) {
1516         if (thread == Py_None) {
1517             /* do nothing if sys.stderr is None and thread is None */
1518             Py_RETURN_NONE;
1519         }
1520 
1521         file = PyObject_GetAttrString(thread, "_stderr");
1522         if (file == NULL) {
1523             return NULL;
1524         }
1525         if (file == Py_None) {
1526             Py_DECREF(file);
1527             /* do nothing if sys.stderr is None and sys.stderr was None
1528                when the thread was created */
1529             Py_RETURN_NONE;
1530         }
1531     }
1532     else {
1533         Py_INCREF(file);
1534     }
1535 
1536     int res = thread_excepthook_file(file, exc_type, exc_value, exc_tb,
1537                                      thread);
1538     Py_DECREF(file);
1539     if (res < 0) {
1540         return NULL;
1541     }
1542 
1543     Py_RETURN_NONE;
1544 }
1545 
1546 PyDoc_STRVAR(excepthook_doc,
1547 "excepthook(exc_type, exc_value, exc_traceback, thread)\n\
1548 \n\
1549 Handle uncaught Thread.run() exception.");
1550 
1551 static PyMethodDef thread_methods[] = {
1552     {"start_new_thread",        (PyCFunction)thread_PyThread_start_new_thread,
1553      METH_VARARGS, start_new_doc},
1554     {"start_new",               (PyCFunction)thread_PyThread_start_new_thread,
1555      METH_VARARGS, start_new_doc},
1556     {"allocate_lock",           thread_PyThread_allocate_lock,
1557      METH_NOARGS, allocate_doc},
1558     {"allocate",                thread_PyThread_allocate_lock,
1559      METH_NOARGS, allocate_doc},
1560     {"exit_thread",             thread_PyThread_exit_thread,
1561      METH_NOARGS, exit_doc},
1562     {"exit",                    thread_PyThread_exit_thread,
1563      METH_NOARGS, exit_doc},
1564     {"interrupt_main",          (PyCFunction)thread_PyThread_interrupt_main,
1565      METH_VARARGS, interrupt_doc},
1566     {"get_ident",               thread_get_ident,
1567      METH_NOARGS, get_ident_doc},
1568 #ifdef PY_HAVE_THREAD_NATIVE_ID
1569     {"get_native_id",           thread_get_native_id,
1570      METH_NOARGS, get_native_id_doc},
1571 #endif
1572     {"_count",                  thread__count,
1573      METH_NOARGS, _count_doc},
1574     {"stack_size",              (PyCFunction)thread_stack_size,
1575      METH_VARARGS, stack_size_doc},
1576     {"_set_sentinel",           thread__set_sentinel,
1577      METH_NOARGS, _set_sentinel_doc},
1578     {"_excepthook",              thread_excepthook,
1579      METH_O, excepthook_doc},
1580     {NULL,                      NULL}           /* sentinel */
1581 };
1582 
1583 
1584 /* Initialization function */
1585 
1586 static int
thread_module_exec(PyObject * module)1587 thread_module_exec(PyObject *module)
1588 {
1589     thread_module_state *state = get_thread_state(module);
1590     PyObject *d = PyModule_GetDict(module);
1591 
1592     // Initialize the C thread library
1593     PyThread_init_thread();
1594 
1595     // Lock
1596     state->lock_type = (PyTypeObject *)PyType_FromSpec(&lock_type_spec);
1597     if (state->lock_type == NULL) {
1598         return -1;
1599     }
1600     if (PyDict_SetItemString(d, "LockType", (PyObject *)state->lock_type) < 0) {
1601         return -1;
1602     }
1603 
1604     // RLock
1605     PyTypeObject *rlock_type = (PyTypeObject *)PyType_FromSpec(&rlock_type_spec);
1606     if (rlock_type == NULL) {
1607         return -1;
1608     }
1609     if (PyModule_AddType(module, rlock_type) < 0) {
1610         Py_DECREF(rlock_type);
1611         return -1;
1612     }
1613     Py_DECREF(rlock_type);
1614 
1615     // Local dummy
1616     state->local_dummy_type = (PyTypeObject *)PyType_FromSpec(&local_dummy_type_spec);
1617     if (state->local_dummy_type == NULL) {
1618         return -1;
1619     }
1620 
1621     // Local
1622     state->local_type = (PyTypeObject *)PyType_FromModuleAndSpec(module, &local_type_spec, NULL);
1623     if (state->local_type == NULL) {
1624         return -1;
1625     }
1626     if (PyModule_AddType(module, state->local_type) < 0) {
1627         return -1;
1628     }
1629 
1630     // Add module attributes
1631     if (PyDict_SetItemString(d, "error", ThreadError) < 0) {
1632         return -1;
1633     }
1634 
1635     // _ExceptHookArgs type
1636     state->excepthook_type = PyStructSequence_NewType(&ExceptHookArgs_desc);
1637     if (state->excepthook_type == NULL) {
1638         return -1;
1639     }
1640     if (PyModule_AddType(module, state->excepthook_type) < 0) {
1641         return -1;
1642     }
1643 
1644     // TIMEOUT_MAX
1645     double timeout_max = (double)PY_TIMEOUT_MAX * 1e-6;
1646     double time_max = _PyTime_AsSecondsDouble(_PyTime_MAX);
1647     timeout_max = Py_MIN(timeout_max, time_max);
1648     // Round towards minus infinity
1649     timeout_max = floor(timeout_max);
1650 
1651     if (PyModule_AddObject(module, "TIMEOUT_MAX",
1652                            PyFloat_FromDouble(timeout_max)) < 0) {
1653         return -1;
1654     }
1655 
1656     return 0;
1657 }
1658 
1659 
1660 static int
thread_module_traverse(PyObject * module,visitproc visit,void * arg)1661 thread_module_traverse(PyObject *module, visitproc visit, void *arg)
1662 {
1663     thread_module_state *state = get_thread_state(module);
1664     Py_VISIT(state->excepthook_type);
1665     Py_VISIT(state->lock_type);
1666     Py_VISIT(state->local_type);
1667     Py_VISIT(state->local_dummy_type);
1668     return 0;
1669 }
1670 
1671 static int
thread_module_clear(PyObject * module)1672 thread_module_clear(PyObject *module)
1673 {
1674     thread_module_state *state = get_thread_state(module);
1675     Py_CLEAR(state->excepthook_type);
1676     Py_CLEAR(state->lock_type);
1677     Py_CLEAR(state->local_type);
1678     Py_CLEAR(state->local_dummy_type);
1679     return 0;
1680 }
1681 
1682 static void
thread_module_free(void * module)1683 thread_module_free(void *module)
1684 {
1685     thread_module_clear((PyObject *)module);
1686 }
1687 
1688 
1689 
1690 PyDoc_STRVAR(thread_doc,
1691 "This module provides primitive operations to write multi-threaded programs.\n\
1692 The 'threading' module provides a more convenient interface.");
1693 
1694 static PyModuleDef_Slot thread_module_slots[] = {
1695     {Py_mod_exec, thread_module_exec},
1696     {0, NULL}
1697 };
1698 
1699 static struct PyModuleDef thread_module = {
1700     PyModuleDef_HEAD_INIT,
1701     .m_name = "_thread",
1702     .m_doc = thread_doc,
1703     .m_size = sizeof(thread_module_state),
1704     .m_methods = thread_methods,
1705     .m_traverse = thread_module_traverse,
1706     .m_clear = thread_module_clear,
1707     .m_free = thread_module_free,
1708     .m_slots = thread_module_slots,
1709 };
1710 
1711 PyMODINIT_FUNC
PyInit__thread(void)1712 PyInit__thread(void)
1713 {
1714     return PyModuleDef_Init(&thread_module);
1715 }
1716