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