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-thread option."
10 #error "Then run `make clean' followed by `make'."
15 static PyObject
*ThreadError
;
22 PyThread_type_lock lock_lock
;
25 staticforward 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
)
60 if (!PyArg_Parse(args
, "i", &i
))
66 Py_BEGIN_ALLOW_THREADS
67 i
= PyThread_acquire_lock(self
->lock_lock
, i
);
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\
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.";
90 lock_PyThread_release_lock(lockobject
*self
, PyObject
*args
)
92 if (!PyArg_NoArgs(args
))
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");
102 PyThread_release_lock(self
->lock_lock
);
107 static char release_doc
[] =
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.";
116 lock_locked_lock(lockobject
*self
, PyObject
*args
)
118 if (!PyArg_NoArgs(args
))
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 */
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
)
160 sizeof(lockobject
), /*tp_size*/
163 (destructor
)lock_dealloc
, /*tp_dealloc*/
165 (getattrfunc
)lock_getattr
, /*tp_getattr*/
172 /* Module functions */
175 PyInterpreterState
*interp
;
182 t_bootstrap(void *boot_raw
)
184 struct bootstate
*boot
= (struct bootstate
*) boot_raw
;
185 PyThreadState
*tstate
;
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
);
197 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
200 PySys_WriteStderr("Unhandled exception in thread:\n");
206 PyThreadState_Clear(tstate
);
207 PyThreadState_DeleteCurrent();
208 PyThread_exit_thread();
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
))
219 if (!PyCallable_Check(func
)) {
220 PyErr_SetString(PyExc_TypeError
,
221 "first arg must be callable");
224 if (!PyTuple_Check(args
)) {
225 PyErr_SetString(PyExc_TypeError
,
226 "2nd arg must be a tuple");
229 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
230 PyErr_SetString(PyExc_TypeError
,
231 "optional 3rd arg must be a dictionary");
234 boot
= PyMem_NEW(struct bootstate
, 1);
236 return PyErr_NoMemory();
237 boot
->interp
= PyThreadState_Get()->interp
;
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");
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\
269 thread_PyThread_exit_thread(PyObject
*self
, PyObject
*args
)
271 if (!PyArg_NoArgs(args
))
273 PyErr_SetNone(PyExc_SystemExit
);
277 static char exit_doc
[] =
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.";
286 thread_PyThread_exit_prog(PyObject
*self
, PyObject
*args
)
289 if (!PyArg_Parse(args
, "i", &sts
))
291 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
292 for (;;) { } /* Should not be reached */
297 thread_PyThread_allocate_lock(PyObject
*self
, PyObject
*args
)
299 if (!PyArg_NoArgs(args
))
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.";
311 thread_get_ident(PyObject
*self
, PyObject
*args
)
314 if (!PyArg_NoArgs(args
))
316 ident
= PyThread_get_thread_ident();
318 PyErr_SetString(ThreadError
, "no current thread ident");
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
,
339 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
,
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
},
353 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
},
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.";
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();