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