source: python/vendor/Python-2.6.5/Modules/threadmodule.c

Last change on this file was 2, checked in by Yuri Dario, 15 years ago

Initial import for vendor code.

  • Property svn:eol-style set to native
File size: 18.6 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 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
37static PyObject *
38lock_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
52PyDoc_STRVAR(acquire_doc,
53"acquire([wait]) -> None or bool\n\
54(acquire_lock() is an obsolete synonym)\n\
55\n\
56Lock the lock. Without argument, this blocks if the lock is already\n\
57locked (even by the same thread), waiting for another thread to release\n\
58the lock, and return None once the lock is acquired.\n\
59With an argument, this will only block if the argument is true,\n\
60and the return value reflects whether the lock is acquired.\n\
61The blocking operation is not interruptible.");
62
63static PyObject *
64lock_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
78PyDoc_STRVAR(release_doc,
79"release()\n\
80(release_lock() is an obsolete synonym)\n\
81\n\
82Release the lock, allowing another thread that is blocked waiting for\n\
83the lock to acquire the lock. The lock must be in the locked state,\n\
84but it needn't be locked by the same thread that unlocks it.");
85
86static PyObject *
87lock_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
96PyDoc_STRVAR(locked_doc,
97"locked() -> bool\n\
98(locked_lock() is an obsolete synonym)\n\
99\n\
100Return whether the lock is in the locked state.");
101
102static 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
122static PyObject *
123lock_getattr(lockobject *self, char *name)
124{
125 return Py_FindMethod(lock_methods, (PyObject *)self, name);
126}
127
128static 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 (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->args);
231 Py_CLEAR(self->kw);
232 Py_CLEAR(self->dict);
233 return 0;
234}
235
236static void
237local_dealloc(localobject *self)
238{
239 PyThreadState *tstate;
240 if (self->key
241 && (tstate = PyThreadState_Get())
242 && tstate->interp) {
243 for(tstate = PyInterpreterState_ThreadHead(tstate->interp);
244 tstate;
245 tstate = PyThreadState_Next(tstate))
246 if (tstate->dict &&
247 PyDict_GetItem(tstate->dict, self->key))
248 PyDict_DelItem(tstate->dict, self->key);
249 }
250
251 Py_XDECREF(self->key);
252 local_clear(self);
253 Py_TYPE(self)->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 (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init &&
286 Py_TYPE(self)->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
297 /* The call to tp_init above may have caused another thread to run.
298 Install our ldict again. */
299 if (self->dict != ldict) {
300 Py_CLEAR(self->dict);
301 Py_INCREF(ldict);
302 self->dict = ldict;
303 }
304
305 return ldict;
306}
307
308static int
309local_setattro(localobject *self, PyObject *name, PyObject *v)
310{
311 PyObject *ldict;
312
313 ldict = _ldict(self);
314 if (ldict == NULL)
315 return -1;
316
317 return PyObject_GenericSetAttr((PyObject *)self, name, v);
318}
319
320static PyObject *
321local_getdict(localobject *self, void *closure)
322{
323 if (self->dict == NULL) {
324 PyErr_SetString(PyExc_AttributeError, "__dict__");
325 return NULL;
326 }
327
328 Py_INCREF(self->dict);
329 return self->dict;
330}
331
332static PyGetSetDef local_getset[] = {
333 {"__dict__", (getter)local_getdict, (setter)NULL,
334 "Local-data dictionary", NULL},
335 {NULL} /* Sentinel */
336};
337
338static PyObject *local_getattro(localobject *, PyObject *);
339
340static PyTypeObject localtype = {
341 PyVarObject_HEAD_INIT(NULL, 0)
342 /* tp_name */ "thread._local",
343 /* tp_basicsize */ sizeof(localobject),
344 /* tp_itemsize */ 0,
345 /* tp_dealloc */ (destructor)local_dealloc,
346 /* tp_print */ 0,
347 /* tp_getattr */ 0,
348 /* tp_setattr */ 0,
349 /* tp_compare */ 0,
350 /* tp_repr */ 0,
351 /* tp_as_number */ 0,
352 /* tp_as_sequence */ 0,
353 /* tp_as_mapping */ 0,
354 /* tp_hash */ 0,
355 /* tp_call */ 0,
356 /* tp_str */ 0,
357 /* tp_getattro */ (getattrofunc)local_getattro,
358 /* tp_setattro */ (setattrofunc)local_setattro,
359 /* tp_as_buffer */ 0,
360 /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
361 /* tp_doc */ "Thread-local data",
362 /* tp_traverse */ (traverseproc)local_traverse,
363 /* tp_clear */ (inquiry)local_clear,
364 /* tp_richcompare */ 0,
365 /* tp_weaklistoffset */ 0,
366 /* tp_iter */ 0,
367 /* tp_iternext */ 0,
368 /* tp_methods */ 0,
369 /* tp_members */ 0,
370 /* tp_getset */ local_getset,
371 /* tp_base */ 0,
372 /* tp_dict */ 0, /* internal use */
373 /* tp_descr_get */ 0,
374 /* tp_descr_set */ 0,
375 /* tp_dictoffset */ offsetof(localobject, dict),
376 /* tp_init */ 0,
377 /* tp_alloc */ 0,
378 /* tp_new */ local_new,
379 /* tp_free */ 0, /* Low-level free-mem routine */
380 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
381};
382
383static PyObject *
384local_getattro(localobject *self, PyObject *name)
385{
386 PyObject *ldict, *value;
387
388 ldict = _ldict(self);
389 if (ldict == NULL)
390 return NULL;
391
392 if (Py_TYPE(self) != &localtype)
393 /* use generic lookup for subtypes */
394 return PyObject_GenericGetAttr((PyObject *)self, name);
395
396 /* Optimization: just look in dict ourselves */
397 value = PyDict_GetItem(ldict, name);
398 if (value == NULL)
399 /* Fall back on generic to get __class__ and __dict__ */
400 return PyObject_GenericGetAttr((PyObject *)self, name);
401
402 Py_INCREF(value);
403 return value;
404}
405
406/* Module functions */
407
408struct bootstate {
409 PyInterpreterState *interp;
410 PyObject *func;
411 PyObject *args;
412 PyObject *keyw;
413};
414
415static void
416t_bootstrap(void *boot_raw)
417{
418 struct bootstate *boot = (struct bootstate *) boot_raw;
419 PyThreadState *tstate;
420 PyObject *res;
421
422 tstate = PyThreadState_New(boot->interp);
423
424 PyEval_AcquireThread(tstate);
425 res = PyEval_CallObjectWithKeywords(
426 boot->func, boot->args, boot->keyw);
427 if (res == NULL) {
428 if (PyErr_ExceptionMatches(PyExc_SystemExit))
429 PyErr_Clear();
430 else {
431 PyObject *file;
432 PySys_WriteStderr(
433 "Unhandled exception in thread started by ");
434 file = PySys_GetObject("stderr");
435 if (file)
436 PyFile_WriteObject(boot->func, file, 0);
437 else
438 PyObject_Print(boot->func, stderr, 0);
439 PySys_WriteStderr("\n");
440 PyErr_PrintEx(0);
441 }
442 }
443 else
444 Py_DECREF(res);
445 Py_DECREF(boot->func);
446 Py_DECREF(boot->args);
447 Py_XDECREF(boot->keyw);
448 PyMem_DEL(boot_raw);
449 PyThreadState_Clear(tstate);
450 PyThreadState_DeleteCurrent();
451 PyThread_exit_thread();
452}
453
454static PyObject *
455thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
456{
457 PyObject *func, *args, *keyw = NULL;
458 struct bootstate *boot;
459 long ident;
460
461 if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
462 &func, &args, &keyw))
463 return NULL;
464 if (!PyCallable_Check(func)) {
465 PyErr_SetString(PyExc_TypeError,
466 "first arg must be callable");
467 return NULL;
468 }
469 if (!PyTuple_Check(args)) {
470 PyErr_SetString(PyExc_TypeError,
471 "2nd arg must be a tuple");
472 return NULL;
473 }
474 if (keyw != NULL && !PyDict_Check(keyw)) {
475 PyErr_SetString(PyExc_TypeError,
476 "optional 3rd arg must be a dictionary");
477 return NULL;
478 }
479 boot = PyMem_NEW(struct bootstate, 1);
480 if (boot == NULL)
481 return PyErr_NoMemory();
482 boot->interp = PyThreadState_GET()->interp;
483 boot->func = func;
484 boot->args = args;
485 boot->keyw = keyw;
486 Py_INCREF(func);
487 Py_INCREF(args);
488 Py_XINCREF(keyw);
489 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
490 ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
491 if (ident == -1) {
492 PyErr_SetString(ThreadError, "can't start new thread");
493 Py_DECREF(func);
494 Py_DECREF(args);
495 Py_XDECREF(keyw);
496 PyMem_DEL(boot);
497 return NULL;
498 }
499 return PyInt_FromLong(ident);
500}
501
502PyDoc_STRVAR(start_new_doc,
503"start_new_thread(function, args[, kwargs])\n\
504(start_new() is an obsolete synonym)\n\
505\n\
506Start a new thread and return its identifier. The thread will call the\n\
507function with positional arguments from the tuple args and keyword arguments\n\
508taken from the optional dictionary kwargs. The thread exits when the\n\
509function returns; the return value is ignored. The thread will also exit\n\
510when the function raises an unhandled exception; a stack trace will be\n\
511printed unless the exception is SystemExit.\n");
512
513static PyObject *
514thread_PyThread_exit_thread(PyObject *self)
515{
516 PyErr_SetNone(PyExc_SystemExit);
517 return NULL;
518}
519
520PyDoc_STRVAR(exit_doc,
521"exit()\n\
522(PyThread_exit_thread() is an obsolete synonym)\n\
523\n\
524This is synonymous to ``raise SystemExit''. It will cause the current\n\
525thread to exit silently unless the exception is caught.");
526
527static PyObject *
528thread_PyThread_interrupt_main(PyObject * self)
529{
530 PyErr_SetInterrupt();
531 Py_INCREF(Py_None);
532 return Py_None;
533}
534
535PyDoc_STRVAR(interrupt_doc,
536"interrupt_main()\n\
537\n\
538Raise a KeyboardInterrupt in the main thread.\n\
539A subthread can use this function to interrupt the main thread."
540);
541
542#ifndef NO_EXIT_PROG
543static PyObject *
544thread_PyThread_exit_prog(PyObject *self, PyObject *args)
545{
546 int sts;
547 if (!PyArg_ParseTuple(args, "i:exit_prog", &sts))
548 return NULL;
549 Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
550 for (;;) { } /* Should not be reached */
551}
552#endif
553
554static lockobject *newlockobject(void);
555
556static PyObject *
557thread_PyThread_allocate_lock(PyObject *self)
558{
559 return (PyObject *) newlockobject();
560}
561
562PyDoc_STRVAR(allocate_doc,
563"allocate_lock() -> lock object\n\
564(allocate() is an obsolete synonym)\n\
565\n\
566Create a new lock object. See LockType.__doc__ for information about locks.");
567
568static PyObject *
569thread_get_ident(PyObject *self)
570{
571 long ident;
572 ident = PyThread_get_thread_ident();
573 if (ident == -1) {
574 PyErr_SetString(ThreadError, "no current thread ident");
575 return NULL;
576 }
577 return PyInt_FromLong(ident);
578}
579
580PyDoc_STRVAR(get_ident_doc,
581"get_ident() -> integer\n\
582\n\
583Return a non-zero integer that uniquely identifies the current thread\n\
584amongst other threads that exist simultaneously.\n\
585This may be used to identify per-thread resources.\n\
586Even though on some platforms threads identities may appear to be\n\
587allocated consecutive numbers starting at 1, this behavior should not\n\
588be relied upon, and the number should be seen purely as a magic cookie.\n\
589A thread's identity may be reused for another thread after it exits.");
590
591static PyObject *
592thread_stack_size(PyObject *self, PyObject *args)
593{
594 size_t old_size;
595 Py_ssize_t new_size = 0;
596 int rc;
597
598 if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size))
599 return NULL;
600
601 if (new_size < 0) {
602 PyErr_SetString(PyExc_ValueError,
603 "size must be 0 or a positive value");
604 return NULL;
605 }
606
607 old_size = PyThread_get_stacksize();
608
609 rc = PyThread_set_stacksize((size_t) new_size);
610 if (rc == -1) {
611 PyErr_Format(PyExc_ValueError,
612 "size not valid: %zd bytes",
613 new_size);
614 return NULL;
615 }
616 if (rc == -2) {
617 PyErr_SetString(ThreadError,
618 "setting stack size not supported");
619 return NULL;
620 }
621
622 return PyInt_FromSsize_t((Py_ssize_t) old_size);
623}
624
625PyDoc_STRVAR(stack_size_doc,
626"stack_size([size]) -> size\n\
627\n\
628Return the thread stack size used when creating new threads. The\n\
629optional size argument specifies the stack size (in bytes) to be used\n\
630for subsequently created threads, and must be 0 (use platform or\n\
631configured default) or a positive integer value of at least 32,768 (32k).\n\
632If changing the thread stack size is unsupported, a ThreadError\n\
633exception is raised. If the specified size is invalid, a ValueError\n\
634exception is raised, and the stack size is unmodified. 32k bytes\n\
635 currently the minimum supported stack size value to guarantee\n\
636sufficient stack space for the interpreter itself.\n\
637\n\
638Note that some platforms may have particular restrictions on values for\n\
639the stack size, such as requiring a minimum stack size larger than 32kB or\n\
640requiring allocation in multiples of the system memory page size\n\
641- platform documentation should be referred to for more information\n\
642(4kB pages are common; using multiples of 4096 for the stack size is\n\
643the suggested approach in the absence of more specific information).");
644
645static PyMethodDef thread_methods[] = {
646 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
647 METH_VARARGS,
648 start_new_doc},
649 {"start_new", (PyCFunction)thread_PyThread_start_new_thread,
650 METH_VARARGS,
651 start_new_doc},
652 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
653 METH_NOARGS, allocate_doc},
654 {"allocate", (PyCFunction)thread_PyThread_allocate_lock,
655 METH_NOARGS, allocate_doc},
656 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread,
657 METH_NOARGS, exit_doc},
658 {"exit", (PyCFunction)thread_PyThread_exit_thread,
659 METH_NOARGS, exit_doc},
660 {"interrupt_main", (PyCFunction)thread_PyThread_interrupt_main,
661 METH_NOARGS, interrupt_doc},
662 {"get_ident", (PyCFunction)thread_get_ident,
663 METH_NOARGS, get_ident_doc},
664 {"stack_size", (PyCFunction)thread_stack_size,
665 METH_VARARGS,
666 stack_size_doc},
667#ifndef NO_EXIT_PROG
668 {"exit_prog", (PyCFunction)thread_PyThread_exit_prog,
669 METH_VARARGS},
670#endif
671 {NULL, NULL} /* sentinel */
672};
673
674
675/* Initialization function */
676
677PyDoc_STRVAR(thread_doc,
678"This module provides primitive operations to write multi-threaded programs.\n\
679The 'threading' module provides a more convenient interface.");
680
681PyDoc_STRVAR(lock_doc,
682"A lock object is a synchronization primitive. To create a lock,\n\
683call the PyThread_allocate_lock() function. Methods are:\n\
684\n\
685acquire() -- lock the lock, possibly blocking until it can be obtained\n\
686release() -- unlock of the lock\n\
687locked() -- test whether the lock is currently locked\n\
688\n\
689A lock is not owned by the thread that locked it; another thread may\n\
690unlock it. A thread attempting to lock a lock that it has already locked\n\
691will block until another thread unlocks it. Deadlocks may ensue.");
692
693PyMODINIT_FUNC
694initthread(void)
695{
696 PyObject *m, *d;
697
698 /* Initialize types: */
699 if (PyType_Ready(&localtype) < 0)
700 return;
701
702 /* Create the module and add the functions */
703 m = Py_InitModule3("thread", thread_methods, thread_doc);
704 if (m == NULL)
705 return;
706
707 /* Add a symbolic constant */
708 d = PyModule_GetDict(m);
709 ThreadError = PyErr_NewException("thread.error", NULL, NULL);
710 PyDict_SetItemString(d, "error", ThreadError);
711 Locktype.tp_doc = lock_doc;
712 Py_INCREF(&Locktype);
713 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
714
715 Py_INCREF(&localtype);
716 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0)
717 return;
718
719 /* Initialize the C thread library */
720 PyThread_init_thread();
721}
Note: See TracBrowser for help on using the repository browser.