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