Issue #7117, continued: Remove substitution of %g-style formatting for
[python.git] / Modules / threadmodule.c
blobc682af22ef23e51467d2a05a19d3d4f0a841d51b
2 /* Thread module */
3 /* Interface to Sjoerd's portable C thread library */
5 #include "Python.h"
6 #include "structmember.h" /* offsetof */
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
14 #include "pythread.h"
16 static PyObject *ThreadError;
17 static long nb_threads = 0;
19 /* Lock objects */
21 typedef struct {
22 PyObject_HEAD
23 PyThread_type_lock lock_lock;
24 PyObject *in_weakreflist;
25 } lockobject;
27 static void
28 lock_dealloc(lockobject *self)
30 assert(self->lock_lock);
31 if (self->in_weakreflist != NULL)
32 PyObject_ClearWeakRefs((PyObject *) self);
33 /* Unlock the lock so it's safe to free it */
34 PyThread_acquire_lock(self->lock_lock, 0);
35 PyThread_release_lock(self->lock_lock);
37 PyThread_free_lock(self->lock_lock);
38 PyObject_Del(self);
41 static PyObject *
42 lock_PyThread_acquire_lock(lockobject *self, PyObject *args)
44 int i = 1;
46 if (!PyArg_ParseTuple(args, "|i:acquire", &i))
47 return NULL;
49 Py_BEGIN_ALLOW_THREADS
50 i = PyThread_acquire_lock(self->lock_lock, i);
51 Py_END_ALLOW_THREADS
53 return PyBool_FromLong((long)i);
56 PyDoc_STRVAR(acquire_doc,
57 "acquire([wait]) -> None or bool\n\
58 (acquire_lock() is an obsolete synonym)\n\
59 \n\
60 Lock the lock. Without argument, this blocks if the lock is already\n\
61 locked (even by the same thread), waiting for another thread to release\n\
62 the lock, and return None once the lock is acquired.\n\
63 With an argument, this will only block if the argument is true,\n\
64 and the return value reflects whether the lock is acquired.\n\
65 The blocking operation is not interruptible.");
67 static PyObject *
68 lock_PyThread_release_lock(lockobject *self)
70 /* Sanity check: the lock must be locked */
71 if (PyThread_acquire_lock(self->lock_lock, 0)) {
72 PyThread_release_lock(self->lock_lock);
73 PyErr_SetString(ThreadError, "release unlocked lock");
74 return NULL;
77 PyThread_release_lock(self->lock_lock);
78 Py_INCREF(Py_None);
79 return Py_None;
82 PyDoc_STRVAR(release_doc,
83 "release()\n\
84 (release_lock() is an obsolete synonym)\n\
85 \n\
86 Release the lock, allowing another thread that is blocked waiting for\n\
87 the lock to acquire the lock. The lock must be in the locked state,\n\
88 but it needn't be locked by the same thread that unlocks it.");
90 static PyObject *
91 lock_locked_lock(lockobject *self)
93 if (PyThread_acquire_lock(self->lock_lock, 0)) {
94 PyThread_release_lock(self->lock_lock);
95 return PyBool_FromLong(0L);
97 return PyBool_FromLong(1L);
100 PyDoc_STRVAR(locked_doc,
101 "locked() -> bool\n\
102 (locked_lock() is an obsolete synonym)\n\
104 Return whether the lock is in the locked state.");
106 static PyMethodDef lock_methods[] = {
107 {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
108 METH_VARARGS, acquire_doc},
109 {"acquire", (PyCFunction)lock_PyThread_acquire_lock,
110 METH_VARARGS, acquire_doc},
111 {"release_lock", (PyCFunction)lock_PyThread_release_lock,
112 METH_NOARGS, release_doc},
113 {"release", (PyCFunction)lock_PyThread_release_lock,
114 METH_NOARGS, release_doc},
115 {"locked_lock", (PyCFunction)lock_locked_lock,
116 METH_NOARGS, locked_doc},
117 {"locked", (PyCFunction)lock_locked_lock,
118 METH_NOARGS, locked_doc},
119 {"__enter__", (PyCFunction)lock_PyThread_acquire_lock,
120 METH_VARARGS, acquire_doc},
121 {"__exit__", (PyCFunction)lock_PyThread_release_lock,
122 METH_VARARGS, release_doc},
123 {NULL} /* sentinel */
126 static PyTypeObject Locktype = {
127 PyVarObject_HEAD_INIT(&PyType_Type, 0)
128 "thread.lock", /*tp_name*/
129 sizeof(lockobject), /*tp_size*/
130 0, /*tp_itemsize*/
131 /* methods */
132 (destructor)lock_dealloc, /*tp_dealloc*/
133 0, /*tp_print*/
134 0, /*tp_getattr*/
135 0, /*tp_setattr*/
136 0, /*tp_compare*/
137 0, /*tp_repr*/
138 0, /* tp_as_number */
139 0, /* tp_as_sequence */
140 0, /* tp_as_mapping */
141 0, /* tp_hash */
142 0, /* tp_call */
143 0, /* tp_str */
144 0, /* tp_getattro */
145 0, /* tp_setattro */
146 0, /* tp_as_buffer */
147 Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */
148 0, /* tp_doc */
149 0, /* tp_traverse */
150 0, /* tp_clear */
151 0, /* tp_richcompare */
152 offsetof(lockobject, in_weakreflist), /* tp_weaklistoffset */
153 0, /* tp_iter */
154 0, /* tp_iternext */
155 lock_methods, /* tp_methods */
158 static lockobject *
159 newlockobject(void)
161 lockobject *self;
162 self = PyObject_New(lockobject, &Locktype);
163 if (self == NULL)
164 return NULL;
165 self->lock_lock = PyThread_allocate_lock();
166 self->in_weakreflist = NULL;
167 if (self->lock_lock == NULL) {
168 PyObject_Del(self);
169 self = NULL;
170 PyErr_SetString(ThreadError, "can't allocate lock");
172 return self;
175 /* Thread-local objects */
177 #include "structmember.h"
179 typedef struct {
180 PyObject_HEAD
181 PyObject *key;
182 PyObject *args;
183 PyObject *kw;
184 PyObject *dict;
185 } localobject;
187 static PyObject *
188 local_new(PyTypeObject *type, PyObject *args, PyObject *kw)
190 localobject *self;
191 PyObject *tdict;
193 if (type->tp_init == PyBaseObject_Type.tp_init
194 && ((args && PyObject_IsTrue(args))
195 || (kw && PyObject_IsTrue(kw)))) {
196 PyErr_SetString(PyExc_TypeError,
197 "Initialization arguments are not supported");
198 return NULL;
201 self = (localobject *)type->tp_alloc(type, 0);
202 if (self == NULL)
203 return NULL;
205 Py_XINCREF(args);
206 self->args = args;
207 Py_XINCREF(kw);
208 self->kw = kw;
209 self->dict = NULL; /* making sure */
210 self->key = PyString_FromFormat("thread.local.%p", self);
211 if (self->key == NULL)
212 goto err;
214 self->dict = PyDict_New();
215 if (self->dict == NULL)
216 goto err;
218 tdict = PyThreadState_GetDict();
219 if (tdict == NULL) {
220 PyErr_SetString(PyExc_SystemError,
221 "Couldn't get thread-state dictionary");
222 goto err;
225 if (PyDict_SetItem(tdict, self->key, self->dict) < 0)
226 goto err;
228 return (PyObject *)self;
230 err:
231 Py_DECREF(self);
232 return NULL;
235 static int
236 local_traverse(localobject *self, visitproc visit, void *arg)
238 Py_VISIT(self->args);
239 Py_VISIT(self->kw);
240 Py_VISIT(self->dict);
241 return 0;
244 static int
245 local_clear(localobject *self)
247 Py_CLEAR(self->args);
248 Py_CLEAR(self->kw);
249 Py_CLEAR(self->dict);
250 return 0;
253 static void
254 local_dealloc(localobject *self)
256 PyThreadState *tstate;
257 if (self->key
258 && (tstate = PyThreadState_Get())
259 && tstate->interp) {
260 for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
261 tstate;
262 tstate = PyThreadState_Next(tstate))
263 if (tstate->dict &&
264 PyDict_GetItem(tstate->dict, self->key))
265 PyDict_DelItem(tstate->dict, self->key);
268 Py_XDECREF(self->key);
269 local_clear(self);
270 Py_TYPE(self)->tp_free((PyObject*)self);
273 static PyObject *
274 _ldict(localobject *self)
276 PyObject *tdict, *ldict;
278 tdict = PyThreadState_GetDict();
279 if (tdict == NULL) {
280 PyErr_SetString(PyExc_SystemError,
281 "Couldn't get thread-state dictionary");
282 return NULL;
285 ldict = PyDict_GetItem(tdict, self->key);
286 if (ldict == NULL) {
287 ldict = PyDict_New(); /* we own ldict */
289 if (ldict == NULL)
290 return NULL;
291 else {
292 int i = PyDict_SetItem(tdict, self->key, ldict);
293 Py_DECREF(ldict); /* now ldict is borrowed */
294 if (i < 0)
295 return NULL;
298 Py_CLEAR(self->dict);
299 Py_INCREF(ldict);
300 self->dict = ldict; /* still borrowed */
302 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init &&
303 Py_TYPE(self)->tp_init((PyObject*)self,
304 self->args, self->kw) < 0) {
305 /* we need to get rid of ldict from thread so
306 we create a new one the next time we do an attr
307 acces */
308 PyDict_DelItem(tdict, self->key);
309 return NULL;
314 /* The call to tp_init above may have caused another thread to run.
315 Install our ldict again. */
316 if (self->dict != ldict) {
317 Py_CLEAR(self->dict);
318 Py_INCREF(ldict);
319 self->dict = ldict;
322 return ldict;
325 static int
326 local_setattro(localobject *self, PyObject *name, PyObject *v)
328 PyObject *ldict;
330 ldict = _ldict(self);
331 if (ldict == NULL)
332 return -1;
334 return PyObject_GenericSetAttr((PyObject *)self, name, v);
337 static PyObject *
338 local_getdict(localobject *self, void *closure)
340 if (self->dict == NULL) {
341 PyErr_SetString(PyExc_AttributeError, "__dict__");
342 return NULL;
345 Py_INCREF(self->dict);
346 return self->dict;
349 static PyGetSetDef local_getset[] = {
350 {"__dict__", (getter)local_getdict, (setter)NULL,
351 "Local-data dictionary", NULL},
352 {NULL} /* Sentinel */
355 static PyObject *local_getattro(localobject *, PyObject *);
357 static PyTypeObject localtype = {
358 PyVarObject_HEAD_INIT(NULL, 0)
359 /* tp_name */ "thread._local",
360 /* tp_basicsize */ sizeof(localobject),
361 /* tp_itemsize */ 0,
362 /* tp_dealloc */ (destructor)local_dealloc,
363 /* tp_print */ 0,
364 /* tp_getattr */ 0,
365 /* tp_setattr */ 0,
366 /* tp_compare */ 0,
367 /* tp_repr */ 0,
368 /* tp_as_number */ 0,
369 /* tp_as_sequence */ 0,
370 /* tp_as_mapping */ 0,
371 /* tp_hash */ 0,
372 /* tp_call */ 0,
373 /* tp_str */ 0,
374 /* tp_getattro */ (getattrofunc)local_getattro,
375 /* tp_setattro */ (setattrofunc)local_setattro,
376 /* tp_as_buffer */ 0,
377 /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
378 /* tp_doc */ "Thread-local data",
379 /* tp_traverse */ (traverseproc)local_traverse,
380 /* tp_clear */ (inquiry)local_clear,
381 /* tp_richcompare */ 0,
382 /* tp_weaklistoffset */ 0,
383 /* tp_iter */ 0,
384 /* tp_iternext */ 0,
385 /* tp_methods */ 0,
386 /* tp_members */ 0,
387 /* tp_getset */ local_getset,
388 /* tp_base */ 0,
389 /* tp_dict */ 0, /* internal use */
390 /* tp_descr_get */ 0,
391 /* tp_descr_set */ 0,
392 /* tp_dictoffset */ offsetof(localobject, dict),
393 /* tp_init */ 0,
394 /* tp_alloc */ 0,
395 /* tp_new */ local_new,
396 /* tp_free */ 0, /* Low-level free-mem routine */
397 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
400 static PyObject *
401 local_getattro(localobject *self, PyObject *name)
403 PyObject *ldict, *value;
405 ldict = _ldict(self);
406 if (ldict == NULL)
407 return NULL;
409 if (Py_TYPE(self) != &localtype)
410 /* use generic lookup for subtypes */
411 return PyObject_GenericGetAttr((PyObject *)self, name);
413 /* Optimization: just look in dict ourselves */
414 value = PyDict_GetItem(ldict, name);
415 if (value == NULL)
416 /* Fall back on generic to get __class__ and __dict__ */
417 return PyObject_GenericGetAttr((PyObject *)self, name);
419 Py_INCREF(value);
420 return value;
423 /* Module functions */
425 struct bootstate {
426 PyInterpreterState *interp;
427 PyObject *func;
428 PyObject *args;
429 PyObject *keyw;
432 static void
433 t_bootstrap(void *boot_raw)
435 struct bootstate *boot = (struct bootstate *) boot_raw;
436 PyThreadState *tstate;
437 PyObject *res;
439 tstate = PyThreadState_New(boot->interp);
441 PyEval_AcquireThread(tstate);
442 nb_threads++;
443 res = PyEval_CallObjectWithKeywords(
444 boot->func, boot->args, boot->keyw);
445 if (res == NULL) {
446 if (PyErr_ExceptionMatches(PyExc_SystemExit))
447 PyErr_Clear();
448 else {
449 PyObject *file;
450 PySys_WriteStderr(
451 "Unhandled exception in thread started by ");
452 file = PySys_GetObject("stderr");
453 if (file)
454 PyFile_WriteObject(boot->func, file, 0);
455 else
456 PyObject_Print(boot->func, stderr, 0);
457 PySys_WriteStderr("\n");
458 PyErr_PrintEx(0);
461 else
462 Py_DECREF(res);
463 Py_DECREF(boot->func);
464 Py_DECREF(boot->args);
465 Py_XDECREF(boot->keyw);
466 PyMem_DEL(boot_raw);
467 nb_threads--;
468 PyThreadState_Clear(tstate);
469 PyThreadState_DeleteCurrent();
470 PyThread_exit_thread();
473 static PyObject *
474 thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
476 PyObject *func, *args, *keyw = NULL;
477 struct bootstate *boot;
478 long ident;
480 if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
481 &func, &args, &keyw))
482 return NULL;
483 if (!PyCallable_Check(func)) {
484 PyErr_SetString(PyExc_TypeError,
485 "first arg must be callable");
486 return NULL;
488 if (!PyTuple_Check(args)) {
489 PyErr_SetString(PyExc_TypeError,
490 "2nd arg must be a tuple");
491 return NULL;
493 if (keyw != NULL && !PyDict_Check(keyw)) {
494 PyErr_SetString(PyExc_TypeError,
495 "optional 3rd arg must be a dictionary");
496 return NULL;
498 boot = PyMem_NEW(struct bootstate, 1);
499 if (boot == NULL)
500 return PyErr_NoMemory();
501 boot->interp = PyThreadState_GET()->interp;
502 boot->func = func;
503 boot->args = args;
504 boot->keyw = keyw;
505 Py_INCREF(func);
506 Py_INCREF(args);
507 Py_XINCREF(keyw);
508 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
509 ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
510 if (ident == -1) {
511 PyErr_SetString(ThreadError, "can't start new thread");
512 Py_DECREF(func);
513 Py_DECREF(args);
514 Py_XDECREF(keyw);
515 PyMem_DEL(boot);
516 return NULL;
518 return PyInt_FromLong(ident);
521 PyDoc_STRVAR(start_new_doc,
522 "start_new_thread(function, args[, kwargs])\n\
523 (start_new() is an obsolete synonym)\n\
525 Start a new thread and return its identifier. The thread will call the\n\
526 function with positional arguments from the tuple args and keyword arguments\n\
527 taken from the optional dictionary kwargs. The thread exits when the\n\
528 function returns; the return value is ignored. The thread will also exit\n\
529 when the function raises an unhandled exception; a stack trace will be\n\
530 printed unless the exception is SystemExit.\n");
532 static PyObject *
533 thread_PyThread_exit_thread(PyObject *self)
535 PyErr_SetNone(PyExc_SystemExit);
536 return NULL;
539 PyDoc_STRVAR(exit_doc,
540 "exit()\n\
541 (PyThread_exit_thread() is an obsolete synonym)\n\
543 This is synonymous to ``raise SystemExit''. It will cause the current\n\
544 thread to exit silently unless the exception is caught.");
546 static PyObject *
547 thread_PyThread_interrupt_main(PyObject * self)
549 PyErr_SetInterrupt();
550 Py_INCREF(Py_None);
551 return Py_None;
554 PyDoc_STRVAR(interrupt_doc,
555 "interrupt_main()\n\
557 Raise a KeyboardInterrupt in the main thread.\n\
558 A subthread can use this function to interrupt the main thread."
561 #ifndef NO_EXIT_PROG
562 static PyObject *
563 thread_PyThread_exit_prog(PyObject *self, PyObject *args)
565 int sts;
566 if (!PyArg_ParseTuple(args, "i:exit_prog", &sts))
567 return NULL;
568 Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
569 for (;;) { } /* Should not be reached */
571 #endif
573 static lockobject *newlockobject(void);
575 static PyObject *
576 thread_PyThread_allocate_lock(PyObject *self)
578 return (PyObject *) newlockobject();
581 PyDoc_STRVAR(allocate_doc,
582 "allocate_lock() -> lock object\n\
583 (allocate() is an obsolete synonym)\n\
585 Create a new lock object. See LockType.__doc__ for information about locks.");
587 static PyObject *
588 thread_get_ident(PyObject *self)
590 long ident;
591 ident = PyThread_get_thread_ident();
592 if (ident == -1) {
593 PyErr_SetString(ThreadError, "no current thread ident");
594 return NULL;
596 return PyInt_FromLong(ident);
599 PyDoc_STRVAR(get_ident_doc,
600 "get_ident() -> integer\n\
602 Return a non-zero integer that uniquely identifies the current thread\n\
603 amongst other threads that exist simultaneously.\n\
604 This may be used to identify per-thread resources.\n\
605 Even though on some platforms threads identities may appear to be\n\
606 allocated consecutive numbers starting at 1, this behavior should not\n\
607 be relied upon, and the number should be seen purely as a magic cookie.\n\
608 A thread's identity may be reused for another thread after it exits.");
610 static PyObject *
611 thread__count(PyObject *self)
613 return PyInt_FromLong(nb_threads);
616 PyDoc_STRVAR(_count_doc,
617 "_count() -> integer\n\
620 Return the number of currently running Python threads, excluding \n\
621 the main thread. The returned number comprises all threads created\n\
622 through `start_new_thread()` as well as `threading.Thread`, and not\n\
623 yet finished.\n\
625 This function is meant for internal and specialized purposes only.\n\
626 In most applications `threading.enumerate()` should be used instead.");
628 static PyObject *
629 thread_stack_size(PyObject *self, PyObject *args)
631 size_t old_size;
632 Py_ssize_t new_size = 0;
633 int rc;
635 if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size))
636 return NULL;
638 if (new_size < 0) {
639 PyErr_SetString(PyExc_ValueError,
640 "size must be 0 or a positive value");
641 return NULL;
644 old_size = PyThread_get_stacksize();
646 rc = PyThread_set_stacksize((size_t) new_size);
647 if (rc == -1) {
648 PyErr_Format(PyExc_ValueError,
649 "size not valid: %zd bytes",
650 new_size);
651 return NULL;
653 if (rc == -2) {
654 PyErr_SetString(ThreadError,
655 "setting stack size not supported");
656 return NULL;
659 return PyInt_FromSsize_t((Py_ssize_t) old_size);
662 PyDoc_STRVAR(stack_size_doc,
663 "stack_size([size]) -> size\n\
665 Return the thread stack size used when creating new threads. The\n\
666 optional size argument specifies the stack size (in bytes) to be used\n\
667 for subsequently created threads, and must be 0 (use platform or\n\
668 configured default) or a positive integer value of at least 32,768 (32k).\n\
669 If changing the thread stack size is unsupported, a ThreadError\n\
670 exception is raised. If the specified size is invalid, a ValueError\n\
671 exception is raised, and the stack size is unmodified. 32k bytes\n\
672 currently the minimum supported stack size value to guarantee\n\
673 sufficient stack space for the interpreter itself.\n\
675 Note that some platforms may have particular restrictions on values for\n\
676 the stack size, such as requiring a minimum stack size larger than 32kB or\n\
677 requiring allocation in multiples of the system memory page size\n\
678 - platform documentation should be referred to for more information\n\
679 (4kB pages are common; using multiples of 4096 for the stack size is\n\
680 the suggested approach in the absence of more specific information).");
682 static PyMethodDef thread_methods[] = {
683 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
684 METH_VARARGS,
685 start_new_doc},
686 {"start_new", (PyCFunction)thread_PyThread_start_new_thread,
687 METH_VARARGS,
688 start_new_doc},
689 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
690 METH_NOARGS, allocate_doc},
691 {"allocate", (PyCFunction)thread_PyThread_allocate_lock,
692 METH_NOARGS, allocate_doc},
693 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread,
694 METH_NOARGS, exit_doc},
695 {"exit", (PyCFunction)thread_PyThread_exit_thread,
696 METH_NOARGS, exit_doc},
697 {"interrupt_main", (PyCFunction)thread_PyThread_interrupt_main,
698 METH_NOARGS, interrupt_doc},
699 {"get_ident", (PyCFunction)thread_get_ident,
700 METH_NOARGS, get_ident_doc},
701 {"_count", (PyCFunction)thread__count,
702 METH_NOARGS, _count_doc},
703 {"stack_size", (PyCFunction)thread_stack_size,
704 METH_VARARGS,
705 stack_size_doc},
706 #ifndef NO_EXIT_PROG
707 {"exit_prog", (PyCFunction)thread_PyThread_exit_prog,
708 METH_VARARGS},
709 #endif
710 {NULL, NULL} /* sentinel */
714 /* Initialization function */
716 PyDoc_STRVAR(thread_doc,
717 "This module provides primitive operations to write multi-threaded programs.\n\
718 The 'threading' module provides a more convenient interface.");
720 PyDoc_STRVAR(lock_doc,
721 "A lock object is a synchronization primitive. To create a lock,\n\
722 call the PyThread_allocate_lock() function. Methods are:\n\
724 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
725 release() -- unlock of the lock\n\
726 locked() -- test whether the lock is currently locked\n\
728 A lock is not owned by the thread that locked it; another thread may\n\
729 unlock it. A thread attempting to lock a lock that it has already locked\n\
730 will block until another thread unlocks it. Deadlocks may ensue.");
732 PyMODINIT_FUNC
733 initthread(void)
735 PyObject *m, *d;
737 /* Initialize types: */
738 if (PyType_Ready(&localtype) < 0)
739 return;
741 /* Create the module and add the functions */
742 m = Py_InitModule3("thread", thread_methods, thread_doc);
743 if (m == NULL)
744 return;
746 /* Add a symbolic constant */
747 d = PyModule_GetDict(m);
748 ThreadError = PyErr_NewException("thread.error", NULL, NULL);
749 PyDict_SetItemString(d, "error", ThreadError);
750 Locktype.tp_doc = lock_doc;
751 if (PyType_Ready(&Locktype) < 0)
752 return;
753 Py_INCREF(&Locktype);
754 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
756 Py_INCREF(&localtype);
757 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
758 return;
760 nb_threads = 0;
762 /* Initialize the C thread library */
763 PyThread_init_thread();