source: vendor/python/2.5/Modules/threadmodule.c

Last change on this file was 3225, checked in by bird, 18 years ago

Python 2.5

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