3 /* Interface to Sjoerd's portable C thread library */
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'."
15 static PyObject
*ThreadError
;
22 PyThread_type_lock lock_lock
;
26 lock_dealloc(lockobject
*self
)
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
);
33 PyThread_free_lock(self
->lock_lock
);
38 lock_PyThread_acquire_lock(lockobject
*self
, PyObject
*args
)
42 if (!PyArg_ParseTuple(args
, "|i:acquire", &i
))
45 Py_BEGIN_ALLOW_THREADS
46 i
= PyThread_acquire_lock(self
->lock_lock
, i
);
49 return PyBool_FromLong((long)i
);
52 PyDoc_STRVAR(acquire_doc
,
53 "acquire([wait]) -> None or bool\n\
54 (acquire_lock() is an obsolete synonym)\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.");
64 lock_PyThread_release_lock(lockobject
*self
)
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");
73 PyThread_release_lock(self
->lock_lock
);
78 PyDoc_STRVAR(release_doc
,
80 (release_lock() is an obsolete synonym)\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.");
87 lock_locked_lock(lockobject
*self
)
89 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
90 PyThread_release_lock(self
->lock_lock
);
91 return PyBool_FromLong(0L);
93 return PyBool_FromLong(1L);
96 PyDoc_STRVAR(locked_doc
,
98 (locked_lock() is an obsolete synonym)\n\
100 Return whether the lock is in the locked state.");
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 */
123 lock_getattr(lockobject
*self
, char *name
)
125 return Py_FindMethod(lock_methods
, (PyObject
*)self
, name
);
128 static PyTypeObject Locktype
= {
129 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
130 "thread.lock", /*tp_name*/
131 sizeof(lockobject
), /*tp_size*/
134 (destructor
)lock_dealloc
, /*tp_dealloc*/
136 (getattrfunc
)lock_getattr
, /*tp_getattr*/
146 self
= PyObject_New(lockobject
, &Locktype
);
149 self
->lock_lock
= PyThread_allocate_lock();
150 if (self
->lock_lock
== NULL
) {
153 PyErr_SetString(ThreadError
, "can't allocate lock");
158 /* Thread-local objects */
160 #include "structmember.h"
171 local_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kw
)
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");
184 self
= (localobject
*)type
->tp_alloc(type
, 0);
192 self
->dict
= NULL
; /* making sure */
193 self
->key
= PyString_FromFormat("thread.local.%p", self
);
194 if (self
->key
== NULL
)
197 self
->dict
= PyDict_New();
198 if (self
->dict
== NULL
)
201 tdict
= PyThreadState_GetDict();
203 PyErr_SetString(PyExc_SystemError
,
204 "Couldn't get thread-state dictionary");
208 if (PyDict_SetItem(tdict
, self
->key
, self
->dict
) < 0)
211 return (PyObject
*)self
;
219 local_traverse(localobject
*self
, visitproc visit
, void *arg
)
221 Py_VISIT(self
->args
);
223 Py_VISIT(self
->dict
);
228 local_clear(localobject
*self
)
231 Py_CLEAR(self
->args
);
233 Py_CLEAR(self
->dict
);
238 local_dealloc(localobject
*self
)
240 PyThreadState
*tstate
;
242 && (tstate
= PyThreadState_Get())
244 for(tstate
= PyInterpreterState_ThreadHead(tstate
->interp
);
246 tstate
= PyThreadState_Next(tstate
))
248 PyDict_GetItem(tstate
->dict
, self
->key
))
249 PyDict_DelItem(tstate
->dict
, self
->key
);
253 Py_TYPE(self
)->tp_free((PyObject
*)self
);
257 _ldict(localobject
*self
)
259 PyObject
*tdict
, *ldict
;
261 tdict
= PyThreadState_GetDict();
263 PyErr_SetString(PyExc_SystemError
,
264 "Couldn't get thread-state dictionary");
268 ldict
= PyDict_GetItem(tdict
, self
->key
);
270 ldict
= PyDict_New(); /* we own ldict */
275 int i
= PyDict_SetItem(tdict
, self
->key
, ldict
);
276 Py_DECREF(ldict
); /* now ldict is borrowed */
281 Py_CLEAR(self
->dict
);
283 self
->dict
= ldict
; /* still borrowed */
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
291 PyDict_DelItem(tdict
, self
->key
);
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
);
309 local_setattro(localobject
*self
, PyObject
*name
, PyObject
*v
)
313 ldict
= _ldict(self
);
317 return PyObject_GenericSetAttr((PyObject
*)self
, name
, v
);
321 local_getdict(localobject
*self
, void *closure
)
323 if (self
->dict
== NULL
) {
324 PyErr_SetString(PyExc_AttributeError
, "__dict__");
328 Py_INCREF(self
->dict
);
332 static PyGetSetDef local_getset
[] = {
333 {"__dict__", (getter
)local_getdict
, (setter
)NULL
,
334 "Local-data dictionary", NULL
},
335 {NULL
} /* Sentinel */
338 static PyObject
*local_getattro(localobject
*, PyObject
*);
340 static PyTypeObject localtype
= {
341 PyVarObject_HEAD_INIT(NULL
, 0)
342 /* tp_name */ "thread._local",
343 /* tp_basicsize */ sizeof(localobject
),
345 /* tp_dealloc */ (destructor
)local_dealloc
,
351 /* tp_as_number */ 0,
352 /* tp_as_sequence */ 0,
353 /* tp_as_mapping */ 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,
370 /* tp_getset */ local_getset
,
372 /* tp_dict */ 0, /* internal use */
373 /* tp_descr_get */ 0,
374 /* tp_descr_set */ 0,
375 /* tp_dictoffset */ offsetof(localobject
, dict
),
378 /* tp_new */ local_new
,
379 /* tp_free */ 0, /* Low-level free-mem routine */
380 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
384 local_getattro(localobject
*self
, PyObject
*name
)
386 PyObject
*ldict
, *value
;
388 ldict
= _ldict(self
);
392 if (Py_TYPE(self
) != &localtype
)
393 /* use generic lookup for subtypes */
394 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
396 /* Optimization: just look in dict ourselves */
397 value
= PyDict_GetItem(ldict
, name
);
399 /* Fall back on generic to get __class__ and __dict__ */
400 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
406 /* Module functions */
409 PyInterpreterState
*interp
;
416 t_bootstrap(void *boot_raw
)
418 struct bootstate
*boot
= (struct bootstate
*) boot_raw
;
419 PyThreadState
*tstate
;
422 tstate
= PyThreadState_New(boot
->interp
);
424 PyEval_AcquireThread(tstate
);
425 res
= PyEval_CallObjectWithKeywords(
426 boot
->func
, boot
->args
, boot
->keyw
);
428 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
433 "Unhandled exception in thread started by ");
434 file
= PySys_GetObject("stderr");
436 PyFile_WriteObject(boot
->func
, file
, 0);
438 PyObject_Print(boot
->func
, stderr
, 0);
439 PySys_WriteStderr("\n");
445 Py_DECREF(boot
->func
);
446 Py_DECREF(boot
->args
);
447 Py_XDECREF(boot
->keyw
);
449 PyThreadState_Clear(tstate
);
450 PyThreadState_DeleteCurrent();
451 PyThread_exit_thread();
455 thread_PyThread_start_new_thread(PyObject
*self
, PyObject
*fargs
)
457 PyObject
*func
, *args
, *keyw
= NULL
;
458 struct bootstate
*boot
;
461 if (!PyArg_UnpackTuple(fargs
, "start_new_thread", 2, 3,
462 &func
, &args
, &keyw
))
464 if (!PyCallable_Check(func
)) {
465 PyErr_SetString(PyExc_TypeError
,
466 "first arg must be callable");
469 if (!PyTuple_Check(args
)) {
470 PyErr_SetString(PyExc_TypeError
,
471 "2nd arg must be a tuple");
474 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
475 PyErr_SetString(PyExc_TypeError
,
476 "optional 3rd arg must be a dictionary");
479 boot
= PyMem_NEW(struct bootstate
, 1);
481 return PyErr_NoMemory();
482 boot
->interp
= PyThreadState_GET()->interp
;
489 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
490 ident
= PyThread_start_new_thread(t_bootstrap
, (void*) boot
);
492 PyErr_SetString(ThreadError
, "can't start new thread");
499 return PyInt_FromLong(ident
);
502 PyDoc_STRVAR(start_new_doc
,
503 "start_new_thread(function, args[, kwargs])\n\
504 (start_new() is an obsolete synonym)\n\
506 Start a new thread and return its identifier. The thread will call the\n\
507 function with positional arguments from the tuple args and keyword arguments\n\
508 taken from the optional dictionary kwargs. The thread exits when the\n\
509 function returns; the return value is ignored. The thread will also exit\n\
510 when the function raises an unhandled exception; a stack trace will be\n\
511 printed unless the exception is SystemExit.\n");
514 thread_PyThread_exit_thread(PyObject
*self
)
516 PyErr_SetNone(PyExc_SystemExit
);
520 PyDoc_STRVAR(exit_doc
,
522 (PyThread_exit_thread() is an obsolete synonym)\n\
524 This is synonymous to ``raise SystemExit''. It will cause the current\n\
525 thread to exit silently unless the exception is caught.");
528 thread_PyThread_interrupt_main(PyObject
* self
)
530 PyErr_SetInterrupt();
535 PyDoc_STRVAR(interrupt_doc
,
538 Raise a KeyboardInterrupt in the main thread.\n\
539 A subthread can use this function to interrupt the main thread."
544 thread_PyThread_exit_prog(PyObject
*self
, PyObject
*args
)
547 if (!PyArg_ParseTuple(args
, "i:exit_prog", &sts
))
549 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
550 for (;;) { } /* Should not be reached */
554 static lockobject
*newlockobject(void);
557 thread_PyThread_allocate_lock(PyObject
*self
)
559 return (PyObject
*) newlockobject();
562 PyDoc_STRVAR(allocate_doc
,
563 "allocate_lock() -> lock object\n\
564 (allocate() is an obsolete synonym)\n\
566 Create a new lock object. See LockType.__doc__ for information about locks.");
569 thread_get_ident(PyObject
*self
)
572 ident
= PyThread_get_thread_ident();
574 PyErr_SetString(ThreadError
, "no current thread ident");
577 return PyInt_FromLong(ident
);
580 PyDoc_STRVAR(get_ident_doc
,
581 "get_ident() -> integer\n\
583 Return a non-zero integer that uniquely identifies the current thread\n\
584 amongst other threads that exist simultaneously.\n\
585 This may be used to identify per-thread resources.\n\
586 Even though on some platforms threads identities may appear to be\n\
587 allocated consecutive numbers starting at 1, this behavior should not\n\
588 be relied upon, and the number should be seen purely as a magic cookie.\n\
589 A thread's identity may be reused for another thread after it exits.");
592 thread_stack_size(PyObject
*self
, PyObject
*args
)
595 Py_ssize_t new_size
= 0;
598 if (!PyArg_ParseTuple(args
, "|n:stack_size", &new_size
))
602 PyErr_SetString(PyExc_ValueError
,
603 "size must be 0 or a positive value");
607 old_size
= PyThread_get_stacksize();
609 rc
= PyThread_set_stacksize((size_t) new_size
);
611 PyErr_Format(PyExc_ValueError
,
612 "size not valid: %zd bytes",
617 PyErr_SetString(ThreadError
,
618 "setting stack size not supported");
622 return PyInt_FromSsize_t((Py_ssize_t
) old_size
);
625 PyDoc_STRVAR(stack_size_doc
,
626 "stack_size([size]) -> size\n\
628 Return the thread stack size used when creating new threads. The\n\
629 optional size argument specifies the stack size (in bytes) to be used\n\
630 for subsequently created threads, and must be 0 (use platform or\n\
631 configured default) or a positive integer value of at least 32,768 (32k).\n\
632 If changing the thread stack size is unsupported, a ThreadError\n\
633 exception is raised. If the specified size is invalid, a ValueError\n\
634 exception is raised, and the stack size is unmodified. 32k bytes\n\
635 currently the minimum supported stack size value to guarantee\n\
636 sufficient stack space for the interpreter itself.\n\
638 Note that some platforms may have particular restrictions on values for\n\
639 the stack size, such as requiring a minimum stack size larger than 32kB or\n\
640 requiring 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\
643 the suggested approach in the absence of more specific information).");
645 static PyMethodDef thread_methods
[] = {
646 {"start_new_thread", (PyCFunction
)thread_PyThread_start_new_thread
,
649 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
,
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
,
668 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
,
671 {NULL
, NULL
} /* sentinel */
675 /* Initialization function */
677 PyDoc_STRVAR(thread_doc
,
678 "This module provides primitive operations to write multi-threaded programs.\n\
679 The 'threading' module provides a more convenient interface.");
681 PyDoc_STRVAR(lock_doc
,
682 "A lock object is a synchronization primitive. To create a lock,\n\
683 call the PyThread_allocate_lock() function. Methods are:\n\
685 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
686 release() -- unlock of the lock\n\
687 locked() -- test whether the lock is currently locked\n\
689 A lock is not owned by the thread that locked it; another thread may\n\
690 unlock it. A thread attempting to lock a lock that it has already locked\n\
691 will block until another thread unlocks it. Deadlocks may ensue.");
698 /* Initialize types: */
699 if (PyType_Ready(&localtype
) < 0)
702 /* Create the module and add the functions */
703 m
= Py_InitModule3("thread", thread_methods
, thread_doc
);
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
);
715 Py_INCREF(&localtype
);
716 if (PyModule_AddObject(m
, "_local", (PyObject
*)&localtype
) < 0)
719 /* Initialize the C thread library */
720 PyThread_init_thread();