1
2/* Thread module */
3/* Interface to Sjoerd's portable C thread library */
4
5#include "Python.h"
6#include "structmember.h" /* offsetof */
7
8#ifndef WITH_THREAD
9#error "Error!  The rest of Python is not compiled with thread support."
10#error "Rerun configure, adding a --with-threads option."
11#error "Then run `make clean' followed by `make'."
12#endif
13
14#include "pythread.h"
15
16static PyObject *ThreadError;
17static PyObject *str_dict;
18static long nb_threads = 0;
19
20/* Lock objects */
21
22typedef struct {
23    PyObject_HEAD
24    PyThread_type_lock lock_lock;
25    PyObject *in_weakreflist;
26} lockobject;
27
28static void
29lock_dealloc(lockobject *self)
30{
31    if (self->in_weakreflist != NULL)
32        PyObject_ClearWeakRefs((PyObject *) self);
33    if (self->lock_lock != NULL) {
34        /* Unlock the lock so it's safe to free it */
35        PyThread_acquire_lock(self->lock_lock, 0);
36        PyThread_release_lock(self->lock_lock);
37
38        PyThread_free_lock(self->lock_lock);
39    }
40    PyObject_Del(self);
41}
42
43static PyObject *
44lock_PyThread_acquire_lock(lockobject *self, PyObject *args)
45{
46    int i = 1;
47
48    if (!PyArg_ParseTuple(args, "|i:acquire", &i))
49        return NULL;
50
51    Py_BEGIN_ALLOW_THREADS
52    i = PyThread_acquire_lock(self->lock_lock, i);
53    Py_END_ALLOW_THREADS
54
55    return PyBool_FromLong((long)i);
56}
57
58PyDoc_STRVAR(acquire_doc,
59"acquire([wait]) -> None or bool\n\
60(acquire_lock() is an obsolete synonym)\n\
61\n\
62Lock the lock.  Without argument, this blocks if the lock is already\n\
63locked (even by the same thread), waiting for another thread to release\n\
64the lock, and return None once the lock is acquired.\n\
65With an argument, this will only block if the argument is true,\n\
66and the return value reflects whether the lock is acquired.\n\
67The blocking operation is not interruptible.");
68
69static PyObject *
70lock_PyThread_release_lock(lockobject *self)
71{
72    /* Sanity check: the lock must be locked */
73    if (PyThread_acquire_lock(self->lock_lock, 0)) {
74        PyThread_release_lock(self->lock_lock);
75        PyErr_SetString(ThreadError, "release unlocked lock");
76        return NULL;
77    }
78
79    PyThread_release_lock(self->lock_lock);
80    Py_INCREF(Py_None);
81    return Py_None;
82}
83
84PyDoc_STRVAR(release_doc,
85"release()\n\
86(release_lock() is an obsolete synonym)\n\
87\n\
88Release the lock, allowing another thread that is blocked waiting for\n\
89the lock to acquire the lock.  The lock must be in the locked state,\n\
90but it needn't be locked by the same thread that unlocks it.");
91
92static PyObject *
93lock_locked_lock(lockobject *self)
94{
95    if (PyThread_acquire_lock(self->lock_lock, 0)) {
96        PyThread_release_lock(self->lock_lock);
97        return PyBool_FromLong(0L);
98    }
99    return PyBool_FromLong(1L);
100}
101
102PyDoc_STRVAR(locked_doc,
103"locked() -> bool\n\
104(locked_lock() is an obsolete synonym)\n\
105\n\
106Return whether the lock is in the locked state.");
107
108static PyMethodDef lock_methods[] = {
109    {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
110     METH_VARARGS, acquire_doc},
111    {"acquire",      (PyCFunction)lock_PyThread_acquire_lock,
112     METH_VARARGS, acquire_doc},
113    {"release_lock", (PyCFunction)lock_PyThread_release_lock,
114     METH_NOARGS, release_doc},
115    {"release",      (PyCFunction)lock_PyThread_release_lock,
116     METH_NOARGS, release_doc},
117    {"locked_lock",  (PyCFunction)lock_locked_lock,
118     METH_NOARGS, locked_doc},
119    {"locked",       (PyCFunction)lock_locked_lock,
120     METH_NOARGS, locked_doc},
121    {"__enter__",    (PyCFunction)lock_PyThread_acquire_lock,
122     METH_VARARGS, acquire_doc},
123    {"__exit__",    (PyCFunction)lock_PyThread_release_lock,
124     METH_VARARGS, release_doc},
125    {NULL}              /* sentinel */
126};
127
128static PyTypeObject Locktype = {
129    PyVarObject_HEAD_INIT(&PyType_Type, 0)
130    "thread.lock",                      /*tp_name*/
131    sizeof(lockobject),                 /*tp_size*/
132    0,                                  /*tp_itemsize*/
133    /* methods */
134    (destructor)lock_dealloc,           /*tp_dealloc*/
135    0,                                  /*tp_print*/
136    0,                                  /*tp_getattr*/
137    0,                                  /*tp_setattr*/
138    0,                                  /*tp_compare*/
139    0,                                  /*tp_repr*/
140    0,                                  /* tp_as_number */
141    0,                                  /* tp_as_sequence */
142    0,                                  /* tp_as_mapping */
143    0,                                  /* tp_hash */
144    0,                                  /* tp_call */
145    0,                                  /* tp_str */
146    0,                                  /* tp_getattro */
147    0,                                  /* tp_setattro */
148    0,                                  /* tp_as_buffer */
149    Py_TPFLAGS_HAVE_WEAKREFS,       /* tp_flags */
150    0,                                  /* tp_doc */
151    0,                                  /* tp_traverse */
152    0,                                  /* tp_clear */
153    0,                                  /* tp_richcompare */
154    offsetof(lockobject, in_weakreflist),       /* tp_weaklistoffset */
155    0,                                  /* tp_iter */
156    0,                                  /* tp_iternext */
157    lock_methods,                       /* tp_methods */
158};
159
160static lockobject *
161newlockobject(void)
162{
163    lockobject *self;
164    self = PyObject_New(lockobject, &Locktype);
165    if (self == NULL)
166        return NULL;
167    self->lock_lock = PyThread_allocate_lock();
168    self->in_weakreflist = NULL;
169    if (self->lock_lock == NULL) {
170        Py_DECREF(self);
171        PyErr_SetString(ThreadError, "can't allocate lock");
172        return NULL;
173    }
174    return self;
175}
176
177/* Thread-local objects */
178
179#include "structmember.h"
180
181/* Quick overview:
182
183   We need to be able to reclaim reference cycles as soon as possible
184   (both when a thread is being terminated, or a thread-local object
185    becomes unreachable from user data).  Constraints:
186   - it must not be possible for thread-state dicts to be involved in
187     reference cycles (otherwise the cyclic GC will refuse to consider
188     objects referenced from a reachable thread-state dict, even though
189     local_dealloc would clear them)
190   - the death of a thread-state dict must still imply destruction of the
191     corresponding local dicts in all thread-local objects.
192
193   Our implementation uses small "localdummy" objects in order to break
194   the reference chain. These trivial objects are hashable (using the
195   default scheme of identity hashing) and weakrefable.
196   Each thread-state holds a separate localdummy for each local object
197   (as a /strong reference/),
198   and each thread-local object holds a dict mapping /weak references/
199   of localdummies to local dicts.
200
201   Therefore:
202   - only the thread-state dict holds a strong reference to the dummies
203   - only the thread-local object holds a strong reference to the local dicts
204   - only outside objects (application- or library-level) hold strong
205     references to the thread-local objects
206   - as soon as a thread-state dict is destroyed, the weakref callbacks of all
207     dummies attached to that thread are called, and destroy the corresponding
208     local dicts from thread-local objects
209   - as soon as a thread-local object is destroyed, its local dicts are
210     destroyed and its dummies are manually removed from all thread states
211   - the GC can do its work correctly when a thread-local object is dangling,
212     without any interference from the thread-state dicts
213
214   As an additional optimization, each localdummy holds a borrowed reference
215   to the corresponding localdict.  This borrowed reference is only used
216   by the thread-local object which has created the localdummy, which should
217   guarantee that the localdict still exists when accessed.
218*/
219
220typedef struct {
221    PyObject_HEAD
222    PyObject *localdict;        /* Borrowed reference! */
223    PyObject *weakreflist;      /* List of weak references to self */
224} localdummyobject;
225
226static void
227localdummy_dealloc(localdummyobject *self)
228{
229    if (self->weakreflist != NULL)
230        PyObject_ClearWeakRefs((PyObject *) self);
231    Py_TYPE(self)->tp_free((PyObject*)self);
232}
233
234static PyTypeObject localdummytype = {
235    PyVarObject_HEAD_INIT(NULL, 0)
236    /* tp_name           */ "_thread._localdummy",
237    /* tp_basicsize      */ sizeof(localdummyobject),
238    /* tp_itemsize       */ 0,
239    /* tp_dealloc        */ (destructor)localdummy_dealloc,
240    /* tp_print          */ 0,
241    /* tp_getattr        */ 0,
242    /* tp_setattr        */ 0,
243    /* tp_reserved       */ 0,
244    /* tp_repr           */ 0,
245    /* tp_as_number      */ 0,
246    /* tp_as_sequence    */ 0,
247    /* tp_as_mapping     */ 0,
248    /* tp_hash           */ 0,
249    /* tp_call           */ 0,
250    /* tp_str            */ 0,
251    /* tp_getattro       */ 0,
252    /* tp_setattro       */ 0,
253    /* tp_as_buffer      */ 0,
254    /* tp_flags          */ Py_TPFLAGS_DEFAULT,
255    /* tp_doc            */ "Thread-local dummy",
256    /* tp_traverse       */ 0,
257    /* tp_clear          */ 0,
258    /* tp_richcompare    */ 0,
259    /* tp_weaklistoffset */ offsetof(localdummyobject, weakreflist)
260};
261
262
263typedef struct {
264    PyObject_HEAD
265    PyObject *key;
266    PyObject *args;
267    PyObject *kw;
268    PyObject *weakreflist;      /* List of weak references to self */
269    /* A {localdummy weakref -> localdict} dict */
270    PyObject *dummies;
271    /* The callback for weakrefs to localdummies */
272    PyObject *wr_callback;
273} localobject;
274
275/* Forward declaration */
276static PyObject *_ldict(localobject *self);
277static PyObject *_localdummy_destroyed(PyObject *meth_self, PyObject *dummyweakref);
278
279/* Create and register the dummy for the current thread.
280   Returns a borrowed reference of the corresponding local dict */
281static PyObject *
282_local_create_dummy(localobject *self)
283{
284    PyObject *tdict, *ldict = NULL, *wr = NULL;
285    localdummyobject *dummy = NULL;
286    int r;
287
288    tdict = PyThreadState_GetDict();
289    if (tdict == NULL) {
290        PyErr_SetString(PyExc_SystemError,
291                        "Couldn't get thread-state dictionary");
292        goto err;
293    }
294
295    ldict = PyDict_New();
296    if (ldict == NULL)
297        goto err;
298    dummy = (localdummyobject *) localdummytype.tp_alloc(&localdummytype, 0);
299    if (dummy == NULL)
300        goto err;
301    dummy->localdict = ldict;
302    wr = PyWeakref_NewRef((PyObject *) dummy, self->wr_callback);
303    if (wr == NULL)
304        goto err;
305
306    /* As a side-effect, this will cache the weakref's hash before the
307       dummy gets deleted */
308    r = PyDict_SetItem(self->dummies, wr, ldict);
309    if (r < 0)
310        goto err;
311    Py_CLEAR(wr);
312    r = PyDict_SetItem(tdict, self->key, (PyObject *) dummy);
313    if (r < 0)
314        goto err;
315    Py_CLEAR(dummy);
316
317    Py_DECREF(ldict);
318    return ldict;
319
320err:
321    Py_XDECREF(ldict);
322    Py_XDECREF(wr);
323    Py_XDECREF(dummy);
324    return NULL;
325}
326
327static PyObject *
328local_new(PyTypeObject *type, PyObject *args, PyObject *kw)
329{
330    localobject *self;
331    PyObject *wr;
332    static PyMethodDef wr_callback_def = {
333        "_localdummy_destroyed", (PyCFunction) _localdummy_destroyed, METH_O
334    };
335
336    if (type->tp_init == PyBaseObject_Type.tp_init
337        && ((args && PyObject_IsTrue(args))
338        || (kw && PyObject_IsTrue(kw)))) {
339        PyErr_SetString(PyExc_TypeError,
340                  "Initialization arguments are not supported");
341        return NULL;
342    }
343
344    self = (localobject *)type->tp_alloc(type, 0);
345    if (self == NULL)
346        return NULL;
347
348    Py_XINCREF(args);
349    self->args = args;
350    Py_XINCREF(kw);
351    self->kw = kw;
352    self->key = PyString_FromFormat("thread.local.%p", self);
353    if (self->key == NULL)
354        goto err;
355
356    self->dummies = PyDict_New();
357    if (self->dummies == NULL)
358        goto err;
359
360    /* We use a weak reference to self in the callback closure
361       in order to avoid spurious reference cycles */
362    wr = PyWeakref_NewRef((PyObject *) self, NULL);
363    if (wr == NULL)
364        goto err;
365    self->wr_callback = PyCFunction_New(&wr_callback_def, wr);
366    Py_DECREF(wr);
367    if (self->wr_callback == NULL)
368        goto err;
369
370    if (_local_create_dummy(self) == NULL)
371        goto err;
372
373    return (PyObject *)self;
374
375  err:
376    Py_DECREF(self);
377    return NULL;
378}
379
380static int
381local_traverse(localobject *self, visitproc visit, void *arg)
382{
383    Py_VISIT(self->args);
384    Py_VISIT(self->kw);
385    Py_VISIT(self->dummies);
386    return 0;
387}
388
389static int
390local_clear(localobject *self)
391{
392    PyThreadState *tstate;
393    Py_CLEAR(self->args);
394    Py_CLEAR(self->kw);
395    Py_CLEAR(self->dummies);
396    Py_CLEAR(self->wr_callback);
397    /* Remove all strong references to dummies from the thread states */
398    if (self->key
399        && (tstate = PyThreadState_Get())
400        && tstate->interp) {
401        for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
402            tstate;
403            tstate = PyThreadState_Next(tstate))
404            if (tstate->dict &&
405                PyDict_GetItem(tstate->dict, self->key))
406                PyDict_DelItem(tstate->dict, self->key);
407    }
408    return 0;
409}
410
411static void
412local_dealloc(localobject *self)
413{
414    /* Weakrefs must be invalidated right now, otherwise they can be used
415       from code called below, which is very dangerous since Py_REFCNT(self) == 0 */
416    if (self->weakreflist != NULL)
417        PyObject_ClearWeakRefs((PyObject *) self);
418
419    PyObject_GC_UnTrack(self);
420
421    local_clear(self);
422    Py_XDECREF(self->key);
423    Py_TYPE(self)->tp_free((PyObject*)self);
424}
425
426/* Returns a borrowed reference to the local dict, creating it if necessary */
427static PyObject *
428_ldict(localobject *self)
429{
430    PyObject *tdict, *ldict, *dummy;
431
432    tdict = PyThreadState_GetDict();
433    if (tdict == NULL) {
434        PyErr_SetString(PyExc_SystemError,
435                        "Couldn't get thread-state dictionary");
436        return NULL;
437    }
438
439    dummy = PyDict_GetItem(tdict, self->key);
440    if (dummy == NULL) {
441        ldict = _local_create_dummy(self);
442        if (ldict == NULL)
443            return NULL;
444
445        if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init &&
446            Py_TYPE(self)->tp_init((PyObject*)self,
447                                   self->args, self->kw) < 0) {
448            /* we need to get rid of ldict from thread so
449               we create a new one the next time we do an attr
450               access */
451            PyDict_DelItem(tdict, self->key);
452            return NULL;
453        }
454    }
455    else {
456        assert(Py_TYPE(dummy) == &localdummytype);
457        ldict = ((localdummyobject *) dummy)->localdict;
458    }
459
460    return ldict;
461}
462
463static int
464local_setattro(localobject *self, PyObject *name, PyObject *v)
465{
466    PyObject *ldict;
467    int r;
468
469    ldict = _ldict(self);
470    if (ldict == NULL)
471        return -1;
472
473    r = PyObject_RichCompareBool(name, str_dict, Py_EQ);
474    if (r == 1) {
475        PyErr_Format(PyExc_AttributeError,
476                     "'%.50s' object attribute '__dict__' is read-only",
477                     Py_TYPE(self)->tp_name);
478        return -1;
479    }
480    if (r == -1)
481        return -1;
482
483    return _PyObject_GenericSetAttrWithDict((PyObject *)self, name, v, ldict);
484}
485
486static PyObject *local_getattro(localobject *, PyObject *);
487
488static PyTypeObject localtype = {
489    PyVarObject_HEAD_INIT(NULL, 0)
490    /* tp_name           */ "thread._local",
491    /* tp_basicsize      */ sizeof(localobject),
492    /* tp_itemsize       */ 0,
493    /* tp_dealloc        */ (destructor)local_dealloc,
494    /* tp_print          */ 0,
495    /* tp_getattr        */ 0,
496    /* tp_setattr        */ 0,
497    /* tp_compare        */ 0,
498    /* tp_repr           */ 0,
499    /* tp_as_number      */ 0,
500    /* tp_as_sequence    */ 0,
501    /* tp_as_mapping     */ 0,
502    /* tp_hash           */ 0,
503    /* tp_call           */ 0,
504    /* tp_str            */ 0,
505    /* tp_getattro       */ (getattrofunc)local_getattro,
506    /* tp_setattro       */ (setattrofunc)local_setattro,
507    /* tp_as_buffer      */ 0,
508    /* tp_flags          */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
509                                               | Py_TPFLAGS_HAVE_GC,
510    /* tp_doc            */ "Thread-local data",
511    /* tp_traverse       */ (traverseproc)local_traverse,
512    /* tp_clear          */ (inquiry)local_clear,
513    /* tp_richcompare    */ 0,
514    /* tp_weaklistoffset */ offsetof(localobject, weakreflist),
515    /* tp_iter           */ 0,
516    /* tp_iternext       */ 0,
517    /* tp_methods        */ 0,
518    /* tp_members        */ 0,
519    /* tp_getset         */ 0,
520    /* tp_base           */ 0,
521    /* tp_dict           */ 0, /* internal use */
522    /* tp_descr_get      */ 0,
523    /* tp_descr_set      */ 0,
524    /* tp_dictoffset     */ 0,
525    /* tp_init           */ 0,
526    /* tp_alloc          */ 0,
527    /* tp_new            */ local_new,
528    /* tp_free           */ 0, /* Low-level free-mem routine */
529    /* tp_is_gc          */ 0, /* For PyObject_IS_GC */
530};
531
532static PyObject *
533local_getattro(localobject *self, PyObject *name)
534{
535    PyObject *ldict, *value;
536    int r;
537
538    ldict = _ldict(self);
539    if (ldict == NULL)
540        return NULL;
541
542    r = PyObject_RichCompareBool(name, str_dict, Py_EQ);
543    if (r == 1) {
544        Py_INCREF(ldict);
545        return ldict;
546    }
547    if (r == -1)
548        return NULL;
549
550    if (Py_TYPE(self) != &localtype)
551        /* use generic lookup for subtypes */
552        return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict);
553
554    /* Optimization: just look in dict ourselves */
555    value = PyDict_GetItem(ldict, name);
556    if (value == NULL)
557        /* Fall back on generic to get __class__ and __dict__ */
558        return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict);
559
560    Py_INCREF(value);
561    return value;
562}
563
564/* Called when a dummy is destroyed. */
565static PyObject *
566_localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref)
567{
568    PyObject *obj;
569    localobject *self;
570    assert(PyWeakref_CheckRef(localweakref));
571    obj = PyWeakref_GET_OBJECT(localweakref);
572    if (obj == Py_None)
573        Py_RETURN_NONE;
574    Py_INCREF(obj);
575    assert(PyObject_TypeCheck(obj, &localtype));
576    /* If the thread-local object is still alive and not being cleared,
577       remove the corresponding local dict */
578    self = (localobject *) obj;
579    if (self->dummies != NULL) {
580        PyObject *ldict;
581        ldict = PyDict_GetItem(self->dummies, dummyweakref);
582        if (ldict != NULL) {
583            PyDict_DelItem(self->dummies, dummyweakref);
584        }
585        if (PyErr_Occurred())
586            PyErr_WriteUnraisable(obj);
587    }
588    Py_DECREF(obj);
589    Py_RETURN_NONE;
590}
591
592/* Module functions */
593
594struct bootstate {
595    PyInterpreterState *interp;
596    PyObject *func;
597    PyObject *args;
598    PyObject *keyw;
599    PyThreadState *tstate;
600};
601
602static void
603t_bootstrap(void *boot_raw)
604{
605    struct bootstate *boot = (struct bootstate *) boot_raw;
606    PyThreadState *tstate;
607    PyObject *res;
608
609    tstate = boot->tstate;
610    tstate->thread_id = PyThread_get_thread_ident();
611    _PyThreadState_Init(tstate);
612    PyEval_AcquireThread(tstate);
613    nb_threads++;
614    res = PyEval_CallObjectWithKeywords(
615        boot->func, boot->args, boot->keyw);
616    if (res == NULL) {
617        if (PyErr_ExceptionMatches(PyExc_SystemExit))
618            PyErr_Clear();
619        else {
620            PyObject *file;
621            PySys_WriteStderr(
622                "Unhandled exception in thread started by ");
623            file = PySys_GetObject("stderr");
624            if (file)
625                PyFile_WriteObject(boot->func, file, 0);
626            else
627                PyObject_Print(boot->func, stderr, 0);
628            PySys_WriteStderr("\n");
629            PyErr_PrintEx(0);
630        }
631    }
632    else
633        Py_DECREF(res);
634    Py_DECREF(boot->func);
635    Py_DECREF(boot->args);
636    Py_XDECREF(boot->keyw);
637    PyMem_DEL(boot_raw);
638    nb_threads--;
639    PyThreadState_Clear(tstate);
640    PyThreadState_DeleteCurrent();
641    PyThread_exit_thread();
642}
643
644static PyObject *
645thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
646{
647    PyObject *func, *args, *keyw = NULL;
648    struct bootstate *boot;
649    long ident;
650
651    if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
652                           &func, &args, &keyw))
653        return NULL;
654    if (!PyCallable_Check(func)) {
655        PyErr_SetString(PyExc_TypeError,
656                        "first arg must be callable");
657        return NULL;
658    }
659    if (!PyTuple_Check(args)) {
660        PyErr_SetString(PyExc_TypeError,
661                        "2nd arg must be a tuple");
662        return NULL;
663    }
664    if (keyw != NULL && !PyDict_Check(keyw)) {
665        PyErr_SetString(PyExc_TypeError,
666                        "optional 3rd arg must be a dictionary");
667        return NULL;
668    }
669    boot = PyMem_NEW(struct bootstate, 1);
670    if (boot == NULL)
671        return PyErr_NoMemory();
672    boot->interp = PyThreadState_GET()->interp;
673    boot->func = func;
674    boot->args = args;
675    boot->keyw = keyw;
676    boot->tstate = _PyThreadState_Prealloc(boot->interp);
677    if (boot->tstate == NULL) {
678        PyMem_DEL(boot);
679        return PyErr_NoMemory();
680    }
681    Py_INCREF(func);
682    Py_INCREF(args);
683    Py_XINCREF(keyw);
684    PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
685    ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
686    if (ident == -1) {
687        PyErr_SetString(ThreadError, "can't start new thread");
688        Py_DECREF(func);
689        Py_DECREF(args);
690        Py_XDECREF(keyw);
691        PyThreadState_Clear(boot->tstate);
692        PyMem_DEL(boot);
693        return NULL;
694    }
695    return PyInt_FromLong(ident);
696}
697
698PyDoc_STRVAR(start_new_doc,
699"start_new_thread(function, args[, kwargs])\n\
700(start_new() is an obsolete synonym)\n\
701\n\
702Start a new thread and return its identifier.  The thread will call the\n\
703function with positional arguments from the tuple args and keyword arguments\n\
704taken from the optional dictionary kwargs.  The thread exits when the\n\
705function returns; the return value is ignored.  The thread will also exit\n\
706when the function raises an unhandled exception; a stack trace will be\n\
707printed unless the exception is SystemExit.\n");
708
709static PyObject *
710thread_PyThread_exit_thread(PyObject *self)
711{
712    PyErr_SetNone(PyExc_SystemExit);
713    return NULL;
714}
715
716PyDoc_STRVAR(exit_doc,
717"exit()\n\
718(PyThread_exit_thread() is an obsolete synonym)\n\
719\n\
720This is synonymous to ``raise SystemExit''.  It will cause the current\n\
721thread to exit silently unless the exception is caught.");
722
723static PyObject *
724thread_PyThread_interrupt_main(PyObject * self)
725{
726    PyErr_SetInterrupt();
727    Py_INCREF(Py_None);
728    return Py_None;
729}
730
731PyDoc_STRVAR(interrupt_doc,
732"interrupt_main()\n\
733\n\
734Raise a KeyboardInterrupt in the main thread.\n\
735A subthread can use this function to interrupt the main thread."
736);
737
738static lockobject *newlockobject(void);
739
740static PyObject *
741thread_PyThread_allocate_lock(PyObject *self)
742{
743    return (PyObject *) newlockobject();
744}
745
746PyDoc_STRVAR(allocate_doc,
747"allocate_lock() -> lock object\n\
748(allocate() is an obsolete synonym)\n\
749\n\
750Create a new lock object.  See help(LockType) for information about locks.");
751
752static PyObject *
753thread_get_ident(PyObject *self)
754{
755    long ident;
756    ident = PyThread_get_thread_ident();
757    if (ident == -1) {
758        PyErr_SetString(ThreadError, "no current thread ident");
759        return NULL;
760    }
761    return PyInt_FromLong(ident);
762}
763
764PyDoc_STRVAR(get_ident_doc,
765"get_ident() -> integer\n\
766\n\
767Return a non-zero integer that uniquely identifies the current thread\n\
768amongst other threads that exist simultaneously.\n\
769This may be used to identify per-thread resources.\n\
770Even though on some platforms threads identities may appear to be\n\
771allocated consecutive numbers starting at 1, this behavior should not\n\
772be relied upon, and the number should be seen purely as a magic cookie.\n\
773A thread's identity may be reused for another thread after it exits.");
774
775static PyObject *
776thread__count(PyObject *self)
777{
778    return PyInt_FromLong(nb_threads);
779}
780
781PyDoc_STRVAR(_count_doc,
782"_count() -> integer\n\
783\n\
784\
785Return the number of currently running Python threads, excluding \n\
786the main thread. The returned number comprises all threads created\n\
787through `start_new_thread()` as well as `threading.Thread`, and not\n\
788yet finished.\n\
789\n\
790This function is meant for internal and specialized purposes only.\n\
791In most applications `threading.enumerate()` should be used instead.");
792
793static PyObject *
794thread_stack_size(PyObject *self, PyObject *args)
795{
796    size_t old_size;
797    Py_ssize_t new_size = 0;
798    int rc;
799
800    if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size))
801        return NULL;
802
803    if (new_size < 0) {
804        PyErr_SetString(PyExc_ValueError,
805                        "size must be 0 or a positive value");
806        return NULL;
807    }
808
809    old_size = PyThread_get_stacksize();
810
811    rc = PyThread_set_stacksize((size_t) new_size);
812    if (rc == -1) {
813        PyErr_Format(PyExc_ValueError,
814                     "size not valid: %zd bytes",
815                     new_size);
816        return NULL;
817    }
818    if (rc == -2) {
819        PyErr_SetString(ThreadError,
820                        "setting stack size not supported");
821        return NULL;
822    }
823
824    return PyInt_FromSsize_t((Py_ssize_t) old_size);
825}
826
827PyDoc_STRVAR(stack_size_doc,
828"stack_size([size]) -> size\n\
829\n\
830Return the thread stack size used when creating new threads.  The\n\
831optional size argument specifies the stack size (in bytes) to be used\n\
832for subsequently created threads, and must be 0 (use platform or\n\
833configured default) or a positive integer value of at least 32,768 (32k).\n\
834If changing the thread stack size is unsupported, a ThreadError\n\
835exception is raised.  If the specified size is invalid, a ValueError\n\
836exception is raised, and the stack size is unmodified.  32k bytes\n\
837 currently the minimum supported stack size value to guarantee\n\
838sufficient stack space for the interpreter itself.\n\
839\n\
840Note that some platforms may have particular restrictions on values for\n\
841the stack size, such as requiring a minimum stack size larger than 32kB or\n\
842requiring allocation in multiples of the system memory page size\n\
843- platform documentation should be referred to for more information\n\
844(4kB pages are common; using multiples of 4096 for the stack size is\n\
845the suggested approach in the absence of more specific information).");
846
847static PyMethodDef thread_methods[] = {
848    {"start_new_thread",        (PyCFunction)thread_PyThread_start_new_thread,
849                            METH_VARARGS,
850                            start_new_doc},
851    {"start_new",               (PyCFunction)thread_PyThread_start_new_thread,
852                            METH_VARARGS,
853                            start_new_doc},
854    {"allocate_lock",           (PyCFunction)thread_PyThread_allocate_lock,
855     METH_NOARGS, allocate_doc},
856    {"allocate",                (PyCFunction)thread_PyThread_allocate_lock,
857     METH_NOARGS, allocate_doc},
858    {"exit_thread",             (PyCFunction)thread_PyThread_exit_thread,
859     METH_NOARGS, exit_doc},
860    {"exit",                    (PyCFunction)thread_PyThread_exit_thread,
861     METH_NOARGS, exit_doc},
862    {"interrupt_main",          (PyCFunction)thread_PyThread_interrupt_main,
863     METH_NOARGS, interrupt_doc},
864    {"get_ident",               (PyCFunction)thread_get_ident,
865     METH_NOARGS, get_ident_doc},
866    {"_count",                  (PyCFunction)thread__count,
867     METH_NOARGS, _count_doc},
868    {"stack_size",              (PyCFunction)thread_stack_size,
869                            METH_VARARGS,
870                            stack_size_doc},
871    {NULL,                      NULL}           /* sentinel */
872};
873
874
875/* Initialization function */
876
877PyDoc_STRVAR(thread_doc,
878"This module provides primitive operations to write multi-threaded programs.\n\
879The 'threading' module provides a more convenient interface.");
880
881PyDoc_STRVAR(lock_doc,
882"A lock object is a synchronization primitive.  To create a lock,\n\
883call the PyThread_allocate_lock() function.  Methods are:\n\
884\n\
885acquire() -- lock the lock, possibly blocking until it can be obtained\n\
886release() -- unlock of the lock\n\
887locked() -- test whether the lock is currently locked\n\
888\n\
889A lock is not owned by the thread that locked it; another thread may\n\
890unlock it.  A thread attempting to lock a lock that it has already locked\n\
891will block until another thread unlocks it.  Deadlocks may ensue.");
892
893PyMODINIT_FUNC
894initthread(void)
895{
896    PyObject *m, *d;
897
898    /* Initialize types: */
899    if (PyType_Ready(&localdummytype) < 0)
900        return;
901    if (PyType_Ready(&localtype) < 0)
902        return;
903
904    /* Create the module and add the functions */
905    m = Py_InitModule3("thread", thread_methods, thread_doc);
906    if (m == NULL)
907        return;
908
909    /* Add a symbolic constant */
910    d = PyModule_GetDict(m);
911    ThreadError = PyErr_NewException("thread.error", NULL, NULL);
912    PyDict_SetItemString(d, "error", ThreadError);
913    Locktype.tp_doc = lock_doc;
914    if (PyType_Ready(&Locktype) < 0)
915        return;
916    Py_INCREF(&Locktype);
917    PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
918
919    Py_INCREF(&localtype);
920    if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
921        return;
922
923    nb_threads = 0;
924
925    str_dict = PyString_InternFromString("__dict__");
926    if (str_dict == NULL)
927        return;
928
929    /* Initialize the C thread library */
930    PyThread_init_thread();
931}
932