append(): Fixing the test for convertability after consultation with
[python/dscho.git] / Modules / threadmodule.c
blob62fd76ada340ba8d6102236c5aed920531268e9d
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-threads 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 static 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 = 1;
59 if (!PyArg_ParseTuple(args, "|i:acquire", &i))
60 return NULL;
62 Py_BEGIN_ALLOW_THREADS
63 i = PyThread_acquire_lock(self->lock_lock, i);
64 Py_END_ALLOW_THREADS
66 if (args == NULL) {
67 Py_INCREF(Py_None);
68 return Py_None;
70 else
71 return PyBool_FromLong((long)i);
74 PyDoc_STRVAR(acquire_doc,
75 "acquire([wait]) -> None or bool\n\
76 (PyThread_acquire_lock() is an obsolete synonym)\n\
77 \n\
78 Lock the lock. Without argument, this blocks if the lock is already\n\
79 locked (even by the same thread), waiting for another thread to release\n\
80 the lock, and return None once the lock is acquired.\n\
81 With an argument, this will only block if the argument is true,\n\
82 and the return value reflects whether the lock is acquired.\n\
83 The blocking operation is not interruptible.");
85 static PyObject *
86 lock_PyThread_release_lock(lockobject *self)
88 /* Sanity check: the lock must be locked */
89 if (PyThread_acquire_lock(self->lock_lock, 0)) {
90 PyThread_release_lock(self->lock_lock);
91 PyErr_SetString(ThreadError, "release unlocked lock");
92 return NULL;
95 PyThread_release_lock(self->lock_lock);
96 Py_INCREF(Py_None);
97 return Py_None;
100 PyDoc_STRVAR(release_doc,
101 "release()\n\
102 (PyThread_release_lock() is an obsolete synonym)\n\
104 Release the lock, allowing another thread that is blocked waiting for\n\
105 the lock to acquire the lock. The lock must be in the locked state,\n\
106 but it needn't be locked by the same thread that unlocks it.");
108 static PyObject *
109 lock_locked_lock(lockobject *self)
111 if (PyThread_acquire_lock(self->lock_lock, 0)) {
112 PyThread_release_lock(self->lock_lock);
113 return PyBool_FromLong(0L);
115 return PyBool_FromLong(1L);
118 PyDoc_STRVAR(locked_doc,
119 "locked() -> bool\n\
120 (locked_lock() is an obsolete synonym)\n\
122 Return whether the lock is in the locked state.");
124 static PyMethodDef lock_methods[] = {
125 {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock,
126 METH_VARARGS, acquire_doc},
127 {"acquire", (PyCFunction)lock_PyThread_acquire_lock,
128 METH_VARARGS, acquire_doc},
129 {"release_lock", (PyCFunction)lock_PyThread_release_lock,
130 METH_NOARGS, release_doc},
131 {"release", (PyCFunction)lock_PyThread_release_lock,
132 METH_NOARGS, release_doc},
133 {"locked_lock", (PyCFunction)lock_locked_lock,
134 METH_NOARGS, locked_doc},
135 {"locked", (PyCFunction)lock_locked_lock,
136 METH_NOARGS, locked_doc},
137 {NULL, NULL} /* sentinel */
140 static PyObject *
141 lock_getattr(lockobject *self, char *name)
143 return Py_FindMethod(lock_methods, (PyObject *)self, name);
146 static PyTypeObject Locktype = {
147 PyObject_HEAD_INIT(&PyType_Type)
148 0, /*ob_size*/
149 "thread.lock", /*tp_name*/
150 sizeof(lockobject), /*tp_size*/
151 0, /*tp_itemsize*/
152 /* methods */
153 (destructor)lock_dealloc, /*tp_dealloc*/
154 0, /*tp_print*/
155 (getattrfunc)lock_getattr, /*tp_getattr*/
156 0, /*tp_setattr*/
157 0, /*tp_compare*/
158 0, /*tp_repr*/
162 /* Module functions */
164 struct bootstate {
165 PyInterpreterState *interp;
166 PyObject *func;
167 PyObject *args;
168 PyObject *keyw;
171 static void
172 t_bootstrap(void *boot_raw)
174 struct bootstate *boot = (struct bootstate *) boot_raw;
175 PyThreadState *tstate;
176 PyObject *res;
178 tstate = PyThreadState_New(boot->interp);
179 PyEval_AcquireThread(tstate);
180 res = PyEval_CallObjectWithKeywords(
181 boot->func, boot->args, boot->keyw);
182 Py_DECREF(boot->func);
183 Py_DECREF(boot->args);
184 Py_XDECREF(boot->keyw);
185 PyMem_DEL(boot_raw);
186 if (res == NULL) {
187 if (PyErr_ExceptionMatches(PyExc_SystemExit))
188 PyErr_Clear();
189 else {
190 PySys_WriteStderr("Unhandled exception in thread:\n");
191 PyErr_PrintEx(0);
194 else
195 Py_DECREF(res);
196 PyThreadState_Clear(tstate);
197 PyThreadState_DeleteCurrent();
198 PyThread_exit_thread();
201 static PyObject *
202 thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
204 PyObject *func, *args, *keyw = NULL;
205 struct bootstate *boot;
206 long ident;
208 if (!PyArg_ParseTuple(fargs, "OO|O:start_new_thread", &func, &args, &keyw))
209 return NULL;
210 if (!PyCallable_Check(func)) {
211 PyErr_SetString(PyExc_TypeError,
212 "first arg must be callable");
213 return NULL;
215 if (!PyTuple_Check(args)) {
216 PyErr_SetString(PyExc_TypeError,
217 "2nd arg must be a tuple");
218 return NULL;
220 if (keyw != NULL && !PyDict_Check(keyw)) {
221 PyErr_SetString(PyExc_TypeError,
222 "optional 3rd arg must be a dictionary");
223 return NULL;
225 boot = PyMem_NEW(struct bootstate, 1);
226 if (boot == NULL)
227 return PyErr_NoMemory();
228 boot->interp = PyThreadState_Get()->interp;
229 boot->func = func;
230 boot->args = args;
231 boot->keyw = keyw;
232 Py_INCREF(func);
233 Py_INCREF(args);
234 Py_XINCREF(keyw);
235 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
236 ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
237 if (ident == -1) {
238 PyErr_SetString(ThreadError, "can't start new thread\n");
239 Py_DECREF(func);
240 Py_DECREF(args);
241 Py_XDECREF(keyw);
242 PyMem_DEL(boot);
243 return NULL;
245 return PyInt_FromLong(ident);
248 PyDoc_STRVAR(start_new_doc,
249 "start_new_thread(function, args[, kwargs])\n\
250 (start_new() is an obsolete synonym)\n\
252 Start a new thread and return its identifier. The thread will call the\n\
253 function with positional arguments from the tuple args and keyword arguments\n\
254 taken from the optional dictionary kwargs. The thread exits when the\n\
255 function returns; the return value is ignored. The thread will also exit\n\
256 when the function raises an unhandled exception; a stack trace will be\n\
257 printed unless the exception is SystemExit.\n");
259 static PyObject *
260 thread_PyThread_exit_thread(PyObject *self)
262 PyErr_SetNone(PyExc_SystemExit);
263 return NULL;
266 PyDoc_STRVAR(exit_doc,
267 "exit()\n\
268 (PyThread_exit_thread() is an obsolete synonym)\n\
270 This is synonymous to ``raise SystemExit''. It will cause the current\n\
271 thread to exit silently unless the exception is caught.");
273 #ifndef NO_EXIT_PROG
274 static PyObject *
275 thread_PyThread_exit_prog(PyObject *self, PyObject *args)
277 int sts;
278 if (!PyArg_ParseTuple(args, "i:exit_prog", &sts))
279 return NULL;
280 Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
281 for (;;) { } /* Should not be reached */
283 #endif
285 static PyObject *
286 thread_PyThread_allocate_lock(PyObject *self)
288 return (PyObject *) newlockobject();
291 PyDoc_STRVAR(allocate_doc,
292 "allocate_lock() -> lock object\n\
293 (allocate() is an obsolete synonym)\n\
295 Create a new lock object. See LockType.__doc__ for information about locks.");
297 static PyObject *
298 thread_get_ident(PyObject *self)
300 long ident;
301 ident = PyThread_get_thread_ident();
302 if (ident == -1) {
303 PyErr_SetString(ThreadError, "no current thread ident");
304 return NULL;
306 return PyInt_FromLong(ident);
309 PyDoc_STRVAR(get_ident_doc,
310 "get_ident() -> integer\n\
312 Return a non-zero integer that uniquely identifies the current thread\n\
313 amongst other threads that exist simultaneously.\n\
314 This may be used to identify per-thread resources.\n\
315 Even though on some platforms threads identities may appear to be\n\
316 allocated consecutive numbers starting at 1, this behavior should not\n\
317 be relied upon, and the number should be seen purely as a magic cookie.\n\
318 A thread's identity may be reused for another thread after it exits.");
320 static PyMethodDef thread_methods[] = {
321 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
322 METH_VARARGS,
323 start_new_doc},
324 {"start_new", (PyCFunction)thread_PyThread_start_new_thread,
325 METH_VARARGS,
326 start_new_doc},
327 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
328 METH_NOARGS, allocate_doc},
329 {"allocate", (PyCFunction)thread_PyThread_allocate_lock,
330 METH_NOARGS, allocate_doc},
331 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread,
332 METH_NOARGS, exit_doc},
333 {"exit", (PyCFunction)thread_PyThread_exit_thread,
334 METH_NOARGS, exit_doc},
335 {"get_ident", (PyCFunction)thread_get_ident,
336 METH_NOARGS, get_ident_doc},
337 #ifndef NO_EXIT_PROG
338 {"exit_prog", (PyCFunction)thread_PyThread_exit_prog,
339 METH_VARARGS},
340 #endif
341 {NULL, NULL} /* sentinel */
345 /* Initialization function */
347 PyDoc_STRVAR(thread_doc,
348 "This module provides primitive operations to write multi-threaded programs.\n\
349 The 'threading' module provides a more convenient interface.");
351 PyDoc_STRVAR(lock_doc,
352 "A lock object is a synchronization primitive. To create a lock,\n\
353 call the PyThread_allocate_lock() function. Methods are:\n\
355 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
356 release() -- unlock of the lock\n\
357 locked() -- test whether the lock is currently locked\n\
359 A lock is not owned by the thread that locked it; another thread may\n\
360 unlock it. A thread attempting to lock a lock that it has already locked\n\
361 will block until another thread unlocks it. Deadlocks may ensue.");
363 PyMODINIT_FUNC
364 initthread(void)
366 PyObject *m, *d;
368 /* Create the module and add the functions */
369 m = Py_InitModule3("thread", thread_methods, thread_doc);
371 /* Add a symbolic constant */
372 d = PyModule_GetDict(m);
373 ThreadError = PyErr_NewException("thread.error", NULL, NULL);
374 PyDict_SetItemString(d, "error", ThreadError);
375 Locktype.tp_doc = lock_doc;
376 Py_INCREF(&Locktype);
377 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
379 /* Initialize the C thread library */
380 PyThread_init_thread();