Home | History | Annotate | Download | only in Modules
      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 
     16 static PyObject *ThreadError;
     17 static PyObject *str_dict;
     18 static long nb_threads = 0;
     19 
     20 /* Lock objects */
     21 
     22 typedef struct {
     23     PyObject_HEAD
     24     PyThread_type_lock lock_lock;
     25     PyObject *in_weakreflist;
     26 } lockobject;
     27 
     28 static void
     29 lock_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 
     43 static PyObject *
     44 lock_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 
     58 PyDoc_STRVAR(acquire_doc,
     59 "acquire([wait]) -> bool\n\
     60 (acquire_lock() is an obsolete synonym)\n\
     61 \n\
     62 Lock the lock.  Without argument, this blocks if the lock is already\n\
     63 locked (even by the same thread), waiting for another thread to release\n\
     64 the lock, and return True once the lock is acquired.\n\
     65 With an argument, this will only block if the argument is true,\n\
     66 and the return value reflects whether the lock is acquired.\n\
     67 The blocking operation is not interruptible.");
     68 
     69 static PyObject *
     70 lock_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 
     84 PyDoc_STRVAR(release_doc,
     85 "release()\n\
     86 (release_lock() is an obsolete synonym)\n\
     87 \n\
     88 Release the lock, allowing another thread that is blocked waiting for\n\
     89 the lock to acquire the lock.  The lock must be in the locked state,\n\
     90 but it needn't be locked by the same thread that unlocks it.");
     91 
     92 static PyObject *
     93 lock_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 
    102 PyDoc_STRVAR(locked_doc,
    103 "locked() -> bool\n\
    104 (locked_lock() is an obsolete synonym)\n\
    105 \n\
    106 Return whether the lock is in the locked state.");
    107 
    108 static 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 
    128 static 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 
    160 static lockobject *
    161 newlockobject(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 
    220 typedef struct {
    221     PyObject_HEAD
    222     PyObject *localdict;        /* Borrowed reference! */
    223     PyObject *weakreflist;      /* List of weak references to self */
    224 } localdummyobject;
    225 
    226 static void
    227 localdummy_dealloc(localdummyobject *self)
    228 {
    229     if (self->weakreflist != NULL)
    230         PyObject_ClearWeakRefs((PyObject *) self);
    231     Py_TYPE(self)->tp_free((PyObject*)self);
    232 }
    233 
    234 static 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 
    263 typedef 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 */
    276 static PyObject *_ldict(localobject *self);
    277 static 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 */
    281 static 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 
    320 err:
    321     Py_XDECREF(ldict);
    322     Py_XDECREF(wr);
    323     Py_XDECREF(dummy);
    324     return NULL;
    325 }
    326 
    327 static PyObject *
    328 local_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         int rc = 0;
    338         if (args != NULL)
    339             rc = PyObject_IsTrue(args);
    340         if (rc == 0 && kw != NULL)
    341             rc = PyObject_IsTrue(kw);
    342         if (rc != 0) {
    343             if (rc > 0)
    344                 PyErr_SetString(PyExc_TypeError,
    345                           "Initialization arguments are not supported");
    346             return NULL;
    347         }
    348     }
    349 
    350     self = (localobject *)type->tp_alloc(type, 0);
    351     if (self == NULL)
    352         return NULL;
    353 
    354     Py_XINCREF(args);
    355     self->args = args;
    356     Py_XINCREF(kw);
    357     self->kw = kw;
    358     self->key = PyString_FromFormat("thread.local.%p", self);
    359     if (self->key == NULL)
    360         goto err;
    361 
    362     self->dummies = PyDict_New();
    363     if (self->dummies == NULL)
    364         goto err;
    365 
    366     /* We use a weak reference to self in the callback closure
    367        in order to avoid spurious reference cycles */
    368     wr = PyWeakref_NewRef((PyObject *) self, NULL);
    369     if (wr == NULL)
    370         goto err;
    371     self->wr_callback = PyCFunction_New(&wr_callback_def, wr);
    372     Py_DECREF(wr);
    373     if (self->wr_callback == NULL)
    374         goto err;
    375 
    376     if (_local_create_dummy(self) == NULL)
    377         goto err;
    378 
    379     return (PyObject *)self;
    380 
    381   err:
    382     Py_DECREF(self);
    383     return NULL;
    384 }
    385 
    386 static int
    387 local_traverse(localobject *self, visitproc visit, void *arg)
    388 {
    389     Py_VISIT(self->args);
    390     Py_VISIT(self->kw);
    391     Py_VISIT(self->dummies);
    392     return 0;
    393 }
    394 
    395 static int
    396 local_clear(localobject *self)
    397 {
    398     PyThreadState *tstate;
    399     Py_CLEAR(self->args);
    400     Py_CLEAR(self->kw);
    401     Py_CLEAR(self->dummies);
    402     Py_CLEAR(self->wr_callback);
    403     /* Remove all strong references to dummies from the thread states */
    404     if (self->key
    405         && (tstate = PyThreadState_Get())
    406         && tstate->interp) {
    407         for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
    408             tstate;
    409             tstate = PyThreadState_Next(tstate))
    410             if (tstate->dict &&
    411                 PyDict_GetItem(tstate->dict, self->key))
    412                 PyDict_DelItem(tstate->dict, self->key);
    413     }
    414     return 0;
    415 }
    416 
    417 static void
    418 local_dealloc(localobject *self)
    419 {
    420     /* Weakrefs must be invalidated right now, otherwise they can be used
    421        from code called below, which is very dangerous since Py_REFCNT(self) == 0 */
    422     if (self->weakreflist != NULL)
    423         PyObject_ClearWeakRefs((PyObject *) self);
    424 
    425     PyObject_GC_UnTrack(self);
    426 
    427     local_clear(self);
    428     Py_XDECREF(self->key);
    429     Py_TYPE(self)->tp_free((PyObject*)self);
    430 }
    431 
    432 /* Returns a borrowed reference to the local dict, creating it if necessary */
    433 static PyObject *
    434 _ldict(localobject *self)
    435 {
    436     PyObject *tdict, *ldict, *dummy;
    437 
    438     tdict = PyThreadState_GetDict();
    439     if (tdict == NULL) {
    440         PyErr_SetString(PyExc_SystemError,
    441                         "Couldn't get thread-state dictionary");
    442         return NULL;
    443     }
    444 
    445     dummy = PyDict_GetItem(tdict, self->key);
    446     if (dummy == NULL) {
    447         ldict = _local_create_dummy(self);
    448         if (ldict == NULL)
    449             return NULL;
    450 
    451         if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init &&
    452             Py_TYPE(self)->tp_init((PyObject*)self,
    453                                    self->args, self->kw) < 0) {
    454             /* we need to get rid of ldict from thread so
    455                we create a new one the next time we do an attr
    456                access */
    457             PyDict_DelItem(tdict, self->key);
    458             return NULL;
    459         }
    460     }
    461     else {
    462         assert(Py_TYPE(dummy) == &localdummytype);
    463         ldict = ((localdummyobject *) dummy)->localdict;
    464     }
    465 
    466     return ldict;
    467 }
    468 
    469 static int
    470 local_setattro(localobject *self, PyObject *name, PyObject *v)
    471 {
    472     PyObject *ldict;
    473     int r;
    474 
    475     ldict = _ldict(self);
    476     if (ldict == NULL)
    477         return -1;
    478 
    479     r = PyObject_RichCompareBool(name, str_dict, Py_EQ);
    480     if (r == 1) {
    481         PyErr_Format(PyExc_AttributeError,
    482                      "'%.50s' object attribute '__dict__' is read-only",
    483                      Py_TYPE(self)->tp_name);
    484         return -1;
    485     }
    486     if (r == -1)
    487         return -1;
    488 
    489     return _PyObject_GenericSetAttrWithDict((PyObject *)self, name, v, ldict);
    490 }
    491 
    492 static PyObject *local_getattro(localobject *, PyObject *);
    493 
    494 static PyTypeObject localtype = {
    495     PyVarObject_HEAD_INIT(NULL, 0)
    496     /* tp_name           */ "thread._local",
    497     /* tp_basicsize      */ sizeof(localobject),
    498     /* tp_itemsize       */ 0,
    499     /* tp_dealloc        */ (destructor)local_dealloc,
    500     /* tp_print          */ 0,
    501     /* tp_getattr        */ 0,
    502     /* tp_setattr        */ 0,
    503     /* tp_compare        */ 0,
    504     /* tp_repr           */ 0,
    505     /* tp_as_number      */ 0,
    506     /* tp_as_sequence    */ 0,
    507     /* tp_as_mapping     */ 0,
    508     /* tp_hash           */ 0,
    509     /* tp_call           */ 0,
    510     /* tp_str            */ 0,
    511     /* tp_getattro       */ (getattrofunc)local_getattro,
    512     /* tp_setattro       */ (setattrofunc)local_setattro,
    513     /* tp_as_buffer      */ 0,
    514     /* tp_flags          */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE
    515                                                | Py_TPFLAGS_HAVE_GC,
    516     /* tp_doc            */ "Thread-local data",
    517     /* tp_traverse       */ (traverseproc)local_traverse,
    518     /* tp_clear          */ (inquiry)local_clear,
    519     /* tp_richcompare    */ 0,
    520     /* tp_weaklistoffset */ offsetof(localobject, weakreflist),
    521     /* tp_iter           */ 0,
    522     /* tp_iternext       */ 0,
    523     /* tp_methods        */ 0,
    524     /* tp_members        */ 0,
    525     /* tp_getset         */ 0,
    526     /* tp_base           */ 0,
    527     /* tp_dict           */ 0, /* internal use */
    528     /* tp_descr_get      */ 0,
    529     /* tp_descr_set      */ 0,
    530     /* tp_dictoffset     */ 0,
    531     /* tp_init           */ 0,
    532     /* tp_alloc          */ 0,
    533     /* tp_new            */ local_new,
    534     /* tp_free           */ 0, /* Low-level free-mem routine */
    535     /* tp_is_gc          */ 0, /* For PyObject_IS_GC */
    536 };
    537 
    538 static PyObject *
    539 local_getattro(localobject *self, PyObject *name)
    540 {
    541     PyObject *ldict, *value;
    542     int r;
    543 
    544     ldict = _ldict(self);
    545     if (ldict == NULL)
    546         return NULL;
    547 
    548     r = PyObject_RichCompareBool(name, str_dict, Py_EQ);
    549     if (r == 1) {
    550         Py_INCREF(ldict);
    551         return ldict;
    552     }
    553     if (r == -1)
    554         return NULL;
    555 
    556     if (Py_TYPE(self) != &localtype)
    557         /* use generic lookup for subtypes */
    558         return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict);
    559 
    560     /* Optimization: just look in dict ourselves */
    561     value = PyDict_GetItem(ldict, name);
    562     if (value == NULL)
    563         /* Fall back on generic to get __class__ and __dict__ */
    564         return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict);
    565 
    566     Py_INCREF(value);
    567     return value;
    568 }
    569 
    570 /* Called when a dummy is destroyed. */
    571 static PyObject *
    572 _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref)
    573 {
    574     PyObject *obj;
    575     localobject *self;
    576     assert(PyWeakref_CheckRef(localweakref));
    577     obj = PyWeakref_GET_OBJECT(localweakref);
    578     if (obj == Py_None)
    579         Py_RETURN_NONE;
    580     Py_INCREF(obj);
    581     assert(PyObject_TypeCheck(obj, &localtype));
    582     /* If the thread-local object is still alive and not being cleared,
    583        remove the corresponding local dict */
    584     self = (localobject *) obj;
    585     if (self->dummies != NULL) {
    586         PyObject *ldict;
    587         ldict = PyDict_GetItem(self->dummies, dummyweakref);
    588         if (ldict != NULL) {
    589             PyDict_DelItem(self->dummies, dummyweakref);
    590         }
    591         if (PyErr_Occurred())
    592             PyErr_WriteUnraisable(obj);
    593     }
    594     Py_DECREF(obj);
    595     Py_RETURN_NONE;
    596 }
    597 
    598 /* Module functions */
    599 
    600 struct bootstate {
    601     PyInterpreterState *interp;
    602     PyObject *func;
    603     PyObject *args;
    604     PyObject *keyw;
    605     PyThreadState *tstate;
    606 };
    607 
    608 static void
    609 t_bootstrap(void *boot_raw)
    610 {
    611     struct bootstate *boot = (struct bootstate *) boot_raw;
    612     PyThreadState *tstate;
    613     PyObject *res;
    614 
    615     tstate = boot->tstate;
    616     tstate->thread_id = PyThread_get_thread_ident();
    617     _PyThreadState_Init(tstate);
    618     PyEval_AcquireThread(tstate);
    619     nb_threads++;
    620     res = PyEval_CallObjectWithKeywords(
    621         boot->func, boot->args, boot->keyw);
    622     if (res == NULL) {
    623         if (PyErr_ExceptionMatches(PyExc_SystemExit))
    624             PyErr_Clear();
    625         else {
    626             PyObject *file;
    627             PyObject *exc, *value, *tb;
    628             PyErr_Fetch(&exc, &value, &tb);
    629             PySys_WriteStderr(
    630                 "Unhandled exception in thread started by ");
    631             file = PySys_GetObject("stderr");
    632             if (file)
    633                 PyFile_WriteObject(boot->func, file, 0);
    634             else
    635                 PyObject_Print(boot->func, stderr, 0);
    636             PySys_WriteStderr("\n");
    637             PyErr_Restore(exc, value, tb);
    638             PyErr_PrintEx(0);
    639         }
    640     }
    641     else
    642         Py_DECREF(res);
    643     Py_DECREF(boot->func);
    644     Py_DECREF(boot->args);
    645     Py_XDECREF(boot->keyw);
    646     PyMem_DEL(boot_raw);
    647     nb_threads--;
    648     PyThreadState_Clear(tstate);
    649     PyThreadState_DeleteCurrent();
    650     PyThread_exit_thread();
    651 }
    652 
    653 static PyObject *
    654 thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
    655 {
    656     PyObject *func, *args, *keyw = NULL;
    657     struct bootstate *boot;
    658     long ident;
    659 
    660     if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
    661                            &func, &args, &keyw))
    662         return NULL;
    663     if (!PyCallable_Check(func)) {
    664         PyErr_SetString(PyExc_TypeError,
    665                         "first arg must be callable");
    666         return NULL;
    667     }
    668     if (!PyTuple_Check(args)) {
    669         PyErr_SetString(PyExc_TypeError,
    670                         "2nd arg must be a tuple");
    671         return NULL;
    672     }
    673     if (keyw != NULL && !PyDict_Check(keyw)) {
    674         PyErr_SetString(PyExc_TypeError,
    675                         "optional 3rd arg must be a dictionary");
    676         return NULL;
    677     }
    678     boot = PyMem_NEW(struct bootstate, 1);
    679     if (boot == NULL)
    680         return PyErr_NoMemory();
    681     boot->interp = PyThreadState_GET()->interp;
    682     boot->func = func;
    683     boot->args = args;
    684     boot->keyw = keyw;
    685     boot->tstate = _PyThreadState_Prealloc(boot->interp);
    686     if (boot->tstate == NULL) {
    687         PyMem_DEL(boot);
    688         return PyErr_NoMemory();
    689     }
    690     Py_INCREF(func);
    691     Py_INCREF(args);
    692     Py_XINCREF(keyw);
    693     PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
    694     ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
    695     if (ident == -1) {
    696         PyErr_SetString(ThreadError, "can't start new thread");
    697         Py_DECREF(func);
    698         Py_DECREF(args);
    699         Py_XDECREF(keyw);
    700         PyThreadState_Clear(boot->tstate);
    701         PyMem_DEL(boot);
    702         return NULL;
    703     }
    704     return PyInt_FromLong(ident);
    705 }
    706 
    707 PyDoc_STRVAR(start_new_doc,
    708 "start_new_thread(function, args[, kwargs])\n\
    709 (start_new() is an obsolete synonym)\n\
    710 \n\
    711 Start a new thread and return its identifier.  The thread will call the\n\
    712 function with positional arguments from the tuple args and keyword arguments\n\
    713 taken from the optional dictionary kwargs.  The thread exits when the\n\
    714 function returns; the return value is ignored.  The thread will also exit\n\
    715 when the function raises an unhandled exception; a stack trace will be\n\
    716 printed unless the exception is SystemExit.\n");
    717 
    718 static PyObject *
    719 thread_PyThread_exit_thread(PyObject *self)
    720 {
    721     PyErr_SetNone(PyExc_SystemExit);
    722     return NULL;
    723 }
    724 
    725 PyDoc_STRVAR(exit_doc,
    726 "exit()\n\
    727 (exit_thread() is an obsolete synonym)\n\
    728 \n\
    729 This is synonymous to ``raise SystemExit''.  It will cause the current\n\
    730 thread to exit silently unless the exception is caught.");
    731 
    732 static PyObject *
    733 thread_PyThread_interrupt_main(PyObject * self)
    734 {
    735     PyErr_SetInterrupt();
    736     Py_INCREF(Py_None);
    737     return Py_None;
    738 }
    739 
    740 PyDoc_STRVAR(interrupt_doc,
    741 "interrupt_main()\n\
    742 \n\
    743 Raise a KeyboardInterrupt in the main thread.\n\
    744 A subthread can use this function to interrupt the main thread."
    745 );
    746 
    747 static lockobject *newlockobject(void);
    748 
    749 static PyObject *
    750 thread_PyThread_allocate_lock(PyObject *self)
    751 {
    752     return (PyObject *) newlockobject();
    753 }
    754 
    755 PyDoc_STRVAR(allocate_doc,
    756 "allocate_lock() -> lock object\n\
    757 (allocate() is an obsolete synonym)\n\
    758 \n\
    759 Create a new lock object.  See help(LockType) for information about locks.");
    760 
    761 static PyObject *
    762 thread_get_ident(PyObject *self)
    763 {
    764     long ident;
    765     ident = PyThread_get_thread_ident();
    766     if (ident == -1) {
    767         PyErr_SetString(ThreadError, "no current thread ident");
    768         return NULL;
    769     }
    770     return PyInt_FromLong(ident);
    771 }
    772 
    773 PyDoc_STRVAR(get_ident_doc,
    774 "get_ident() -> integer\n\
    775 \n\
    776 Return a non-zero integer that uniquely identifies the current thread\n\
    777 amongst other threads that exist simultaneously.\n\
    778 This may be used to identify per-thread resources.\n\
    779 Even though on some platforms threads identities may appear to be\n\
    780 allocated consecutive numbers starting at 1, this behavior should not\n\
    781 be relied upon, and the number should be seen purely as a magic cookie.\n\
    782 A thread's identity may be reused for another thread after it exits.");
    783 
    784 static PyObject *
    785 thread__count(PyObject *self)
    786 {
    787     return PyInt_FromLong(nb_threads);
    788 }
    789 
    790 PyDoc_STRVAR(_count_doc,
    791 "_count() -> integer\n\
    792 \n\
    793 \
    794 Return the number of currently running Python threads, excluding \n\
    795 the main thread. The returned number comprises all threads created\n\
    796 through `start_new_thread()` as well as `threading.Thread`, and not\n\
    797 yet finished.\n\
    798 \n\
    799 This function is meant for internal and specialized purposes only.\n\
    800 In most applications `threading.enumerate()` should be used instead.");
    801 
    802 static PyObject *
    803 thread_stack_size(PyObject *self, PyObject *args)
    804 {
    805     size_t old_size;
    806     Py_ssize_t new_size = 0;
    807     int rc;
    808 
    809     if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size))
    810         return NULL;
    811 
    812     if (new_size < 0) {
    813         PyErr_SetString(PyExc_ValueError,
    814                         "size must be 0 or a positive value");
    815         return NULL;
    816     }
    817 
    818     old_size = PyThread_get_stacksize();
    819 
    820     rc = PyThread_set_stacksize((size_t) new_size);
    821     if (rc == -1) {
    822         PyErr_Format(PyExc_ValueError,
    823                      "size not valid: %zd bytes",
    824                      new_size);
    825         return NULL;
    826     }
    827     if (rc == -2) {
    828         PyErr_SetString(ThreadError,
    829                         "setting stack size not supported");
    830         return NULL;
    831     }
    832 
    833     return PyInt_FromSsize_t((Py_ssize_t) old_size);
    834 }
    835 
    836 PyDoc_STRVAR(stack_size_doc,
    837 "stack_size([size]) -> size\n\
    838 \n\
    839 Return the thread stack size used when creating new threads.  The\n\
    840 optional size argument specifies the stack size (in bytes) to be used\n\
    841 for subsequently created threads, and must be 0 (use platform or\n\
    842 configured default) or a positive integer value of at least 32,768 (32k).\n\
    843 If changing the thread stack size is unsupported, a ThreadError\n\
    844 exception is raised.  If the specified size is invalid, a ValueError\n\
    845 exception is raised, and the stack size is unmodified.  32k bytes\n\
    846  currently the minimum supported stack size value to guarantee\n\
    847 sufficient stack space for the interpreter itself.\n\
    848 \n\
    849 Note that some platforms may have particular restrictions on values for\n\
    850 the stack size, such as requiring a minimum stack size larger than 32kB or\n\
    851 requiring allocation in multiples of the system memory page size\n\
    852 - platform documentation should be referred to for more information\n\
    853 (4kB pages are common; using multiples of 4096 for the stack size is\n\
    854 the suggested approach in the absence of more specific information).");
    855 
    856 static PyMethodDef thread_methods[] = {
    857     {"start_new_thread",        (PyCFunction)thread_PyThread_start_new_thread,
    858                             METH_VARARGS,
    859                             start_new_doc},
    860     {"start_new",               (PyCFunction)thread_PyThread_start_new_thread,
    861                             METH_VARARGS,
    862                             start_new_doc},
    863     {"allocate_lock",           (PyCFunction)thread_PyThread_allocate_lock,
    864      METH_NOARGS, allocate_doc},
    865     {"allocate",                (PyCFunction)thread_PyThread_allocate_lock,
    866      METH_NOARGS, allocate_doc},
    867     {"exit_thread",             (PyCFunction)thread_PyThread_exit_thread,
    868      METH_NOARGS, exit_doc},
    869     {"exit",                    (PyCFunction)thread_PyThread_exit_thread,
    870      METH_NOARGS, exit_doc},
    871     {"interrupt_main",          (PyCFunction)thread_PyThread_interrupt_main,
    872      METH_NOARGS, interrupt_doc},
    873     {"get_ident",               (PyCFunction)thread_get_ident,
    874      METH_NOARGS, get_ident_doc},
    875     {"_count",                  (PyCFunction)thread__count,
    876      METH_NOARGS, _count_doc},
    877     {"stack_size",              (PyCFunction)thread_stack_size,
    878                             METH_VARARGS,
    879                             stack_size_doc},
    880     {NULL,                      NULL}           /* sentinel */
    881 };
    882 
    883 
    884 /* Initialization function */
    885 
    886 PyDoc_STRVAR(thread_doc,
    887 "This module provides primitive operations to write multi-threaded programs.\n\
    888 The 'threading' module provides a more convenient interface.");
    889 
    890 PyDoc_STRVAR(lock_doc,
    891 "A lock object is a synchronization primitive.  To create a lock,\n\
    892 call the PyThread_allocate_lock() function.  Methods are:\n\
    893 \n\
    894 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
    895 release() -- unlock of the lock\n\
    896 locked() -- test whether the lock is currently locked\n\
    897 \n\
    898 A lock is not owned by the thread that locked it; another thread may\n\
    899 unlock it.  A thread attempting to lock a lock that it has already locked\n\
    900 will block until another thread unlocks it.  Deadlocks may ensue.");
    901 
    902 PyMODINIT_FUNC
    903 initthread(void)
    904 {
    905     PyObject *m, *d;
    906 
    907     /* Initialize types: */
    908     if (PyType_Ready(&localdummytype) < 0)
    909         return;
    910     if (PyType_Ready(&localtype) < 0)
    911         return;
    912 
    913     /* Create the module and add the functions */
    914     m = Py_InitModule3("thread", thread_methods, thread_doc);
    915     if (m == NULL)
    916         return;
    917 
    918     /* Add a symbolic constant */
    919     d = PyModule_GetDict(m);
    920     ThreadError = PyErr_NewException("thread.error", NULL, NULL);
    921     PyDict_SetItemString(d, "error", ThreadError);
    922     Locktype.tp_doc = lock_doc;
    923     if (PyType_Ready(&Locktype) < 0)
    924         return;
    925     Py_INCREF(&Locktype);
    926     PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
    927 
    928     Py_INCREF(&localtype);
    929     if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
    930         return;
    931 
    932     nb_threads = 0;
    933 
    934     str_dict = PyString_InternFromString("__dict__");
    935     if (str_dict == NULL)
    936         return;
    937 
    938     /* Initialize the C thread library */
    939     PyThread_init_thread();
    940 }
    941