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
27static struct PyModuleDef thread_module;
28
29
30typedef struct {
31 PyTypeObject *lock_type;
32 PyTypeObject *local_type;
33 PyTypeObject *local_dummy_type;
34} thread_module_state;
35
36static inline thread_module_state*
37get_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
47typedef struct {
48 PyObject_HEAD
49 PyThread_type_lock lock_lock;
50 PyObject *in_weakreflist;
51 char locked; /* for sanity checking */
52} lockobject;
53
54static int
55lock_traverse(lockobject *self, visitproc visit, void *arg)
56{
57 Py_VISIT(Py_TYPE(self));
58 return 0;
59}
60
61static void
62lock_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 */
84static PyLockStatus
85acquire_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
131static int
132lock_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
176static PyObject *
177lock_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
193PyDoc_STRVAR(acquire_doc,
194"acquire(blocking=True, timeout=-1) -> bool\n\
195(acquire_lock() is an obsolete synonym)\n\
196\n\
197Lock the lock. Without argument, this blocks if the lock is already\n\
198locked (even by the same thread), waiting for another thread to release\n\
199the lock, and return True once the lock is acquired.\n\
200With an argument, this will only block if the argument is true,\n\
201and the return value reflects whether the lock is acquired.\n\
202The blocking operation is interruptible.");
203
204static PyObject *
205lock_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
218PyDoc_STRVAR(release_doc,
219"release()\n\
220(release_lock() is an obsolete synonym)\n\
221\n\
222Release the lock, allowing another thread that is blocked waiting for\n\
223the lock to acquire the lock. The lock must be in the locked state,\n\
224but it needn't be locked by the same thread that unlocks it.");
225
226static PyObject *
227lock_locked_lock(lockobject *self, PyObject *Py_UNUSED(ignored))
228{
229 return PyBool_FromLong((long)self->locked);
230}
231
232PyDoc_STRVAR(locked_doc,
233"locked() -> bool\n\
234(locked_lock() is an obsolete synonym)\n\
235\n\
236Return whether the lock is in the locked state.");
237
238static PyObject *
239lock_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
246static PyObject *
247lock__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
261static 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
285PyDoc_STRVAR(lock_doc,
286"A lock object is a synchronization primitive. To create a lock,\n\
287call threading.Lock(). Methods are:\n\
288\n\
289acquire() -- lock the lock, possibly blocking until it can be obtained\n\
290release() -- unlock of the lock\n\
291locked() -- test whether the lock is currently locked\n\
292\n\
293A lock is not owned by the thread that locked it; another thread may\n\
294unlock it. A thread attempting to lock a lock that it has already locked\n\
295will block until another thread unlocks it. Deadlocks may ensue.");
296
297static PyMemberDef lock_type_members[] = {
298 {"__weaklistoffset__", T_PYSSIZET, offsetof(lockobject, in_weakreflist), READONLY},
299 {NULL},
300};
301
302static 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
312static 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
322typedef 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
330static int
331rlock_traverse(rlockobject *self, visitproc visit, void *arg)
332{
333 Py_VISIT(Py_TYPE(self));
334 return 0;
335}
336
337
338static void
339rlock_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
357static PyObject *
358rlock_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
391PyDoc_STRVAR(rlock_acquire_doc,
392"acquire(blocking=True) -> bool\n\
393\n\
394Lock the lock. `blocking` indicates whether we should wait\n\
395for the lock to be available or not. If `blocking` is False\n\
396and another thread holds the lock, the method will return False\n\
397immediately. If `blocking` is True and another thread holds\n\
398the lock, the method will wait for the lock to be released,\n\
399take it and then return True.\n\
400(note: the blocking operation is interruptible.)\n\
401\n\
402In all other cases, the method will return True immediately.\n\
403Precisely, if the current thread already holds the lock, its\n\
404internal counter is simply incremented. If nobody holds the lock,\n\
405the lock is taken and its internal counter initialized to 1.");
406
407static PyObject *
408rlock_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
424PyDoc_STRVAR(rlock_release_doc,
425"release()\n\
426\n\
427Release the lock, allowing another thread that is blocked waiting for\n\
428the lock to acquire the lock. The lock must be in the locked state,\n\
429and must be locked by the same thread that unlocks it; otherwise a\n\
430`RuntimeError` is raised.\n\
431\n\
432Do note that if the lock was acquire()d several times in a row by the\n\
433current thread, release() needs to be called as many times for the lock\n\
434to be available for other threads.");
435
436static PyObject *
437rlock_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
461PyDoc_STRVAR(rlock_acquire_restore_doc,
462"_acquire_restore(state) -> None\n\
463\n\
464For internal use by `threading.Condition`.");
465
466static PyObject *
467rlock_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
486PyDoc_STRVAR(rlock_release_save_doc,
487"_release_save() -> tuple\n\
488\n\
489For internal use by `threading.Condition`.");
490
491
492static PyObject *
493rlock_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
503PyDoc_STRVAR(rlock_is_owned_doc,
504"_is_owned() -> bool\n\
505\n\
506For internal use by `threading.Condition`.");
507
508static PyObject *
509rlock_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
528static PyObject *
529rlock_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
539static PyObject *
540rlock__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
555static 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
578static PyMemberDef rlock_type_members[] = {
579 {"__weaklistoffset__", T_PYSSIZET, offsetof(rlockobject, in_weakreflist), READONLY},
580 {NULL},
581};
582
583static 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
594static 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
602static lockobject *
603newlockobject(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
666typedef struct {
667 PyObject_HEAD
668 PyObject *localdict; /* Borrowed reference! */
669 PyObject *weakreflist; /* List of weak references to self */
670} localdummyobject;
671
672static void
673localdummy_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
682static PyMemberDef local_dummy_type_members[] = {
683 {"__weaklistoffset__", T_PYSSIZET, offsetof(localdummyobject, weakreflist), READONLY},
684 {NULL},
685};
686
687static 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
694static 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
703typedef 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 */
716static PyObject *_ldict(localobject *self, thread_module_state *state);
717static 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 */
721static PyObject *
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
765err:
766 Py_XDECREF(ldict);
767 Py_XDECREF(wr);
768 Py_XDECREF(dummy);
769 return NULL;
770}
771
772static PyObject *
773local_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
835static int
836local_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
845static int
846local_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
872static void
873local_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 */
892static PyObject *
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
930static int
931local_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
960static PyObject *local_getattro(localobject *, PyObject *);
961
962static PyMemberDef local_type_members[] = {
963 {"__weaklistoffset__", T_PYSSIZET, offsetof(localobject, weakreflist), READONLY},
964 {NULL},
965};
966
967static 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
979static 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
987static PyObject *
988local_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. */
1031static PyObject *
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
1058struct bootstate {
1059 PyInterpreterState *interp;
1060 PyObject *func;
1061 PyObject *args;
1062 PyObject *kwargs;
1063 PyThreadState *tstate;
1064 _PyRuntimeState *runtime;
1065};
1066
1067
1068static void
1069thread_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
1078static void
1079thread_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
1113static PyObject *
1114thread_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
1170PyDoc_STRVAR(start_new_doc,
1171"start_new_thread(function, args[, kwargs])\n\
1172(start_new() is an obsolete synonym)\n\
1173\n\
1174Start a new thread and return its identifier. The thread will call the\n\
1175function with positional arguments from the tuple args and keyword arguments\n\
1176taken from the optional dictionary kwargs. The thread exits when the\n\
1177function returns; the return value is ignored. The thread will also exit\n\
1178when the function raises an unhandled exception; a stack trace will be\n\
1179printed unless the exception is SystemExit.\n");
1180
1181static PyObject *
1182thread_PyThread_exit_thread(PyObject *self, PyObject *Py_UNUSED(ignored))
1183{
1184 PyErr_SetNone(PyExc_SystemExit);
1185 return NULL;
1186}
1187
1188PyDoc_STRVAR(exit_doc,
1189"exit()\n\
1190(exit_thread() is an obsolete synonym)\n\
1191\n\
1192This is synonymous to ``raise SystemExit''. It will cause the current\n\
1193thread to exit silently unless the exception is caught.");
1194
1195static PyObject *
1196thread_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
1210PyDoc_STRVAR(interrupt_doc,
1211"interrupt_main(signum=signal.SIGINT, /)\n\
1212\n\
1213Simulate the arrival of the given signal in the main thread,\n\
1214where the corresponding signal handler will be executed.\n\
1215If *signum* is omitted, SIGINT is assumed.\n\
1216A subthread can use this function to interrupt the main thread.\n\
1217\n\
1218Note: the default signal handler for SIGINT raises ``KeyboardInterrupt``."
1219);
1220
1221static lockobject *newlockobject(PyObject *module);
1222
1223static PyObject *
1224thread_PyThread_allocate_lock(PyObject *module, PyObject *Py_UNUSED(ignored))
1225{
1226 return (PyObject *) newlockobject(module);
1227}
1228
1229PyDoc_STRVAR(allocate_doc,
1230"allocate_lock() -> lock object\n\
1231(allocate() is an obsolete synonym)\n\
1232\n\
1233Create a new lock object. See help(type(threading.Lock())) for\n\
1234information about locks.");
1235
1236static PyObject *
1237thread_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
1247PyDoc_STRVAR(get_ident_doc,
1248"get_ident() -> integer\n\
1249\n\
1250Return a non-zero integer that uniquely identifies the current thread\n\
1251amongst other threads that exist simultaneously.\n\
1252This may be used to identify per-thread resources.\n\
1253Even though on some platforms threads identities may appear to be\n\
1254allocated consecutive numbers starting at 1, this behavior should not\n\
1255be relied upon, and the number should be seen purely as a magic cookie.\n\
1256A thread's identity may be reused for another thread after it exits.");
1257
1258#ifdef PY_HAVE_THREAD_NATIVE_ID
1259static PyObject *
1260thread_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
1266PyDoc_STRVAR(get_native_id_doc,
1267"get_native_id() -> integer\n\
1268\n\
1269Return a non-negative integer identifying the thread as reported\n\
1270by the OS (kernel). This may be used to uniquely identify a\n\
1271particular thread within a system.");
1272#endif
1273
1274static PyObject *
1275thread__count(PyObject *self, PyObject *Py_UNUSED(ignored))
1276{
1277 PyInterpreterState *interp = _PyInterpreterState_GET();
1278 return PyLong_FromLong(interp->num_threads);
1279}
1280
1281PyDoc_STRVAR(_count_doc,
1282"_count() -> integer\n\
1283\n\
1284\
1285Return the number of currently running Python threads, excluding\n\
1286the main thread. The returned number comprises all threads created\n\
1287through `start_new_thread()` as well as `threading.Thread`, and not\n\
1288yet finished.\n\
1289\n\
1290This function is meant for internal and specialized purposes only.\n\
1291In most applications `threading.enumerate()` should be used instead.");
1292
1293static void
1294release_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
1314static PyObject *
1315thread__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
1345PyDoc_STRVAR(_set_sentinel_doc,
1346"_set_sentinel() -> lock\n\
1347\n\
1348Set a sentinel lock that will be released when the current thread\n\
1349state is finalized (after it is untied from the interpreter).\n\
1350\n\
1351This is a private API for the threading module.");
1352
1353static PyObject *
1354thread_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
1387PyDoc_STRVAR(stack_size_doc,
1388"stack_size([size]) -> size\n\
1389\n\
1390Return the thread stack size used when creating new threads. The\n\
1391optional size argument specifies the stack size (in bytes) to be used\n\
1392for subsequently created threads, and must be 0 (use platform or\n\
1393configured default) or a positive integer value of at least 32,768 (32k).\n\
1394If changing the thread stack size is unsupported, a ThreadError\n\
1395exception is raised. If the specified size is invalid, a ValueError\n\
1396exception is raised, and the stack size is unmodified. 32k bytes\n\
1397 currently the minimum supported stack size value to guarantee\n\
1398sufficient stack space for the interpreter itself.\n\
1399\n\
1400Note that some platforms may have particular restrictions on values for\n\
1401the stack size, such as requiring a minimum stack size larger than 32 KiB or\n\
1402requiring 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\
1405the suggested approach in the absence of more specific information).");
1406
1407static int
1408thread_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
1467PyDoc_STRVAR(ExceptHookArgs__doc__,
1468"ExceptHookArgs\n\
1469\n\
1470Type used to pass arguments to threading.excepthook.");
1471
1472static PyTypeObject ExceptHookArgsType;
1473
1474static 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
1482static PyStructSequence_Desc ExceptHookArgs_desc = {
1483 .name = "_thread._ExceptHookArgs",
1484 .doc = ExceptHookArgs__doc__,
1485 .fields = ExceptHookArgs_fields,
1486 .n_in_sequence = 4
1487};
1488
1489
1490static PyObject *
1491thread_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
1544PyDoc_STRVAR(excepthook_doc,
1545"excepthook(exc_type, exc_value, exc_traceback, thread)\n\
1546\n\
1547Handle uncaught Thread.run() exception.");
1548
1549static 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
1584static int
1585thread_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
1659static int
1660thread_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
1669static int
1670thread_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
1679static void
1680thread_module_free(void *module)
1681{
1682 thread_module_clear((PyObject *)module);
1683}
1684
1685
1686
1687PyDoc_STRVAR(thread_doc,
1688"This module provides primitive operations to write multi-threaded programs.\n\
1689The 'threading' module provides a more convenient interface.");
1690
1691static PyModuleDef_Slot thread_module_slots[] = {
1692 {Py_mod_exec, thread_module_exec},
1693 {0, NULL}
1694};
1695
1696static 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
1708PyMODINIT_FUNC
1709PyInit__thread(void)
1710{
1711 return PyModuleDef_Init(&thread_module);
1712}
1713