_make_boundary(): Fix for SF bug #745478, broken boundary calculation
[python/dscho.git] / Modules / threadmodule.c
blob8b174b3af538f09b0123dc24d5970b8a39e65f6b
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 if (res == NULL) {
183 if (PyErr_ExceptionMatches(PyExc_SystemExit))
184 PyErr_Clear();
185 else {
186 PyObject *file;
187 PySys_WriteStderr(
188 "Unhandled exception in thread started by ");
189 file = PySys_GetObject("stderr");
190 if (file)
191 PyFile_WriteObject(boot->func, file, 0);
192 else
193 PyObject_Print(boot->func, stderr, 0);
194 PySys_WriteStderr("\n");
195 PyErr_PrintEx(0);
198 else
199 Py_DECREF(res);
200 Py_DECREF(boot->func);
201 Py_DECREF(boot->args);
202 Py_XDECREF(boot->keyw);
203 PyMem_DEL(boot_raw);
204 PyThreadState_Clear(tstate);
205 PyThreadState_DeleteCurrent();
206 PyThread_exit_thread();
209 static PyObject *
210 thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
212 PyObject *func, *args, *keyw = NULL;
213 struct bootstate *boot;
214 long ident;
216 if (!PyArg_ParseTuple(fargs, "OO|O:start_new_thread", &func, &args, &keyw))
217 return NULL;
218 if (!PyCallable_Check(func)) {
219 PyErr_SetString(PyExc_TypeError,
220 "first arg must be callable");
221 return NULL;
223 if (!PyTuple_Check(args)) {
224 PyErr_SetString(PyExc_TypeError,
225 "2nd arg must be a tuple");
226 return NULL;
228 if (keyw != NULL && !PyDict_Check(keyw)) {
229 PyErr_SetString(PyExc_TypeError,
230 "optional 3rd arg must be a dictionary");
231 return NULL;
233 boot = PyMem_NEW(struct bootstate, 1);
234 if (boot == NULL)
235 return PyErr_NoMemory();
236 boot->interp = PyThreadState_Get()->interp;
237 boot->func = func;
238 boot->args = args;
239 boot->keyw = keyw;
240 Py_INCREF(func);
241 Py_INCREF(args);
242 Py_XINCREF(keyw);
243 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
244 ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
245 if (ident == -1) {
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 return PyInt_FromLong(ident);
256 PyDoc_STRVAR(start_new_doc,
257 "start_new_thread(function, args[, kwargs])\n\
258 (start_new() is an obsolete synonym)\n\
260 Start a new thread and return its identifier. The thread will call the\n\
261 function with positional arguments from the tuple args and keyword arguments\n\
262 taken from the optional dictionary kwargs. The thread exits when the\n\
263 function returns; the return value is ignored. The thread will also exit\n\
264 when the function raises an unhandled exception; a stack trace will be\n\
265 printed unless the exception is SystemExit.\n");
267 static PyObject *
268 thread_PyThread_exit_thread(PyObject *self)
270 PyErr_SetNone(PyExc_SystemExit);
271 return NULL;
274 PyDoc_STRVAR(exit_doc,
275 "exit()\n\
276 (PyThread_exit_thread() is an obsolete synonym)\n\
278 This is synonymous to ``raise SystemExit''. It will cause the current\n\
279 thread to exit silently unless the exception is caught.");
281 #ifndef NO_EXIT_PROG
282 static PyObject *
283 thread_PyThread_exit_prog(PyObject *self, PyObject *args)
285 int sts;
286 if (!PyArg_ParseTuple(args, "i:exit_prog", &sts))
287 return NULL;
288 Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
289 for (;;) { } /* Should not be reached */
291 #endif
293 static PyObject *
294 thread_PyThread_allocate_lock(PyObject *self)
296 return (PyObject *) newlockobject();
299 PyDoc_STRVAR(allocate_doc,
300 "allocate_lock() -> lock object\n\
301 (allocate() is an obsolete synonym)\n\
303 Create a new lock object. See LockType.__doc__ for information about locks.");
305 static PyObject *
306 thread_get_ident(PyObject *self)
308 long ident;
309 ident = PyThread_get_thread_ident();
310 if (ident == -1) {
311 PyErr_SetString(ThreadError, "no current thread ident");
312 return NULL;
314 return PyInt_FromLong(ident);
317 PyDoc_STRVAR(get_ident_doc,
318 "get_ident() -> integer\n\
320 Return a non-zero integer that uniquely identifies the current thread\n\
321 amongst other threads that exist simultaneously.\n\
322 This may be used to identify per-thread resources.\n\
323 Even though on some platforms threads identities may appear to be\n\
324 allocated consecutive numbers starting at 1, this behavior should not\n\
325 be relied upon, and the number should be seen purely as a magic cookie.\n\
326 A thread's identity may be reused for another thread after it exits.");
328 static PyMethodDef thread_methods[] = {
329 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
330 METH_VARARGS,
331 start_new_doc},
332 {"start_new", (PyCFunction)thread_PyThread_start_new_thread,
333 METH_VARARGS,
334 start_new_doc},
335 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock,
336 METH_NOARGS, allocate_doc},
337 {"allocate", (PyCFunction)thread_PyThread_allocate_lock,
338 METH_NOARGS, allocate_doc},
339 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread,
340 METH_NOARGS, exit_doc},
341 {"exit", (PyCFunction)thread_PyThread_exit_thread,
342 METH_NOARGS, exit_doc},
343 {"get_ident", (PyCFunction)thread_get_ident,
344 METH_NOARGS, get_ident_doc},
345 #ifndef NO_EXIT_PROG
346 {"exit_prog", (PyCFunction)thread_PyThread_exit_prog,
347 METH_VARARGS},
348 #endif
349 {NULL, NULL} /* sentinel */
353 /* Initialization function */
355 PyDoc_STRVAR(thread_doc,
356 "This module provides primitive operations to write multi-threaded programs.\n\
357 The 'threading' module provides a more convenient interface.");
359 PyDoc_STRVAR(lock_doc,
360 "A lock object is a synchronization primitive. To create a lock,\n\
361 call the PyThread_allocate_lock() function. Methods are:\n\
363 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
364 release() -- unlock of the lock\n\
365 locked() -- test whether the lock is currently locked\n\
367 A lock is not owned by the thread that locked it; another thread may\n\
368 unlock it. A thread attempting to lock a lock that it has already locked\n\
369 will block until another thread unlocks it. Deadlocks may ensue.");
371 PyMODINIT_FUNC
372 initthread(void)
374 PyObject *m, *d;
376 /* Create the module and add the functions */
377 m = Py_InitModule3("thread", thread_methods, thread_doc);
379 /* Add a symbolic constant */
380 d = PyModule_GetDict(m);
381 ThreadError = PyErr_NewException("thread.error", NULL, NULL);
382 PyDict_SetItemString(d, "error", ThreadError);
383 Locktype.tp_doc = lock_doc;
384 Py_INCREF(&Locktype);
385 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype);
387 /* Initialize the C thread library */
388 PyThread_init_thread();