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