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 /* 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
);
32 PyThread_free_lock(self
->lock_lock
);
37 lock_PyThread_acquire_lock(lockobject
*self
, PyObject
*args
)
41 if (!PyArg_ParseTuple(args
, "|i:acquire", &i
))
44 Py_BEGIN_ALLOW_THREADS
45 i
= PyThread_acquire_lock(self
->lock_lock
, i
);
48 return PyBool_FromLong((long)i
);
51 PyDoc_STRVAR(acquire_doc
,
52 "acquire([wait]) -> None or bool\n\
53 (acquire_lock() is an obsolete synonym)\n\
55 Lock the lock. Without argument, this blocks if the lock is already\n\
56 locked (even by the same thread), waiting for another thread to release\n\
57 the lock, and return None once the lock is acquired.\n\
58 With an argument, this will only block if the argument is true,\n\
59 and the return value reflects whether the lock is acquired.\n\
60 The blocking operation is not interruptible.");
63 lock_PyThread_release_lock(lockobject
*self
)
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");
72 PyThread_release_lock(self
->lock_lock
);
77 PyDoc_STRVAR(release_doc
,
79 (release_lock() is an obsolete synonym)\n\
81 Release the lock, allowing another thread that is blocked waiting for\n\
82 the lock to acquire the lock. The lock must be in the locked state,\n\
83 but it needn't be locked by the same thread that unlocks it.");
86 lock_locked_lock(lockobject
*self
)
88 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
89 PyThread_release_lock(self
->lock_lock
);
90 return PyBool_FromLong(0L);
92 return PyBool_FromLong(1L);
95 PyDoc_STRVAR(locked_doc
,
97 (locked_lock() is an obsolete synonym)\n\
99 Return whether the lock is in the locked state.");
101 static 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 */
122 lock_getattr(lockobject
*self
, char *name
)
124 return Py_FindMethod(lock_methods
, (PyObject
*)self
, name
);
127 static PyTypeObject Locktype
= {
128 PyObject_HEAD_INIT(&PyType_Type
)
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 self
->ob_type
->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 (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
291 PyDict_DelItem(tdict
, self
->key
);
296 else if (self
->dict
!= ldict
) {
297 Py_CLEAR(self
->dict
);
306 local_setattro(localobject
*self
, PyObject
*name
, PyObject
*v
)
310 ldict
= _ldict(self
);
314 return PyObject_GenericSetAttr((PyObject
*)self
, name
, v
);
318 local_getdict(localobject
*self
, void *closure
)
320 if (self
->dict
== NULL
) {
321 PyErr_SetString(PyExc_AttributeError
, "__dict__");
325 Py_INCREF(self
->dict
);
329 static PyGetSetDef local_getset
[] = {
330 {"__dict__", (getter
)local_getdict
, (setter
)NULL
,
331 "Local-data dictionary", NULL
},
332 {NULL
} /* Sentinel */
335 static PyObject
*local_getattro(localobject
*, PyObject
*);
337 static PyTypeObject localtype
= {
338 PyObject_HEAD_INIT(NULL
)
340 /* tp_name */ "thread._local",
341 /* tp_basicsize */ sizeof(localobject
),
343 /* tp_dealloc */ (destructor
)local_dealloc
,
349 /* tp_as_number */ 0,
350 /* tp_as_sequence */ 0,
351 /* tp_as_mapping */ 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,
368 /* tp_getset */ local_getset
,
370 /* tp_dict */ 0, /* internal use */
371 /* tp_descr_get */ 0,
372 /* tp_descr_set */ 0,
373 /* tp_dictoffset */ offsetof(localobject
, dict
),
376 /* tp_new */ local_new
,
377 /* tp_free */ 0, /* Low-level free-mem routine */
378 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
382 local_getattro(localobject
*self
, PyObject
*name
)
384 PyObject
*ldict
, *value
;
386 ldict
= _ldict(self
);
390 if (self
->ob_type
!= &localtype
)
391 /* use generic lookup for subtypes */
392 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
394 /* Optimization: just look in dict ourselves */
395 value
= PyDict_GetItem(ldict
, name
);
397 /* Fall back on generic to get __class__ and __dict__ */
398 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
404 /* Module functions */
407 PyInterpreterState
*interp
;
414 t_bootstrap(void *boot_raw
)
416 struct bootstate
*boot
= (struct bootstate
*) boot_raw
;
417 PyThreadState
*tstate
;
420 tstate
= PyThreadState_New(boot
->interp
);
422 PyEval_AcquireThread(tstate
);
423 res
= PyEval_CallObjectWithKeywords(
424 boot
->func
, boot
->args
, boot
->keyw
);
426 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
431 "Unhandled exception in thread started by ");
432 file
= PySys_GetObject("stderr");
434 PyFile_WriteObject(boot
->func
, file
, 0);
436 PyObject_Print(boot
->func
, stderr
, 0);
437 PySys_WriteStderr("\n");
443 Py_DECREF(boot
->func
);
444 Py_DECREF(boot
->args
);
445 Py_XDECREF(boot
->keyw
);
447 PyThreadState_Clear(tstate
);
448 PyThreadState_DeleteCurrent();
449 PyThread_exit_thread();
453 thread_PyThread_start_new_thread(PyObject
*self
, PyObject
*fargs
)
455 PyObject
*func
, *args
, *keyw
= NULL
;
456 struct bootstate
*boot
;
459 if (!PyArg_ParseTuple(fargs
, "OO|O:start_new_thread", &func
, &args
, &keyw
))
461 if (!PyCallable_Check(func
)) {
462 PyErr_SetString(PyExc_TypeError
,
463 "first arg must be callable");
466 if (!PyTuple_Check(args
)) {
467 PyErr_SetString(PyExc_TypeError
,
468 "2nd arg must be a tuple");
471 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
472 PyErr_SetString(PyExc_TypeError
,
473 "optional 3rd arg must be a dictionary");
476 boot
= PyMem_NEW(struct bootstate
, 1);
478 return PyErr_NoMemory();
479 boot
->interp
= PyThreadState_GET()->interp
;
486 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
487 ident
= PyThread_start_new_thread(t_bootstrap
, (void*) boot
);
489 PyErr_SetString(ThreadError
, "can't start new thread");
496 return PyInt_FromLong(ident
);
499 PyDoc_STRVAR(start_new_doc
,
500 "start_new_thread(function, args[, kwargs])\n\
501 (start_new() is an obsolete synonym)\n\
503 Start a new thread and return its identifier. The thread will call the\n\
504 function with positional arguments from the tuple args and keyword arguments\n\
505 taken from the optional dictionary kwargs. The thread exits when the\n\
506 function returns; the return value is ignored. The thread will also exit\n\
507 when the function raises an unhandled exception; a stack trace will be\n\
508 printed unless the exception is SystemExit.\n");
511 thread_PyThread_exit_thread(PyObject
*self
)
513 PyErr_SetNone(PyExc_SystemExit
);
517 PyDoc_STRVAR(exit_doc
,
519 (PyThread_exit_thread() is an obsolete synonym)\n\
521 This is synonymous to ``raise SystemExit''. It will cause the current\n\
522 thread to exit silently unless the exception is caught.");
525 thread_PyThread_interrupt_main(PyObject
* self
)
527 PyErr_SetInterrupt();
532 PyDoc_STRVAR(interrupt_doc
,
535 Raise a KeyboardInterrupt in the main thread.\n\
536 A subthread can use this function to interrupt the main thread."
541 thread_PyThread_exit_prog(PyObject
*self
, PyObject
*args
)
544 if (!PyArg_ParseTuple(args
, "i:exit_prog", &sts
))
546 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
547 for (;;) { } /* Should not be reached */
551 static lockobject
*newlockobject(void);
554 thread_PyThread_allocate_lock(PyObject
*self
)
556 return (PyObject
*) newlockobject();
559 PyDoc_STRVAR(allocate_doc
,
560 "allocate_lock() -> lock object\n\
561 (allocate() is an obsolete synonym)\n\
563 Create a new lock object. See LockType.__doc__ for information about locks.");
566 thread_get_ident(PyObject
*self
)
569 ident
= PyThread_get_thread_ident();
571 PyErr_SetString(ThreadError
, "no current thread ident");
574 return PyInt_FromLong(ident
);
577 PyDoc_STRVAR(get_ident_doc
,
578 "get_ident() -> integer\n\
580 Return a non-zero integer that uniquely identifies the current thread\n\
581 amongst other threads that exist simultaneously.\n\
582 This may be used to identify per-thread resources.\n\
583 Even though on some platforms threads identities may appear to be\n\
584 allocated consecutive numbers starting at 1, this behavior should not\n\
585 be relied upon, and the number should be seen purely as a magic cookie.\n\
586 A thread's identity may be reused for another thread after it exits.");
588 static PyMethodDef thread_methods
[] = {
589 {"start_new_thread", (PyCFunction
)thread_PyThread_start_new_thread
,
592 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
,
595 {"allocate_lock", (PyCFunction
)thread_PyThread_allocate_lock
,
596 METH_NOARGS
, allocate_doc
},
597 {"allocate", (PyCFunction
)thread_PyThread_allocate_lock
,
598 METH_NOARGS
, allocate_doc
},
599 {"exit_thread", (PyCFunction
)thread_PyThread_exit_thread
,
600 METH_NOARGS
, exit_doc
},
601 {"exit", (PyCFunction
)thread_PyThread_exit_thread
,
602 METH_NOARGS
, exit_doc
},
603 {"interrupt_main", (PyCFunction
)thread_PyThread_interrupt_main
,
604 METH_NOARGS
, interrupt_doc
},
605 {"get_ident", (PyCFunction
)thread_get_ident
,
606 METH_NOARGS
, get_ident_doc
},
608 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
,
611 {NULL
, NULL
} /* sentinel */
615 /* Initialization function */
617 PyDoc_STRVAR(thread_doc
,
618 "This module provides primitive operations to write multi-threaded programs.\n\
619 The 'threading' module provides a more convenient interface.");
621 PyDoc_STRVAR(lock_doc
,
622 "A lock object is a synchronization primitive. To create a lock,\n\
623 call the PyThread_allocate_lock() function. Methods are:\n\
625 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
626 release() -- unlock of the lock\n\
627 locked() -- test whether the lock is currently locked\n\
629 A lock is not owned by the thread that locked it; another thread may\n\
630 unlock it. A thread attempting to lock a lock that it has already locked\n\
631 will block until another thread unlocks it. Deadlocks may ensue.");
638 /* Initialize types: */
639 if (PyType_Ready(&localtype
) < 0)
642 /* Create the module and add the functions */
643 m
= Py_InitModule3("thread", thread_methods
, thread_doc
);
647 /* Add a symbolic constant */
648 d
= PyModule_GetDict(m
);
649 ThreadError
= PyErr_NewException("thread.error", NULL
, NULL
);
650 PyDict_SetItemString(d
, "error", ThreadError
);
651 Locktype
.tp_doc
= lock_doc
;
652 Py_INCREF(&Locktype
);
653 PyDict_SetItemString(d
, "LockType", (PyObject
*)&Locktype
);
655 Py_INCREF(&localtype
);
656 if (PyModule_AddObject(m
, "_local", (PyObject
*)&localtype
) < 0)
659 /* Initialize the C thread library */
660 PyThread_init_thread();