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
;
25 static PyTypeObject Locktype
;
31 self
= PyObject_New(lockobject
, &Locktype
);
34 self
->lock_lock
= PyThread_allocate_lock();
35 if (self
->lock_lock
== NULL
) {
38 PyErr_SetString(ThreadError
, "can't allocate lock");
44 lock_dealloc(lockobject
*self
)
46 /* Unlock the lock so it's safe to free it */
47 PyThread_acquire_lock(self
->lock_lock
, 0);
48 PyThread_release_lock(self
->lock_lock
);
50 PyThread_free_lock(self
->lock_lock
);
55 lock_PyThread_acquire_lock(lockobject
*self
, PyObject
*args
)
59 if (!PyArg_ParseTuple(args
, "|i:acquire", &i
))
62 Py_BEGIN_ALLOW_THREADS
63 i
= PyThread_acquire_lock(self
->lock_lock
, i
);
66 return PyBool_FromLong((long)i
);
69 PyDoc_STRVAR(acquire_doc
,
70 "acquire([wait]) -> None or bool\n\
71 (acquire_lock() is an obsolete synonym)\n\
73 Lock the lock. Without argument, this blocks if the lock is already\n\
74 locked (even by the same thread), waiting for another thread to release\n\
75 the lock, and return None once the lock is acquired.\n\
76 With an argument, this will only block if the argument is true,\n\
77 and the return value reflects whether the lock is acquired.\n\
78 The blocking operation is not interruptible.");
81 lock_PyThread_release_lock(lockobject
*self
)
83 /* Sanity check: the lock must be locked */
84 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
85 PyThread_release_lock(self
->lock_lock
);
86 PyErr_SetString(ThreadError
, "release unlocked lock");
90 PyThread_release_lock(self
->lock_lock
);
95 PyDoc_STRVAR(release_doc
,
97 (release_lock() is an obsolete synonym)\n\
99 Release the lock, allowing another thread that is blocked waiting for\n\
100 the lock to acquire the lock. The lock must be in the locked state,\n\
101 but it needn't be locked by the same thread that unlocks it.");
104 lock_locked_lock(lockobject
*self
)
106 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
107 PyThread_release_lock(self
->lock_lock
);
108 return PyBool_FromLong(0L);
110 return PyBool_FromLong(1L);
113 PyDoc_STRVAR(locked_doc
,
115 (locked_lock() is an obsolete synonym)\n\
117 Return whether the lock is in the locked state.");
120 lock_context(lockobject
*self
)
123 return (PyObject
*)self
;
126 static PyMethodDef lock_methods
[] = {
127 {"acquire_lock", (PyCFunction
)lock_PyThread_acquire_lock
,
128 METH_VARARGS
, acquire_doc
},
129 {"acquire", (PyCFunction
)lock_PyThread_acquire_lock
,
130 METH_VARARGS
, acquire_doc
},
131 {"release_lock", (PyCFunction
)lock_PyThread_release_lock
,
132 METH_NOARGS
, release_doc
},
133 {"release", (PyCFunction
)lock_PyThread_release_lock
,
134 METH_NOARGS
, release_doc
},
135 {"locked_lock", (PyCFunction
)lock_locked_lock
,
136 METH_NOARGS
, locked_doc
},
137 {"locked", (PyCFunction
)lock_locked_lock
,
138 METH_NOARGS
, locked_doc
},
139 {"__context__", (PyCFunction
)lock_context
,
140 METH_NOARGS
, PyDoc_STR("__context__() -> self.")},
141 {"__enter__", (PyCFunction
)lock_PyThread_acquire_lock
,
142 METH_VARARGS
, acquire_doc
},
143 {"__exit__", (PyCFunction
)lock_PyThread_release_lock
,
144 METH_VARARGS
, release_doc
},
145 {NULL
, NULL
} /* sentinel */
149 lock_getattr(lockobject
*self
, char *name
)
151 return Py_FindMethod(lock_methods
, (PyObject
*)self
, name
);
154 static PyTypeObject Locktype
= {
155 PyObject_HEAD_INIT(&PyType_Type
)
157 "thread.lock", /*tp_name*/
158 sizeof(lockobject
), /*tp_size*/
161 (destructor
)lock_dealloc
, /*tp_dealloc*/
163 (getattrfunc
)lock_getattr
, /*tp_getattr*/
169 /* Thread-local objects */
171 #include "structmember.h"
181 static PyTypeObject localtype
;
184 local_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kw
)
189 if (type
->tp_init
== PyBaseObject_Type
.tp_init
190 && ((args
&& PyObject_IsTrue(args
))
191 || (kw
&& PyObject_IsTrue(kw
)))) {
192 PyErr_SetString(PyExc_TypeError
,
193 "Initialization arguments are not supported");
197 self
= (localobject
*)type
->tp_alloc(type
, 0);
205 self
->dict
= NULL
; /* making sure */
206 self
->key
= PyString_FromFormat("thread.local.%p", self
);
207 if (self
->key
== NULL
)
210 self
->dict
= PyDict_New();
211 if (self
->dict
== NULL
)
214 tdict
= PyThreadState_GetDict();
216 PyErr_SetString(PyExc_SystemError
,
217 "Couldn't get thread-state dictionary");
221 if (PyDict_SetItem(tdict
, self
->key
, self
->dict
) < 0)
224 return (PyObject
*)self
;
232 local_traverse(localobject
*self
, visitproc visit
, void *arg
)
234 Py_VISIT(self
->args
);
236 Py_VISIT(self
->dict
);
241 local_clear(localobject
*self
)
244 Py_CLEAR(self
->args
);
246 Py_CLEAR(self
->dict
);
251 local_dealloc(localobject
*self
)
253 PyThreadState
*tstate
;
255 && (tstate
= PyThreadState_Get())
257 for(tstate
= PyInterpreterState_ThreadHead(tstate
->interp
);
259 tstate
= PyThreadState_Next(tstate
))
261 PyDict_GetItem(tstate
->dict
, self
->key
))
262 PyDict_DelItem(tstate
->dict
, self
->key
);
266 self
->ob_type
->tp_free((PyObject
*)self
);
270 _ldict(localobject
*self
)
272 PyObject
*tdict
, *ldict
;
274 tdict
= PyThreadState_GetDict();
276 PyErr_SetString(PyExc_SystemError
,
277 "Couldn't get thread-state dictionary");
281 ldict
= PyDict_GetItem(tdict
, self
->key
);
283 ldict
= PyDict_New(); /* we own ldict */
288 int i
= PyDict_SetItem(tdict
, self
->key
, ldict
);
289 Py_DECREF(ldict
); /* now ldict is borrowed */
294 Py_CLEAR(self
->dict
);
296 self
->dict
= ldict
; /* still borrowed */
298 if (self
->ob_type
->tp_init
!= PyBaseObject_Type
.tp_init
&&
299 self
->ob_type
->tp_init((PyObject
*)self
,
300 self
->args
, self
->kw
) < 0) {
301 /* we need to get rid of ldict from thread so
302 we create a new one the next time we do an attr
304 PyDict_DelItem(tdict
, self
->key
);
309 else if (self
->dict
!= ldict
) {
310 Py_CLEAR(self
->dict
);
319 local_getattro(localobject
*self
, PyObject
*name
)
321 PyObject
*ldict
, *value
;
323 ldict
= _ldict(self
);
327 if (self
->ob_type
!= &localtype
)
328 /* use generic lookup for subtypes */
329 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
331 /* Optimization: just look in dict ourselves */
332 value
= PyDict_GetItem(ldict
, name
);
334 /* Fall back on generic to get __class__ and __dict__ */
335 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
342 local_setattro(localobject
*self
, PyObject
*name
, PyObject
*v
)
346 ldict
= _ldict(self
);
350 return PyObject_GenericSetAttr((PyObject
*)self
, name
, v
);
354 local_getdict(localobject
*self
, void *closure
)
356 if (self
->dict
== NULL
) {
357 PyErr_SetString(PyExc_AttributeError
, "__dict__");
361 Py_INCREF(self
->dict
);
365 static PyGetSetDef local_getset
[] = {
366 {"__dict__", (getter
)local_getdict
, (setter
)NULL
,
367 "Local-data dictionary", NULL
},
368 {NULL
} /* Sentinel */
371 static PyTypeObject localtype
= {
372 PyObject_HEAD_INIT(NULL
)
374 /* tp_name */ "thread._local",
375 /* tp_basicsize */ sizeof(localobject
),
377 /* tp_dealloc */ (destructor
)local_dealloc
,
378 /* tp_print */ (printfunc
)0,
379 /* tp_getattr */ (getattrfunc
)0,
380 /* tp_setattr */ (setattrfunc
)0,
381 /* tp_compare */ (cmpfunc
)0,
382 /* tp_repr */ (reprfunc
)0,
383 /* tp_as_number */ 0,
384 /* tp_as_sequence */ 0,
385 /* tp_as_mapping */ 0,
386 /* tp_hash */ (hashfunc
)0,
387 /* tp_call */ (ternaryfunc
)0,
388 /* tp_str */ (reprfunc
)0,
389 /* tp_getattro */ (getattrofunc
)local_getattro
,
390 /* tp_setattro */ (setattrofunc
)local_setattro
,
391 /* tp_as_buffer */ 0,
392 /* tp_flags */ Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
,
393 /* tp_doc */ "Thread-local data",
394 /* tp_traverse */ (traverseproc
)local_traverse
,
395 /* tp_clear */ (inquiry
)local_clear
,
396 /* tp_richcompare */ (richcmpfunc
)0,
397 /* tp_weaklistoffset */ (long)0,
398 /* tp_iter */ (getiterfunc
)0,
399 /* tp_iternext */ (iternextfunc
)0,
402 /* tp_getset */ local_getset
,
404 /* tp_dict */ 0, /* internal use */
405 /* tp_descr_get */ (descrgetfunc
)0,
406 /* tp_descr_set */ (descrsetfunc
)0,
407 /* tp_dictoffset */ offsetof(localobject
, dict
),
408 /* tp_init */ (initproc
)0,
409 /* tp_alloc */ (allocfunc
)0,
410 /* tp_new */ (newfunc
)local_new
,
411 /* tp_free */ 0, /* Low-level free-mem routine */
412 /* tp_is_gc */ (inquiry
)0, /* For PyObject_IS_GC */
416 /* Module functions */
419 PyInterpreterState
*interp
;
426 t_bootstrap(void *boot_raw
)
428 struct bootstate
*boot
= (struct bootstate
*) boot_raw
;
429 PyThreadState
*tstate
;
432 tstate
= PyThreadState_New(boot
->interp
);
434 PyEval_AcquireThread(tstate
);
435 res
= PyEval_CallObjectWithKeywords(
436 boot
->func
, boot
->args
, boot
->keyw
);
438 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
443 "Unhandled exception in thread started by ");
444 file
= PySys_GetObject("stderr");
446 PyFile_WriteObject(boot
->func
, file
, 0);
448 PyObject_Print(boot
->func
, stderr
, 0);
449 PySys_WriteStderr("\n");
455 Py_DECREF(boot
->func
);
456 Py_DECREF(boot
->args
);
457 Py_XDECREF(boot
->keyw
);
459 PyThreadState_Clear(tstate
);
460 PyThreadState_DeleteCurrent();
461 PyThread_exit_thread();
465 thread_PyThread_start_new_thread(PyObject
*self
, PyObject
*fargs
)
467 PyObject
*func
, *args
, *keyw
= NULL
;
468 struct bootstate
*boot
;
471 if (!PyArg_ParseTuple(fargs
, "OO|O:start_new_thread", &func
, &args
, &keyw
))
473 if (!PyCallable_Check(func
)) {
474 PyErr_SetString(PyExc_TypeError
,
475 "first arg must be callable");
478 if (!PyTuple_Check(args
)) {
479 PyErr_SetString(PyExc_TypeError
,
480 "2nd arg must be a tuple");
483 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
484 PyErr_SetString(PyExc_TypeError
,
485 "optional 3rd arg must be a dictionary");
488 boot
= PyMem_NEW(struct bootstate
, 1);
490 return PyErr_NoMemory();
491 boot
->interp
= PyThreadState_GET()->interp
;
498 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
499 ident
= PyThread_start_new_thread(t_bootstrap
, (void*) boot
);
501 PyErr_SetString(ThreadError
, "can't start new thread");
508 return PyInt_FromLong(ident
);
511 PyDoc_STRVAR(start_new_doc
,
512 "start_new_thread(function, args[, kwargs])\n\
513 (start_new() is an obsolete synonym)\n\
515 Start a new thread and return its identifier. The thread will call the\n\
516 function with positional arguments from the tuple args and keyword arguments\n\
517 taken from the optional dictionary kwargs. The thread exits when the\n\
518 function returns; the return value is ignored. The thread will also exit\n\
519 when the function raises an unhandled exception; a stack trace will be\n\
520 printed unless the exception is SystemExit.\n");
523 thread_PyThread_exit_thread(PyObject
*self
)
525 PyErr_SetNone(PyExc_SystemExit
);
529 PyDoc_STRVAR(exit_doc
,
531 (PyThread_exit_thread() is an obsolete synonym)\n\
533 This is synonymous to ``raise SystemExit''. It will cause the current\n\
534 thread to exit silently unless the exception is caught.");
537 thread_PyThread_interrupt_main(PyObject
* self
)
539 PyErr_SetInterrupt();
544 PyDoc_STRVAR(interrupt_doc
,
547 Raise a KeyboardInterrupt in the main thread.\n\
548 A subthread can use this function to interrupt the main thread."
553 thread_PyThread_exit_prog(PyObject
*self
, PyObject
*args
)
556 if (!PyArg_ParseTuple(args
, "i:exit_prog", &sts
))
558 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
559 for (;;) { } /* Should not be reached */
564 thread_PyThread_allocate_lock(PyObject
*self
)
566 return (PyObject
*) newlockobject();
569 PyDoc_STRVAR(allocate_doc
,
570 "allocate_lock() -> lock object\n\
571 (allocate() is an obsolete synonym)\n\
573 Create a new lock object. See LockType.__doc__ for information about locks.");
576 thread_get_ident(PyObject
*self
)
579 ident
= PyThread_get_thread_ident();
581 PyErr_SetString(ThreadError
, "no current thread ident");
584 return PyInt_FromLong(ident
);
587 PyDoc_STRVAR(get_ident_doc
,
588 "get_ident() -> integer\n\
590 Return a non-zero integer that uniquely identifies the current thread\n\
591 amongst other threads that exist simultaneously.\n\
592 This may be used to identify per-thread resources.\n\
593 Even though on some platforms threads identities may appear to be\n\
594 allocated consecutive numbers starting at 1, this behavior should not\n\
595 be relied upon, and the number should be seen purely as a magic cookie.\n\
596 A thread's identity may be reused for another thread after it exits.");
598 static PyMethodDef thread_methods
[] = {
599 {"start_new_thread", (PyCFunction
)thread_PyThread_start_new_thread
,
602 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
,
605 {"allocate_lock", (PyCFunction
)thread_PyThread_allocate_lock
,
606 METH_NOARGS
, allocate_doc
},
607 {"allocate", (PyCFunction
)thread_PyThread_allocate_lock
,
608 METH_NOARGS
, allocate_doc
},
609 {"exit_thread", (PyCFunction
)thread_PyThread_exit_thread
,
610 METH_NOARGS
, exit_doc
},
611 {"exit", (PyCFunction
)thread_PyThread_exit_thread
,
612 METH_NOARGS
, exit_doc
},
613 {"interrupt_main", (PyCFunction
)thread_PyThread_interrupt_main
,
614 METH_NOARGS
, interrupt_doc
},
615 {"get_ident", (PyCFunction
)thread_get_ident
,
616 METH_NOARGS
, get_ident_doc
},
618 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
,
621 {NULL
, NULL
} /* sentinel */
625 /* Initialization function */
627 PyDoc_STRVAR(thread_doc
,
628 "This module provides primitive operations to write multi-threaded programs.\n\
629 The 'threading' module provides a more convenient interface.");
631 PyDoc_STRVAR(lock_doc
,
632 "A lock object is a synchronization primitive. To create a lock,\n\
633 call the PyThread_allocate_lock() function. Methods are:\n\
635 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
636 release() -- unlock of the lock\n\
637 locked() -- test whether the lock is currently locked\n\
639 A lock is not owned by the thread that locked it; another thread may\n\
640 unlock it. A thread attempting to lock a lock that it has already locked\n\
641 will block until another thread unlocks it. Deadlocks may ensue.");
648 /* Initialize types: */
649 if (PyType_Ready(&localtype
) < 0)
652 /* Create the module and add the functions */
653 m
= Py_InitModule3("thread", thread_methods
, thread_doc
);
657 /* Add a symbolic constant */
658 d
= PyModule_GetDict(m
);
659 ThreadError
= PyErr_NewException("thread.error", NULL
, NULL
);
660 PyDict_SetItemString(d
, "error", ThreadError
);
661 Locktype
.tp_doc
= lock_doc
;
662 Py_INCREF(&Locktype
);
663 PyDict_SetItemString(d
, "LockType", (PyObject
*)&Locktype
);
665 Py_INCREF(&localtype
);
666 if (PyModule_AddObject(m
, "_local", (PyObject
*)&localtype
) < 0)
669 /* Initialize the C thread library */
670 PyThread_init_thread();