1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
33 /* Interface to Sjoerd's portable C thread library */
38 #error "Error! The rest of Python is not compiled with thread support."
39 #error "Rerun configure, adding a --with-thread option."
40 #error "Then run `make clean' followed by `make'."
45 static PyObject
*ThreadError
;
52 PyThread_type_lock lock_lock
;
55 staticforward PyTypeObject Locktype
;
61 self
= PyObject_NEW(lockobject
, &Locktype
);
64 self
->lock_lock
= PyThread_allocate_lock();
65 if (self
->lock_lock
== NULL
) {
68 PyErr_SetString(ThreadError
, "can't allocate lock");
77 /* Unlock the lock so it's safe to free it */
78 PyThread_acquire_lock(self
->lock_lock
, 0);
79 PyThread_release_lock(self
->lock_lock
);
81 PyThread_free_lock(self
->lock_lock
);
86 lock_PyThread_acquire_lock(self
, args
)
93 if (!PyArg_Parse(args
, "i", &i
))
99 Py_BEGIN_ALLOW_THREADS
100 i
= PyThread_acquire_lock(self
->lock_lock
, i
);
108 return PyInt_FromLong((long)i
);
111 static char acquire_doc
[] =
112 "acquire([wait]) -> None or Boolean\n\
113 (PyThread_acquire_lock() is an obsolete synonym)\n\
115 Lock the lock. Without argument, this blocks if the lock is already\n\
116 locked (even by the same thread), waiting for another thread to release\n\
117 the lock, and return None when the lock is acquired.\n\
118 With a Boolean argument, this will only block if the argument is true,\n\
119 and the return value reflects whether the lock is acquired.\n\
120 The blocking operation is not interruptible.";
123 lock_PyThread_release_lock(self
, args
)
127 if (!PyArg_NoArgs(args
))
130 /* Sanity check: the lock must be locked */
131 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
132 PyThread_release_lock(self
->lock_lock
);
133 PyErr_SetString(ThreadError
, "release unlocked lock");
137 PyThread_release_lock(self
->lock_lock
);
142 static char release_doc
[] =
144 (PyThread_release_lock() is an obsolete synonym)\n\
146 Release the lock, allowing another thread that is blocked waiting for\n\
147 the lock to acquire the lock. The lock must be in the locked state,\n\
148 but it needn't be locked by the same thread that unlocks it.";
151 lock_locked_lock(self
, args
)
155 if (!PyArg_NoArgs(args
))
158 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
159 PyThread_release_lock(self
->lock_lock
);
160 return PyInt_FromLong(0L);
162 return PyInt_FromLong(1L);
165 static char locked_doc
[] =
166 "locked() -> Boolean\n\
167 (locked_lock() is an obsolete synonym)\n\
169 Return whether the lock is in the locked state.";
171 static PyMethodDef lock_methods
[] = {
172 {"acquire_lock", (PyCFunction
)lock_PyThread_acquire_lock
, 0, acquire_doc
},
173 {"acquire", (PyCFunction
)lock_PyThread_acquire_lock
, 0, acquire_doc
},
174 {"release_lock", (PyCFunction
)lock_PyThread_release_lock
, 0, release_doc
},
175 {"release", (PyCFunction
)lock_PyThread_release_lock
, 0, release_doc
},
176 {"locked_lock", (PyCFunction
)lock_locked_lock
, 0, locked_doc
},
177 {"locked", (PyCFunction
)lock_locked_lock
, 0, locked_doc
},
178 {NULL
, NULL
} /* sentinel */
182 lock_getattr(self
, name
)
186 return Py_FindMethod(lock_methods
, (PyObject
*)self
, name
);
189 static PyTypeObject Locktype
= {
190 PyObject_HEAD_INIT(&PyType_Type
)
193 sizeof(lockobject
), /*tp_size*/
196 (destructor
)lock_dealloc
, /*tp_dealloc*/
198 (getattrfunc
)lock_getattr
, /*tp_getattr*/
205 /* Module functions */
208 PyInterpreterState
*interp
;
215 t_bootstrap(boot_raw
)
218 struct bootstate
*boot
= (struct bootstate
*) boot_raw
;
219 PyThreadState
*tstate
;
222 tstate
= PyThreadState_New(boot
->interp
);
223 PyEval_AcquireThread(tstate
);
224 res
= PyEval_CallObjectWithKeywords(
225 boot
->func
, boot
->args
, boot
->keyw
);
226 Py_DECREF(boot
->func
);
227 Py_DECREF(boot
->args
);
228 Py_XDECREF(boot
->keyw
);
231 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
234 fprintf(stderr
, "Unhandled exception in thread:\n");
240 PyThreadState_Clear(tstate
);
241 PyEval_ReleaseThread(tstate
);
242 PyThreadState_Delete(tstate
);
243 PyThread_exit_thread();
247 thread_PyThread_start_new_thread(self
, fargs
)
248 PyObject
*self
; /* Not used */
251 PyObject
*func
, *args
= NULL
, *keyw
= NULL
;
252 struct bootstate
*boot
;
254 if (!PyArg_ParseTuple(fargs
, "OO|O", &func
, &args
, &keyw
))
256 if (!PyCallable_Check(func
)) {
257 PyErr_SetString(PyExc_TypeError
,
258 "first arg must be callable");
261 if (!PyTuple_Check(args
)) {
262 PyErr_SetString(PyExc_TypeError
,
263 "optional 2nd arg must be a tuple");
266 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
267 PyErr_SetString(PyExc_TypeError
,
268 "optional 3rd arg must be a dictionary");
271 boot
= PyMem_NEW(struct bootstate
, 1);
273 return PyErr_NoMemory();
274 boot
->interp
= PyThreadState_Get()->interp
;
281 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
282 if (!PyThread_start_new_thread(t_bootstrap
, (void*) boot
)) {
283 PyErr_SetString(ThreadError
, "can't start new thread\n");
294 static char start_new_doc
[] =
295 "start_new_thread(functon, args[, kwargs])\n\
296 (start_new() is an obsolete synonym)\n\
298 Start a new thread. The thread will call the function with positional\n\
299 arguments from the tuple args and keyword arguments taken from the optional\n\
300 dictionary kwargs. The thread exits when the function returns; the return\n\
301 value is ignored. The thread will also exit when the function raises an\n\
302 unhandled exception; a stack trace will be printed unless the exception is\n\
306 thread_PyThread_exit_thread(self
, args
)
307 PyObject
*self
; /* Not used */
310 if (!PyArg_NoArgs(args
))
312 PyErr_SetNone(PyExc_SystemExit
);
316 static char exit_doc
[] =
318 (PyThread_exit_thread() is an obsolete synonym)\n\
320 This is synonymous to ``raise SystemExit''. It will cause the current\n\
321 thread to exit silently unless the exception is caught.";
325 thread_PyThread_exit_prog(self
, args
)
326 PyObject
*self
; /* Not used */
330 if (!PyArg_Parse(args
, "i", &sts
))
332 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
333 for (;;) { } /* Should not be reached */
338 thread_PyThread_allocate_lock(self
, args
)
339 PyObject
*self
; /* Not used */
342 if (!PyArg_NoArgs(args
))
344 return (PyObject
*) newlockobject();
347 static char allocate_doc
[] =
348 "allocate_lock() -> lock object\n\
349 (allocate() is an obsolete synonym)\n\
351 Create a new lock object. See LockType.__doc__ for information about locks.";
354 thread_get_ident(self
, args
)
355 PyObject
*self
; /* Not used */
359 if (!PyArg_NoArgs(args
))
361 ident
= PyThread_get_thread_ident();
363 PyErr_SetString(ThreadError
, "no current thread ident");
366 return PyInt_FromLong(ident
);
369 static char get_ident_doc
[] =
370 "get_ident() -> integer\n\
372 Return a non-zero integer that uniquely identifies the current thread\n\
373 amongst other threads that exist simultaneously.\n\
374 This may be used to identify per-thread resources.\n\
375 Even though on some platforms threads identities may appear to be\n\
376 allocated consecutive numbers starting at 1, this behavior should not\n\
377 be relied upon, and the number should be seen purely as a magic cookie.\n\
378 A thread's identity may be reused for another thread after it exits.";
380 static PyMethodDef thread_methods
[] = {
381 {"start_new_thread", (PyCFunction
)thread_PyThread_start_new_thread
, 1,
383 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
, 1,
385 {"allocate_lock", (PyCFunction
)thread_PyThread_allocate_lock
, 0,
387 {"allocate", (PyCFunction
)thread_PyThread_allocate_lock
, 0,
389 {"exit_thread", (PyCFunction
)thread_PyThread_exit_thread
, 0,
391 {"exit", (PyCFunction
)thread_PyThread_exit_thread
, 0,
393 {"get_ident", (PyCFunction
)thread_get_ident
, 0,
396 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
},
398 {NULL
, NULL
} /* sentinel */
402 /* Initialization function */
404 static char thread_doc
[] =
405 "This module provides primitive operations to write multi-threaded programs.\n\
406 The 'threading' module provides a more convenient interface.";
408 static char lock_doc
[] =
409 "A lock object is a synchronization primitive. To create a lock,\n\
410 call the PyThread_allocate_lock() function. Methods are:\n\
412 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
413 release() -- unlock of the lock\n\
414 locked() -- test whether the lock is currently locked\n\
416 A lock is not owned by the thread that locked it; another thread may\n\
417 unlock it. A thread attempting to lock a lock that it has already locked\n\
418 will block until another thread unlocks it. Deadlocks may ensue.";
425 /* Create the module and add the functions */
426 m
= Py_InitModule3("thread", thread_methods
, thread_doc
);
428 /* Add a symbolic constant */
429 d
= PyModule_GetDict(m
);
430 ThreadError
= PyErr_NewException("thread.error", NULL
, NULL
);
431 PyDict_SetItemString(d
, "error", ThreadError
);
432 Locktype
.tp_doc
= lock_doc
;
433 Py_INCREF(&Locktype
);
434 PyDict_SetItemString(d
, "LockType", (PyObject
*)&Locktype
);
436 /* Initialize the C thread library */
437 PyThread_init_thread();