ยปCore Development>Code coverage>Modules/_threadmodule.c

Python code coverage for Modules/_threadmodule.c

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