History

add hg and python

cinap_lenrek committed 15 years ago

Commit 4bb9e221 parent 987265c3706 files · +1228772 −-233Browse files

Showing the changes to sys/src/cmd/python/Modules/threadmodule.c (1 of 3706 files). Show all

Unified · Split

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