Added 'description' class attribute to every command class (to help the
[python/dscho.git] / Modules / threadmodule.c
blob3d5e4ccb3248278a85bb70026df0513ac5a45fb2
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
15 permission.
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
32 /* Thread module */
33 /* Interface to Sjoerd's portable C thread library */
35 #include "Python.h"
37 #ifndef WITH_THREAD
38 #error "Error! The rest of Python is not compiled with thread support."
39 #error "Rerun configure, adding a --with-thread option."
40 #error "Then run `make clean' followed by `make'."
41 #endif
43 #include "pythread.h"
45 static PyObject *ThreadError;
48 /* Lock objects */
50 typedef struct {
51 PyObject_HEAD
52 PyThread_type_lock lock_lock;
53 } lockobject;
55 staticforward PyTypeObject Locktype;
57 static lockobject *
58 newlockobject()
60 lockobject *self;
61 self = PyObject_NEW(lockobject, &Locktype);
62 if (self == NULL)
63 return NULL;
64 self->lock_lock = PyThread_allocate_lock();
65 if (self->lock_lock == NULL) {
66 PyMem_DEL(self);
67 self = NULL;
68 PyErr_SetString(ThreadError, "can't allocate lock");
70 return self;
73 static void
74 lock_dealloc(self)
75 lockobject *self;
77 /* Unlock the lock so it's safe to free it */
78 PyThread_acquire_lock(self->lock_lock, 0);
79 PyThread_release_lock(self->lock_lock);
81 PyThread_free_lock(self->lock_lock);
82 PyMem_DEL(self);
85 static PyObject *
86 lock_PyThread_acquire_lock(self, args)
87 lockobject *self;
88 PyObject *args;
90 int i;
92 if (args != NULL) {
93 if (!PyArg_Parse(args, "i", &i))
94 return NULL;
96 else
97 i = 1;
99 Py_BEGIN_ALLOW_THREADS
100 i = PyThread_acquire_lock(self->lock_lock, i);
101 Py_END_ALLOW_THREADS
103 if (args == NULL) {
104 Py_INCREF(Py_None);
105 return Py_None;
107 else
108 return PyInt_FromLong((long)i);
111 static char acquire_doc[] =
112 "acquire([wait]) -> None or Boolean\n\
113 (PyThread_acquire_lock() is an obsolete synonym)\n\
115 Lock the lock. Without argument, this blocks if the lock is already\n\
116 locked (even by the same thread), waiting for another thread to release\n\
117 the lock, and return None when the lock is acquired.\n\
118 With a Boolean argument, this will only block if the argument is true,\n\
119 and the return value reflects whether the lock is acquired.\n\
120 The blocking operation is not interruptible.";
122 static PyObject *
123 lock_PyThread_release_lock(self, args)
124 lockobject *self;
125 PyObject *args;
127 if (!PyArg_NoArgs(args))
128 return NULL;
130 /* Sanity check: the lock must be locked */
131 if (PyThread_acquire_lock(self->lock_lock, 0)) {
132 PyThread_release_lock(self->lock_lock);
133 PyErr_SetString(ThreadError, "release unlocked lock");
134 return NULL;
137 PyThread_release_lock(self->lock_lock);
138 Py_INCREF(Py_None);
139 return Py_None;
142 static char release_doc[] =
143 "release()\n\
144 (PyThread_release_lock() is an obsolete synonym)\n\
146 Release the lock, allowing another thread that is blocked waiting for\n\
147 the lock to acquire the lock. The lock must be in the locked state,\n\
148 but it needn't be locked by the same thread that unlocks it.";
150 static PyObject *
151 lock_locked_lock(self, args)
152 lockobject *self;
153 PyObject *args;
155 if (!PyArg_NoArgs(args))
156 return NULL;
158 if (PyThread_acquire_lock(self->lock_lock, 0)) {
159 PyThread_release_lock(self->lock_lock);
160 return PyInt_FromLong(0L);
162 return PyInt_FromLong(1L);
165 static char locked_doc[] =
166 "locked() -> Boolean\n\
167 (locked_lock() is an obsolete synonym)\n\
169 Return whether the lock is in the locked state.";
171 static PyMethodDef lock_methods[] = {
172 {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock, 0, acquire_doc},
173 {"acquire", (PyCFunction)lock_PyThread_acquire_lock, 0, acquire_doc},
174 {"release_lock", (PyCFunction)lock_PyThread_release_lock, 0, release_doc},
175 {"release", (PyCFunction)lock_PyThread_release_lock, 0, release_doc},
176 {"locked_lock", (PyCFunction)lock_locked_lock, 0, locked_doc},
177 {"locked", (PyCFunction)lock_locked_lock, 0, locked_doc},
178 {NULL, NULL} /* sentinel */
181 static PyObject *
182 lock_getattr(self, name)
183 lockobject *self;
184 char *name;
186 return Py_FindMethod(lock_methods, (PyObject *)self, name);
189 static PyTypeObject Locktype = {
190 PyObject_HEAD_INIT(&PyType_Type)
191 0, /*ob_size*/
192 "lock", /*tp_name*/
193 sizeof(lockobject), /*tp_size*/
194 0, /*tp_itemsize*/
195 /* methods */
196 (destructor)lock_dealloc, /*tp_dealloc*/
197 0, /*tp_print*/
198 (getattrfunc)lock_getattr, /*tp_getattr*/
199 0, /*tp_setattr*/
200 0, /*tp_compare*/
201 0, /*tp_repr*/
205 /* Module functions */
207 struct bootstate {
208 PyInterpreterState *interp;
209 PyObject *func;
210 PyObject *args;
211 PyObject *keyw;
214 static void
215 t_bootstrap(boot_raw)
216 void *boot_raw;
218 struct bootstate *boot = (struct bootstate *) boot_raw;
219 PyThreadState *tstate;
220 PyObject *res;
222 tstate = PyThreadState_New(boot->interp);
223 PyEval_AcquireThread(tstate);
224 res = PyEval_CallObjectWithKeywords(
225 boot->func, boot->args, boot->keyw);
226 Py_DECREF(boot->func);
227 Py_DECREF(boot->args);
228 Py_XDECREF(boot->keyw);
229 PyMem_DEL(boot_raw);
230 if (res == NULL) {
231 if (PyErr_ExceptionMatches(PyExc_SystemExit))
232 PyErr_Clear();
233 else {
234 fprintf(stderr, "Unhandled exception in thread:\n");
235 PyErr_PrintEx(0);
238 else
239 Py_DECREF(res);
240 PyThreadState_Clear(tstate);
241 PyEval_ReleaseThread(tstate);
242 PyThreadState_Delete(tstate);
243 PyThread_exit_thread();
246 static PyObject *
247 thread_PyThread_start_new_thread(self, fargs)
248 PyObject *self; /* Not used */
249 PyObject *fargs;
251 PyObject *func, *args = NULL, *keyw = NULL;
252 struct bootstate *boot;
254 if (!PyArg_ParseTuple(fargs, "OO|O", &func, &args, &keyw))
255 return NULL;
256 if (!PyCallable_Check(func)) {
257 PyErr_SetString(PyExc_TypeError,
258 "first arg must be callable");
259 return NULL;
261 if (!PyTuple_Check(args)) {
262 PyErr_SetString(PyExc_TypeError,
263 "optional 2nd arg must be a tuple");
264 return NULL;
266 if (keyw != NULL && !PyDict_Check(keyw)) {
267 PyErr_SetString(PyExc_TypeError,
268 "optional 3rd arg must be a dictionary");
269 return NULL;
271 boot = PyMem_NEW(struct bootstate, 1);
272 if (boot == NULL)
273 return PyErr_NoMemory();
274 boot->interp = PyThreadState_Get()->interp;
275 boot->func = func;
276 boot->args = args;
277 boot->keyw = keyw;
278 Py_INCREF(func);
279 Py_INCREF(args);
280 Py_XINCREF(keyw);
281 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
282 if (!PyThread_start_new_thread(t_bootstrap, (void*) boot)) {
283 PyErr_SetString(ThreadError, "can't start new thread\n");
284 Py_DECREF(func);
285 Py_DECREF(args);
286 Py_XDECREF(keyw);
287 PyMem_DEL(boot);
288 return NULL;
290 Py_INCREF(Py_None);
291 return Py_None;
294 static char start_new_doc[] =
295 "start_new_thread(functon, args[, kwargs])\n\
296 (start_new() is an obsolete synonym)\n\
298 Start a new thread. The thread will call the function with positional\n\
299 arguments from the tuple args and keyword arguments taken from the optional\n\
300 dictionary kwargs. The thread exits when the function returns; the return\n\
301 value is ignored. The thread will also exit when the function raises an\n\
302 unhandled exception; a stack trace will be printed unless the exception is\n\
303 SystemExit.";
305 static PyObject *
306 thread_PyThread_exit_thread(self, args)
307 PyObject *self; /* Not used */
308 PyObject *args;
310 if (!PyArg_NoArgs(args))
311 return NULL;
312 PyErr_SetNone(PyExc_SystemExit);
313 return NULL;
316 static char exit_doc[] =
317 "exit()\n\
318 (PyThread_exit_thread() is an obsolete synonym)\n\
320 This is synonymous to ``raise SystemExit''. It will cause the current\n\
321 thread to exit silently unless the exception is caught.";
323 #ifndef NO_EXIT_PROG
324 static PyObject *
325 thread_PyThread_exit_prog(self, args)
326 PyObject *self; /* Not used */
327 PyObject *args;
329 int sts;
330 if (!PyArg_Parse(args, "i", &sts))
331 return NULL;
332 Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
333 for (;;) { } /* Should not be reached */
335 #endif
337 static PyObject *
338 thread_PyThread_allocate_lock(self, args)
339 PyObject *self; /* Not used */
340 PyObject *args;
342 if (!PyArg_NoArgs(args))
343 return NULL;
344 return (PyObject *) newlockobject();
347 static char allocate_doc[] =
348 "allocate_lock() -> lock object\n\
349 (allocate() is an obsolete synonym)\n\
351 Create a new lock object. See LockType.__doc__ for information about locks.";
353 static PyObject *
354 thread_get_ident(self, args)
355 PyObject *self; /* Not used */
356 PyObject *args;
358 long ident;
359 if (!PyArg_NoArgs(args))
360 return NULL;
361 ident = PyThread_get_thread_ident();
362 if (ident == -1) {
363 PyErr_SetString(ThreadError, "no current thread ident");
364 return NULL;
366 return PyInt_FromLong(ident);
369 static char get_ident_doc[] =
370 "get_ident() -> integer\n\
372 Return a non-zero integer that uniquely identifies the current thread\n\
373 amongst other threads that exist simultaneously.\n\
374 This may be used to identify per-thread resources.\n\
375 Even though on some platforms threads identities may appear to be\n\
376 allocated consecutive numbers starting at 1, this behavior should not\n\
377 be relied upon, and the number should be seen purely as a magic cookie.\n\
378 A thread's identity may be reused for another thread after it exits.";
380 static PyMethodDef thread_methods[] = {
381 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, 1,
382 start_new_doc},
383 {"start_new", (PyCFunction)thread_PyThread_start_new_thread, 1,
384 start_new_doc},
385 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock, 0,
386 allocate_doc},
387 {"allocate", (PyCFunction)thread_PyThread_allocate_lock, 0,
388 allocate_doc},
389 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread, 0,
390 exit_doc},
391 {"exit", (PyCFunction)thread_PyThread_exit_thread, 0,
392 exit_doc},
393 {"get_ident", (PyCFunction)thread_get_ident, 0,
394 get_ident_doc},
395 #ifndef NO_EXIT_PROG
396 {"exit_prog", (PyCFunction)thread_PyThread_exit_prog},
397 #endif
398 {NULL, NULL} /* sentinel */
402 /* Initialization function */
404 static char thread_doc[] =
405 "This module provides primitive operations to write multi-threaded programs.\n\
406 The 'threading' module provides a more convenient interface.";
408 static char lock_doc[] =
409 "A lock object is a synchronization primitive. To create a lock,\n\
410 call the PyThread_allocate_lock() function. Methods are:\n\
412 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
413 release() -- unlock of the lock\n\
414 locked() -- test whether the lock is currently locked\n\
416 A lock is not owned by the thread that locked it; another thread may\n\
417 unlock it. A thread attempting to lock a lock that it has already locked\n\
418 will block until another thread unlocks it. Deadlocks may ensue.";
420 DL_EXPORT(void)
421 initthread()
423 PyObject *m, *d;
425 /* Create the module and add the functions */
426 m = Py_InitModule3("thread", thread_methods, thread_doc);
428 /* Add a symbolic constant */
429 d = PyModule_GetDict(m);
430 ThreadError = PyErr_NewException("thread.error", NULL, NULL);
431 PyDict_SetItemString(d, "error", ThreadError);
432 Locktype.tp_doc = lock_doc;
433 Py_INCREF(&Locktype);
434 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
436 /* Initialize the C thread library */
437 PyThread_init_thread();