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
;
25 static PyTypeObject Locktype
;
31 self
= PyObject_New(lockobject
, &Locktype
);
34 self
->lock_lock
= PyThread_allocate_lock();
35 if (self
->lock_lock
== NULL
) {
38 PyErr_SetString(ThreadError
, "can't allocate lock");
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
);
55 lock_PyThread_acquire_lock(lockobject
*self
, PyObject
*args
)
59 if (!PyArg_ParseTuple(args
, "|i:acquire", &i
))
62 Py_BEGIN_ALLOW_THREADS
63 i
= PyThread_acquire_lock(self
->lock_lock
, i
);
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\
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.");
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");
95 PyThread_release_lock(self
->lock_lock
);
100 PyDoc_STRVAR(release_doc
,
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.");
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
,
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 */
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
)
149 "thread.lock", /*tp_name*/
150 sizeof(lockobject
), /*tp_size*/
153 (destructor
)lock_dealloc
, /*tp_dealloc*/
155 (getattrfunc
)lock_getattr
, /*tp_getattr*/
162 /* Module functions */
165 PyInterpreterState
*interp
;
172 t_bootstrap(void *boot_raw
)
174 struct bootstate
*boot
= (struct bootstate
*) boot_raw
;
175 PyThreadState
*tstate
;
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
);
187 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
190 PySys_WriteStderr("Unhandled exception in thread:\n");
196 PyThreadState_Clear(tstate
);
197 PyThreadState_DeleteCurrent();
198 PyThread_exit_thread();
202 thread_PyThread_start_new_thread(PyObject
*self
, PyObject
*fargs
)
204 PyObject
*func
, *args
, *keyw
= NULL
;
205 struct bootstate
*boot
;
208 if (!PyArg_ParseTuple(fargs
, "OO|O:start_new_thread", &func
, &args
, &keyw
))
210 if (!PyCallable_Check(func
)) {
211 PyErr_SetString(PyExc_TypeError
,
212 "first arg must be callable");
215 if (!PyTuple_Check(args
)) {
216 PyErr_SetString(PyExc_TypeError
,
217 "2nd arg must be a tuple");
220 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
221 PyErr_SetString(PyExc_TypeError
,
222 "optional 3rd arg must be a dictionary");
225 boot
= PyMem_NEW(struct bootstate
, 1);
227 return PyErr_NoMemory();
228 boot
->interp
= PyThreadState_Get()->interp
;
235 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
236 ident
= PyThread_start_new_thread(t_bootstrap
, (void*) boot
);
238 PyErr_SetString(ThreadError
, "can't start new thread\n");
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");
260 thread_PyThread_exit_thread(PyObject
*self
)
262 PyErr_SetNone(PyExc_SystemExit
);
266 PyDoc_STRVAR(exit_doc
,
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.");
275 thread_PyThread_exit_prog(PyObject
*self
, PyObject
*args
)
278 if (!PyArg_ParseTuple(args
, "i:exit_prog", &sts
))
280 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
281 for (;;) { } /* Should not be reached */
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.");
298 thread_get_ident(PyObject
*self
)
301 ident
= PyThread_get_thread_ident();
303 PyErr_SetString(ThreadError
, "no current thread ident");
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
,
324 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
,
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
},
338 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
,
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.");
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();