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
);
183 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
188 "Unhandled exception in thread started by ");
189 file
= PySys_GetObject("stderr");
191 PyFile_WriteObject(boot
->func
, file
, 0);
193 PyObject_Print(boot
->func
, stderr
, 0);
194 PySys_WriteStderr("\n");
200 Py_DECREF(boot
->func
);
201 Py_DECREF(boot
->args
);
202 Py_XDECREF(boot
->keyw
);
204 PyThreadState_Clear(tstate
);
205 PyThreadState_DeleteCurrent();
206 PyThread_exit_thread();
210 thread_PyThread_start_new_thread(PyObject
*self
, PyObject
*fargs
)
212 PyObject
*func
, *args
, *keyw
= NULL
;
213 struct bootstate
*boot
;
216 if (!PyArg_ParseTuple(fargs
, "OO|O:start_new_thread", &func
, &args
, &keyw
))
218 if (!PyCallable_Check(func
)) {
219 PyErr_SetString(PyExc_TypeError
,
220 "first arg must be callable");
223 if (!PyTuple_Check(args
)) {
224 PyErr_SetString(PyExc_TypeError
,
225 "2nd arg must be a tuple");
228 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
229 PyErr_SetString(PyExc_TypeError
,
230 "optional 3rd arg must be a dictionary");
233 boot
= PyMem_NEW(struct bootstate
, 1);
235 return PyErr_NoMemory();
236 boot
->interp
= PyThreadState_Get()->interp
;
243 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
244 ident
= PyThread_start_new_thread(t_bootstrap
, (void*) boot
);
246 PyErr_SetString(ThreadError
, "can't start new thread\n");
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");
268 thread_PyThread_exit_thread(PyObject
*self
)
270 PyErr_SetNone(PyExc_SystemExit
);
274 PyDoc_STRVAR(exit_doc
,
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.");
283 thread_PyThread_exit_prog(PyObject
*self
, PyObject
*args
)
286 if (!PyArg_ParseTuple(args
, "i:exit_prog", &sts
))
288 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
289 for (;;) { } /* Should not be reached */
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.");
306 thread_get_ident(PyObject
*self
)
309 ident
= PyThread_get_thread_ident();
311 PyErr_SetString(ThreadError
, "no current thread ident");
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
,
332 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
,
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
},
346 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
,
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.");
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();