Updated for 2.1b2 distribution.
[python/dscho.git] / Modules / threadmodule.c
blob48f1f36cdac8a116431f833e1e8cf49d216f075b
2 /* Thread module */
3 /* Interface to Sjoerd's portable C thread library */
5 #include "Python.h"
7 #ifndef WITH_THREAD
8 #error "Error! The rest of Python is not compiled with thread support."
9 #error "Rerun configure, adding a --with-thread option."
10 #error "Then run `make clean' followed by `make'."
11 #endif
13 #include "pythread.h"
15 static PyObject *ThreadError;
18 /* Lock objects */
20 typedef struct {
21 PyObject_HEAD
22 PyThread_type_lock lock_lock;
23 } lockobject;
25 staticforward PyTypeObject Locktype;
27 static lockobject *
28 newlockobject(void)
30 lockobject *self;
31 self = PyObject_New(lockobject, &Locktype);
32 if (self == NULL)
33 return NULL;
34 self->lock_lock = PyThread_allocate_lock();
35 if (self->lock_lock == NULL) {
36 PyObject_Del(self);
37 self = NULL;
38 PyErr_SetString(ThreadError, "can't allocate lock");
40 return self;
43 static void
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);
51 PyObject_Del(self);
54 static PyObject *
55 lock_PyThread_acquire_lock(lockobject *self, PyObject *args)
57 int i;
59 if (args != NULL) {
60 if (!PyArg_Parse(args, "i", &i))
61 return NULL;
63 else
64 i = 1;
66 Py_BEGIN_ALLOW_THREADS
67 i = PyThread_acquire_lock(self->lock_lock, i);
68 Py_END_ALLOW_THREADS
70 if (args == NULL) {
71 Py_INCREF(Py_None);
72 return Py_None;
74 else
75 return PyInt_FromLong((long)i);
78 static char acquire_doc[] =
79 "acquire([wait]) -> None or Boolean\n\
80 (PyThread_acquire_lock() is an obsolete synonym)\n\
81 \n\
82 Lock the lock. Without argument, this blocks if the lock is already\n\
83 locked (even by the same thread), waiting for another thread to release\n\
84 the lock, and return None when the lock is acquired.\n\
85 With a Boolean argument, this will only block if the argument is true,\n\
86 and the return value reflects whether the lock is acquired.\n\
87 The blocking operation is not interruptible.";
89 static PyObject *
90 lock_PyThread_release_lock(lockobject *self, PyObject *args)
92 if (!PyArg_NoArgs(args))
93 return NULL;
95 /* Sanity check: the lock must be locked */
96 if (PyThread_acquire_lock(self->lock_lock, 0)) {
97 PyThread_release_lock(self->lock_lock);
98 PyErr_SetString(ThreadError, "release unlocked lock");
99 return NULL;
102 PyThread_release_lock(self->lock_lock);
103 Py_INCREF(Py_None);
104 return Py_None;
107 static char release_doc[] =
108 "release()\n\
109 (PyThread_release_lock() is an obsolete synonym)\n\
111 Release the lock, allowing another thread that is blocked waiting for\n\
112 the lock to acquire the lock. The lock must be in the locked state,\n\
113 but it needn't be locked by the same thread that unlocks it.";
115 static PyObject *
116 lock_locked_lock(lockobject *self, PyObject *args)
118 if (!PyArg_NoArgs(args))
119 return NULL;
121 if (PyThread_acquire_lock(self->lock_lock, 0)) {
122 PyThread_release_lock(self->lock_lock);
123 return PyInt_FromLong(0L);
125 return PyInt_FromLong(1L);
128 static char locked_doc[] =
129 "locked() -> Boolean\n\
130 (locked_lock() is an obsolete synonym)\n\
132 Return whether the lock is in the locked state.";
134 static PyMethodDef lock_methods[] = {
135 {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
136 METH_OLDARGS, acquire_doc},
137 {"acquire", (PyCFunction)lock_PyThread_acquire_lock,
138 METH_OLDARGS, acquire_doc},
139 {"release_lock", (PyCFunction)lock_PyThread_release_lock,
140 METH_OLDARGS, release_doc},
141 {"release", (PyCFunction)lock_PyThread_release_lock,
142 METH_OLDARGS, release_doc},
143 {"locked_lock", (PyCFunction)lock_locked_lock,
144 METH_OLDARGS, locked_doc},
145 {"locked", (PyCFunction)lock_locked_lock,
146 METH_OLDARGS, locked_doc},
147 {NULL, NULL} /* sentinel */
150 static PyObject *
151 lock_getattr(lockobject *self, char *name)
153 return Py_FindMethod(lock_methods, (PyObject *)self, name);
156 static PyTypeObject Locktype = {
157 PyObject_HEAD_INIT(&PyType_Type)
158 0, /*ob_size*/
159 "lock", /*tp_name*/
160 sizeof(lockobject), /*tp_size*/
161 0, /*tp_itemsize*/
162 /* methods */
163 (destructor)lock_dealloc, /*tp_dealloc*/
164 0, /*tp_print*/
165 (getattrfunc)lock_getattr, /*tp_getattr*/
166 0, /*tp_setattr*/
167 0, /*tp_compare*/
168 0, /*tp_repr*/
172 /* Module functions */
174 struct bootstate {
175 PyInterpreterState *interp;
176 PyObject *func;
177 PyObject *args;
178 PyObject *keyw;
181 static void
182 t_bootstrap(void *boot_raw)
184 struct bootstate *boot = (struct bootstate *) boot_raw;
185 PyThreadState *tstate;
186 PyObject *res;
188 tstate = PyThreadState_New(boot->interp);
189 PyEval_AcquireThread(tstate);
190 res = PyEval_CallObjectWithKeywords(
191 boot->func, boot->args, boot->keyw);
192 Py_DECREF(boot->func);
193 Py_DECREF(boot->args);
194 Py_XDECREF(boot->keyw);
195 PyMem_DEL(boot_raw);
196 if (res == NULL) {
197 if (PyErr_ExceptionMatches(PyExc_SystemExit))
198 PyErr_Clear();
199 else {
200 PySys_WriteStderr("Unhandled exception in thread:\n");
201 PyErr_PrintEx(0);
204 else
205 Py_DECREF(res);
206 PyThreadState_Clear(tstate);
207 PyThreadState_DeleteCurrent();
208 PyThread_exit_thread();
211 static PyObject *
212 thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
214 PyObject *func, *args, *keyw = NULL;
215 struct bootstate *boot;
217 if (!PyArg_ParseTuple(fargs, "OO|O:start_new_thread", &func, &args, &keyw))
218 return NULL;
219 if (!PyCallable_Check(func)) {
220 PyErr_SetString(PyExc_TypeError,
221 "first arg must be callable");
222 return NULL;
224 if (!PyTuple_Check(args)) {
225 PyErr_SetString(PyExc_TypeError,
226 "2nd arg must be a tuple");
227 return NULL;
229 if (keyw != NULL && !PyDict_Check(keyw)) {
230 PyErr_SetString(PyExc_TypeError,
231 "optional 3rd arg must be a dictionary");
232 return NULL;
234 boot = PyMem_NEW(struct bootstate, 1);
235 if (boot == NULL)
236 return PyErr_NoMemory();
237 boot->interp = PyThreadState_Get()->interp;
238 boot->func = func;
239 boot->args = args;
240 boot->keyw = keyw;
241 Py_INCREF(func);
242 Py_INCREF(args);
243 Py_XINCREF(keyw);
244 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
245 if (!PyThread_start_new_thread(t_bootstrap, (void*) boot)) {
246 PyErr_SetString(ThreadError, "can't start new thread\n");
247 Py_DECREF(func);
248 Py_DECREF(args);
249 Py_XDECREF(keyw);
250 PyMem_DEL(boot);
251 return NULL;
253 Py_INCREF(Py_None);
254 return Py_None;
257 static char start_new_doc[] =
258 "start_new_thread(functon, args[, kwargs])\n\
259 (start_new() is an obsolete synonym)\n\
261 Start a new thread. The thread will call the function with positional\n\
262 arguments from the tuple args and keyword arguments taken from the optional\n\
263 dictionary kwargs. The thread exits when the function returns; the return\n\
264 value is ignored. The thread will also exit when the function raises an\n\
265 unhandled exception; a stack trace will be printed unless the exception is\n\
266 SystemExit.";
268 static PyObject *
269 thread_PyThread_exit_thread(PyObject *self, PyObject *args)
271 if (!PyArg_NoArgs(args))
272 return NULL;
273 PyErr_SetNone(PyExc_SystemExit);
274 return NULL;
277 static char exit_doc[] =
278 "exit()\n\
279 (PyThread_exit_thread() is an obsolete synonym)\n\
281 This is synonymous to ``raise SystemExit''. It will cause the current\n\
282 thread to exit silently unless the exception is caught.";
284 #ifndef NO_EXIT_PROG
285 static PyObject *
286 thread_PyThread_exit_prog(PyObject *self, PyObject *args)
288 int sts;
289 if (!PyArg_Parse(args, "i", &sts))
290 return NULL;
291 Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
292 for (;;) { } /* Should not be reached */
294 #endif
296 static PyObject *
297 thread_PyThread_allocate_lock(PyObject *self, PyObject *args)
299 if (!PyArg_NoArgs(args))
300 return NULL;
301 return (PyObject *) newlockobject();
304 static char allocate_doc[] =
305 "allocate_lock() -> lock object\n\
306 (allocate() is an obsolete synonym)\n\
308 Create a new lock object. See LockType.__doc__ for information about locks.";
310 static PyObject *
311 thread_get_ident(PyObject *self, PyObject *args)
313 long ident;
314 if (!PyArg_NoArgs(args))
315 return NULL;
316 ident = PyThread_get_thread_ident();
317 if (ident == -1) {
318 PyErr_SetString(ThreadError, "no current thread ident");
319 return NULL;
321 return PyInt_FromLong(ident);
324 static char get_ident_doc[] =
325 "get_ident() -> integer\n\
327 Return a non-zero integer that uniquely identifies the current thread\n\
328 amongst other threads that exist simultaneously.\n\
329 This may be used to identify per-thread resources.\n\
330 Even though on some platforms threads identities may appear to be\n\
331 allocated consecutive numbers starting at 1, this behavior should not\n\
332 be relied upon, and the number should be seen purely as a magic cookie.\n\
333 A thread's identity may be reused for another thread after it exits.";
335 static PyMethodDef thread_methods[] = {
336 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
337 METH_VARARGS,
338 start_new_doc},
339 {"start_new", (PyCFunction)thread_PyThread_start_new_thread,
340 METH_VARARGS,
341 start_new_doc},
342 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
343 METH_OLDARGS, allocate_doc},
344 {"allocate", (PyCFunction)thread_PyThread_allocate_lock,
345 METH_OLDARGS, allocate_doc},
346 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread,
347 METH_OLDARGS, exit_doc},
348 {"exit", (PyCFunction)thread_PyThread_exit_thread,
349 METH_OLDARGS, exit_doc},
350 {"get_ident", (PyCFunction)thread_get_ident,
351 METH_OLDARGS, get_ident_doc},
352 #ifndef NO_EXIT_PROG
353 {"exit_prog", (PyCFunction)thread_PyThread_exit_prog},
354 #endif
355 {NULL, NULL} /* sentinel */
359 /* Initialization function */
361 static char thread_doc[] =
362 "This module provides primitive operations to write multi-threaded programs.\n\
363 The 'threading' module provides a more convenient interface.";
365 static char lock_doc[] =
366 "A lock object is a synchronization primitive. To create a lock,\n\
367 call the PyThread_allocate_lock() function. Methods are:\n\
369 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
370 release() -- unlock of the lock\n\
371 locked() -- test whether the lock is currently locked\n\
373 A lock is not owned by the thread that locked it; another thread may\n\
374 unlock it. A thread attempting to lock a lock that it has already locked\n\
375 will block until another thread unlocks it. Deadlocks may ensue.";
377 DL_EXPORT(void)
378 initthread(void)
380 PyObject *m, *d;
382 /* Create the module and add the functions */
383 m = Py_InitModule3("thread", thread_methods, thread_doc);
385 /* Add a symbolic constant */
386 d = PyModule_GetDict(m);
387 ThreadError = PyErr_NewException("thread.error", NULL, NULL);
388 PyDict_SetItemString(d, "error", ThreadError);
389 Locktype.tp_doc = lock_doc;
390 Py_INCREF(&Locktype);
391 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
393 /* Initialize the C thread library */
394 PyThread_init_thread();