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
;
26 lock_dealloc(lockobject
*self
)
28 assert(self
->lock_lock
);
29 /* Unlock the lock so it's safe to free it */
30 PyThread_acquire_lock(self
->lock_lock
, 0);
31 PyThread_release_lock(self
->lock_lock
);
33 PyThread_free_lock(self
->lock_lock
);
38 lock_PyThread_acquire_lock(lockobject
*self
, PyObject
*args
)
42 if (!PyArg_ParseTuple(args
, "|i:acquire", &i
))
45 Py_BEGIN_ALLOW_THREADS
46 i
= PyThread_acquire_lock(self
->lock_lock
, i
);
49 return PyBool_FromLong((long)i
);
52 PyDoc_STRVAR(acquire_doc
,
53 "acquire([wait]) -> None or bool\n\
54 (acquire_lock() is an obsolete synonym)\n\
56 Lock the lock. Without argument, this blocks if the lock is already\n\
57 locked (even by the same thread), waiting for another thread to release\n\
58 the lock, and return None once the lock is acquired.\n\
59 With an argument, this will only block if the argument is true,\n\
60 and the return value reflects whether the lock is acquired.\n\
61 The blocking operation is not interruptible.");
64 lock_PyThread_release_lock(lockobject
*self
)
66 /* Sanity check: the lock must be locked */
67 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
68 PyThread_release_lock(self
->lock_lock
);
69 PyErr_SetString(ThreadError
, "release unlocked lock");
73 PyThread_release_lock(self
->lock_lock
);
78 PyDoc_STRVAR(release_doc
,
80 (release_lock() is an obsolete synonym)\n\
82 Release the lock, allowing another thread that is blocked waiting for\n\
83 the lock to acquire the lock. The lock must be in the locked state,\n\
84 but it needn't be locked by the same thread that unlocks it.");
87 lock_locked_lock(lockobject
*self
)
89 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
90 PyThread_release_lock(self
->lock_lock
);
91 return PyBool_FromLong(0L);
93 return PyBool_FromLong(1L);
96 PyDoc_STRVAR(locked_doc
,
98 (locked_lock() is an obsolete synonym)\n\
100 Return whether the lock is in the locked state.");
102 static PyMethodDef lock_methods
[] = {
103 {"acquire_lock", (PyCFunction
)lock_PyThread_acquire_lock
,
104 METH_VARARGS
, acquire_doc
},
105 {"acquire", (PyCFunction
)lock_PyThread_acquire_lock
,
106 METH_VARARGS
, acquire_doc
},
107 {"release_lock", (PyCFunction
)lock_PyThread_release_lock
,
108 METH_NOARGS
, release_doc
},
109 {"release", (PyCFunction
)lock_PyThread_release_lock
,
110 METH_NOARGS
, release_doc
},
111 {"locked_lock", (PyCFunction
)lock_locked_lock
,
112 METH_NOARGS
, locked_doc
},
113 {"locked", (PyCFunction
)lock_locked_lock
,
114 METH_NOARGS
, locked_doc
},
115 {"__enter__", (PyCFunction
)lock_PyThread_acquire_lock
,
116 METH_VARARGS
, acquire_doc
},
117 {"__exit__", (PyCFunction
)lock_PyThread_release_lock
,
118 METH_VARARGS
, release_doc
},
119 {NULL
, NULL
} /* sentinel */
123 lock_getattr(lockobject
*self
, char *name
)
125 return Py_FindMethod(lock_methods
, (PyObject
*)self
, name
);
128 static PyTypeObject Locktype
= {
129 PyObject_HEAD_INIT(&PyType_Type
)
131 "thread.lock", /*tp_name*/
132 sizeof(lockobject
), /*tp_size*/
135 (destructor
)lock_dealloc
, /*tp_dealloc*/
137 (getattrfunc
)lock_getattr
, /*tp_getattr*/
147 self
= PyObject_New(lockobject
, &Locktype
);
150 self
->lock_lock
= PyThread_allocate_lock();
151 if (self
->lock_lock
== NULL
) {
154 PyErr_SetString(ThreadError
, "can't allocate lock");
159 /* Thread-local objects */
161 #include "structmember.h"
172 local_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kw
)
177 if (type
->tp_init
== PyBaseObject_Type
.tp_init
178 && ((args
&& PyObject_IsTrue(args
))
179 || (kw
&& PyObject_IsTrue(kw
)))) {
180 PyErr_SetString(PyExc_TypeError
,
181 "Initialization arguments are not supported");
185 self
= (localobject
*)type
->tp_alloc(type
, 0);
193 self
->dict
= NULL
; /* making sure */
194 self
->key
= PyString_FromFormat("thread.local.%p", self
);
195 if (self
->key
== NULL
)
198 self
->dict
= PyDict_New();
199 if (self
->dict
== NULL
)
202 tdict
= PyThreadState_GetDict();
204 PyErr_SetString(PyExc_SystemError
,
205 "Couldn't get thread-state dictionary");
209 if (PyDict_SetItem(tdict
, self
->key
, self
->dict
) < 0)
212 return (PyObject
*)self
;
220 local_traverse(localobject
*self
, visitproc visit
, void *arg
)
222 Py_VISIT(self
->args
);
224 Py_VISIT(self
->dict
);
229 local_clear(localobject
*self
)
232 Py_CLEAR(self
->args
);
234 Py_CLEAR(self
->dict
);
239 local_dealloc(localobject
*self
)
241 PyThreadState
*tstate
;
243 && (tstate
= PyThreadState_Get())
245 for(tstate
= PyInterpreterState_ThreadHead(tstate
->interp
);
247 tstate
= PyThreadState_Next(tstate
))
249 PyDict_GetItem(tstate
->dict
, self
->key
))
250 PyDict_DelItem(tstate
->dict
, self
->key
);
254 self
->ob_type
->tp_free((PyObject
*)self
);
258 _ldict(localobject
*self
)
260 PyObject
*tdict
, *ldict
;
262 tdict
= PyThreadState_GetDict();
264 PyErr_SetString(PyExc_SystemError
,
265 "Couldn't get thread-state dictionary");
269 ldict
= PyDict_GetItem(tdict
, self
->key
);
271 ldict
= PyDict_New(); /* we own ldict */
276 int i
= PyDict_SetItem(tdict
, self
->key
, ldict
);
277 Py_DECREF(ldict
); /* now ldict is borrowed */
282 Py_CLEAR(self
->dict
);
284 self
->dict
= ldict
; /* still borrowed */
286 if (self
->ob_type
->tp_init
!= PyBaseObject_Type
.tp_init
&&
287 self
->ob_type
->tp_init((PyObject
*)self
,
288 self
->args
, self
->kw
) < 0) {
289 /* we need to get rid of ldict from thread so
290 we create a new one the next time we do an attr
292 PyDict_DelItem(tdict
, self
->key
);
297 else if (self
->dict
!= ldict
) {
298 Py_CLEAR(self
->dict
);
307 local_setattro(localobject
*self
, PyObject
*name
, PyObject
*v
)
311 ldict
= _ldict(self
);
315 return PyObject_GenericSetAttr((PyObject
*)self
, name
, v
);
319 local_getdict(localobject
*self
, void *closure
)
321 if (self
->dict
== NULL
) {
322 PyErr_SetString(PyExc_AttributeError
, "__dict__");
326 Py_INCREF(self
->dict
);
330 static PyGetSetDef local_getset
[] = {
331 {"__dict__", (getter
)local_getdict
, (setter
)NULL
,
332 "Local-data dictionary", NULL
},
333 {NULL
} /* Sentinel */
336 static PyObject
*local_getattro(localobject
*, PyObject
*);
338 static PyTypeObject localtype
= {
339 PyObject_HEAD_INIT(NULL
)
341 /* tp_name */ "thread._local",
342 /* tp_basicsize */ sizeof(localobject
),
344 /* tp_dealloc */ (destructor
)local_dealloc
,
350 /* tp_as_number */ 0,
351 /* tp_as_sequence */ 0,
352 /* tp_as_mapping */ 0,
356 /* tp_getattro */ (getattrofunc
)local_getattro
,
357 /* tp_setattro */ (setattrofunc
)local_setattro
,
358 /* tp_as_buffer */ 0,
359 /* tp_flags */ Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
,
360 /* tp_doc */ "Thread-local data",
361 /* tp_traverse */ (traverseproc
)local_traverse
,
362 /* tp_clear */ (inquiry
)local_clear
,
363 /* tp_richcompare */ 0,
364 /* tp_weaklistoffset */ 0,
369 /* tp_getset */ local_getset
,
371 /* tp_dict */ 0, /* internal use */
372 /* tp_descr_get */ 0,
373 /* tp_descr_set */ 0,
374 /* tp_dictoffset */ offsetof(localobject
, dict
),
377 /* tp_new */ local_new
,
378 /* tp_free */ 0, /* Low-level free-mem routine */
379 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
383 local_getattro(localobject
*self
, PyObject
*name
)
385 PyObject
*ldict
, *value
;
387 ldict
= _ldict(self
);
391 if (self
->ob_type
!= &localtype
)
392 /* use generic lookup for subtypes */
393 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
395 /* Optimization: just look in dict ourselves */
396 value
= PyDict_GetItem(ldict
, name
);
398 /* Fall back on generic to get __class__ and __dict__ */
399 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
405 /* Module functions */
408 PyInterpreterState
*interp
;
415 t_bootstrap(void *boot_raw
)
417 struct bootstate
*boot
= (struct bootstate
*) boot_raw
;
418 PyThreadState
*tstate
;
421 tstate
= PyThreadState_New(boot
->interp
);
423 PyEval_AcquireThread(tstate
);
424 res
= PyEval_CallObjectWithKeywords(
425 boot
->func
, boot
->args
, boot
->keyw
);
427 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
432 "Unhandled exception in thread started by ");
433 file
= PySys_GetObject("stderr");
435 PyFile_WriteObject(boot
->func
, file
, 0);
437 PyObject_Print(boot
->func
, stderr
, 0);
438 PySys_WriteStderr("\n");
444 Py_DECREF(boot
->func
);
445 Py_DECREF(boot
->args
);
446 Py_XDECREF(boot
->keyw
);
448 PyThreadState_Clear(tstate
);
449 PyThreadState_DeleteCurrent();
450 PyThread_exit_thread();
454 thread_PyThread_start_new_thread(PyObject
*self
, PyObject
*fargs
)
456 PyObject
*func
, *args
, *keyw
= NULL
;
457 struct bootstate
*boot
;
460 if (!PyArg_UnpackTuple(fargs
, "start_new_thread", 2, 3,
461 &func
, &args
, &keyw
))
463 if (!PyCallable_Check(func
)) {
464 PyErr_SetString(PyExc_TypeError
,
465 "first arg must be callable");
468 if (!PyTuple_Check(args
)) {
469 PyErr_SetString(PyExc_TypeError
,
470 "2nd arg must be a tuple");
473 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
474 PyErr_SetString(PyExc_TypeError
,
475 "optional 3rd arg must be a dictionary");
478 boot
= PyMem_NEW(struct bootstate
, 1);
480 return PyErr_NoMemory();
481 boot
->interp
= PyThreadState_GET()->interp
;
488 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
489 ident
= PyThread_start_new_thread(t_bootstrap
, (void*) boot
);
491 PyErr_SetString(ThreadError
, "can't start new thread");
498 return PyInt_FromLong(ident
);
501 PyDoc_STRVAR(start_new_doc
,
502 "start_new_thread(function, args[, kwargs])\n\
503 (start_new() is an obsolete synonym)\n\
505 Start a new thread and return its identifier. The thread will call the\n\
506 function with positional arguments from the tuple args and keyword arguments\n\
507 taken from the optional dictionary kwargs. The thread exits when the\n\
508 function returns; the return value is ignored. The thread will also exit\n\
509 when the function raises an unhandled exception; a stack trace will be\n\
510 printed unless the exception is SystemExit.\n");
513 thread_PyThread_exit_thread(PyObject
*self
)
515 PyErr_SetNone(PyExc_SystemExit
);
519 PyDoc_STRVAR(exit_doc
,
521 (PyThread_exit_thread() is an obsolete synonym)\n\
523 This is synonymous to ``raise SystemExit''. It will cause the current\n\
524 thread to exit silently unless the exception is caught.");
527 thread_PyThread_interrupt_main(PyObject
* self
)
529 PyErr_SetInterrupt();
534 PyDoc_STRVAR(interrupt_doc
,
537 Raise a KeyboardInterrupt in the main thread.\n\
538 A subthread can use this function to interrupt the main thread."
543 thread_PyThread_exit_prog(PyObject
*self
, PyObject
*args
)
546 if (!PyArg_ParseTuple(args
, "i:exit_prog", &sts
))
548 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
549 for (;;) { } /* Should not be reached */
553 static lockobject
*newlockobject(void);
556 thread_PyThread_allocate_lock(PyObject
*self
)
558 return (PyObject
*) newlockobject();
561 PyDoc_STRVAR(allocate_doc
,
562 "allocate_lock() -> lock object\n\
563 (allocate() is an obsolete synonym)\n\
565 Create a new lock object. See LockType.__doc__ for information about locks.");
568 thread_get_ident(PyObject
*self
)
571 ident
= PyThread_get_thread_ident();
573 PyErr_SetString(ThreadError
, "no current thread ident");
576 return PyInt_FromLong(ident
);
579 PyDoc_STRVAR(get_ident_doc
,
580 "get_ident() -> integer\n\
582 Return a non-zero integer that uniquely identifies the current thread\n\
583 amongst other threads that exist simultaneously.\n\
584 This may be used to identify per-thread resources.\n\
585 Even though on some platforms threads identities may appear to be\n\
586 allocated consecutive numbers starting at 1, this behavior should not\n\
587 be relied upon, and the number should be seen purely as a magic cookie.\n\
588 A thread's identity may be reused for another thread after it exits.");
591 thread_stack_size(PyObject
*self
, PyObject
*args
)
594 Py_ssize_t new_size
= 0;
597 if (!PyArg_ParseTuple(args
, "|n:stack_size", &new_size
))
601 PyErr_SetString(PyExc_ValueError
,
602 "size must be 0 or a positive value");
606 old_size
= PyThread_get_stacksize();
608 rc
= PyThread_set_stacksize((size_t) new_size
);
610 PyErr_Format(PyExc_ValueError
,
611 "size not valid: %zd bytes",
616 PyErr_SetString(ThreadError
,
617 "setting stack size not supported");
621 return PyInt_FromSsize_t((Py_ssize_t
) old_size
);
624 PyDoc_STRVAR(stack_size_doc
,
625 "stack_size([size]) -> size\n\
627 Return the thread stack size used when creating new threads. The\n\
628 optional size argument specifies the stack size (in bytes) to be used\n\
629 for subsequently created threads, and must be 0 (use platform or\n\
630 configured default) or a positive integer value of at least 32,768 (32k).\n\
631 If changing the thread stack size is unsupported, a ThreadError\n\
632 exception is raised. If the specified size is invalid, a ValueError\n\
633 exception is raised, and the stack size is unmodified. 32k bytes\n\
634 currently the minimum supported stack size value to guarantee\n\
635 sufficient stack space for the interpreter itself.\n\
637 Note that some platforms may have particular restrictions on values for\n\
638 the stack size, such as requiring a minimum stack size larger than 32kB or\n\
639 requiring allocation in multiples of the system memory page size\n\
640 - platform documentation should be referred to for more information\n\
641 (4kB pages are common; using multiples of 4096 for the stack size is\n\
642 the suggested approach in the absence of more specific information).");
644 static PyMethodDef thread_methods
[] = {
645 {"start_new_thread", (PyCFunction
)thread_PyThread_start_new_thread
,
648 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
,
651 {"allocate_lock", (PyCFunction
)thread_PyThread_allocate_lock
,
652 METH_NOARGS
, allocate_doc
},
653 {"allocate", (PyCFunction
)thread_PyThread_allocate_lock
,
654 METH_NOARGS
, allocate_doc
},
655 {"exit_thread", (PyCFunction
)thread_PyThread_exit_thread
,
656 METH_NOARGS
, exit_doc
},
657 {"exit", (PyCFunction
)thread_PyThread_exit_thread
,
658 METH_NOARGS
, exit_doc
},
659 {"interrupt_main", (PyCFunction
)thread_PyThread_interrupt_main
,
660 METH_NOARGS
, interrupt_doc
},
661 {"get_ident", (PyCFunction
)thread_get_ident
,
662 METH_NOARGS
, get_ident_doc
},
663 {"stack_size", (PyCFunction
)thread_stack_size
,
667 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
,
670 {NULL
, NULL
} /* sentinel */
674 /* Initialization function */
676 PyDoc_STRVAR(thread_doc
,
677 "This module provides primitive operations to write multi-threaded programs.\n\
678 The 'threading' module provides a more convenient interface.");
680 PyDoc_STRVAR(lock_doc
,
681 "A lock object is a synchronization primitive. To create a lock,\n\
682 call the PyThread_allocate_lock() function. Methods are:\n\
684 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
685 release() -- unlock of the lock\n\
686 locked() -- test whether the lock is currently locked\n\
688 A lock is not owned by the thread that locked it; another thread may\n\
689 unlock it. A thread attempting to lock a lock that it has already locked\n\
690 will block until another thread unlocks it. Deadlocks may ensue.");
697 /* Initialize types: */
698 if (PyType_Ready(&localtype
) < 0)
701 /* Create the module and add the functions */
702 m
= Py_InitModule3("thread", thread_methods
, thread_doc
);
706 /* Add a symbolic constant */
707 d
= PyModule_GetDict(m
);
708 ThreadError
= PyErr_NewException("thread.error", NULL
, NULL
);
709 PyDict_SetItemString(d
, "error", ThreadError
);
710 Locktype
.tp_doc
= lock_doc
;
711 Py_INCREF(&Locktype
);
712 PyDict_SetItemString(d
, "LockType", (PyObject
*)&Locktype
);
714 Py_INCREF(&localtype
);
715 if (PyModule_AddObject(m
, "_local", (PyObject
*)&localtype
) < 0)
718 /* Initialize the C thread library */
719 PyThread_init_thread();