3 /* Interface to Sjoerd's portable C thread library */
6 #include "structmember.h" /* offsetof */
9 #error "Error! The rest of Python is not compiled with thread support."
10 #error "Rerun configure, adding a --with-threads option."
11 #error "Then run `make clean' followed by `make'."
16 static PyObject
*ThreadError
;
23 PyThread_type_lock lock_lock
;
24 PyObject
*in_weakreflist
;
28 lock_dealloc(lockobject
*self
)
30 assert(self
->lock_lock
);
31 if (self
->in_weakreflist
!= NULL
)
32 PyObject_ClearWeakRefs((PyObject
*) self
);
33 /* Unlock the lock so it's safe to free it */
34 PyThread_acquire_lock(self
->lock_lock
, 0);
35 PyThread_release_lock(self
->lock_lock
);
37 PyThread_free_lock(self
->lock_lock
);
42 lock_PyThread_acquire_lock(lockobject
*self
, PyObject
*args
)
46 if (!PyArg_ParseTuple(args
, "|i:acquire", &i
))
49 Py_BEGIN_ALLOW_THREADS
50 i
= PyThread_acquire_lock(self
->lock_lock
, i
);
53 return PyBool_FromLong((long)i
);
56 PyDoc_STRVAR(acquire_doc
,
57 "acquire([wait]) -> None or bool\n\
58 (acquire_lock() is an obsolete synonym)\n\
60 Lock the lock. Without argument, this blocks if the lock is already\n\
61 locked (even by the same thread), waiting for another thread to release\n\
62 the lock, and return None once the lock is acquired.\n\
63 With an argument, this will only block if the argument is true,\n\
64 and the return value reflects whether the lock is acquired.\n\
65 The blocking operation is not interruptible.");
68 lock_PyThread_release_lock(lockobject
*self
)
70 /* Sanity check: the lock must be locked */
71 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
72 PyThread_release_lock(self
->lock_lock
);
73 PyErr_SetString(ThreadError
, "release unlocked lock");
77 PyThread_release_lock(self
->lock_lock
);
82 PyDoc_STRVAR(release_doc
,
84 (release_lock() is an obsolete synonym)\n\
86 Release the lock, allowing another thread that is blocked waiting for\n\
87 the lock to acquire the lock. The lock must be in the locked state,\n\
88 but it needn't be locked by the same thread that unlocks it.");
91 lock_locked_lock(lockobject
*self
)
93 if (PyThread_acquire_lock(self
->lock_lock
, 0)) {
94 PyThread_release_lock(self
->lock_lock
);
95 return PyBool_FromLong(0L);
97 return PyBool_FromLong(1L);
100 PyDoc_STRVAR(locked_doc
,
102 (locked_lock() is an obsolete synonym)\n\
104 Return whether the lock is in the locked state.");
106 static PyMethodDef lock_methods
[] = {
107 {"acquire_lock", (PyCFunction
)lock_PyThread_acquire_lock
,
108 METH_VARARGS
, acquire_doc
},
109 {"acquire", (PyCFunction
)lock_PyThread_acquire_lock
,
110 METH_VARARGS
, acquire_doc
},
111 {"release_lock", (PyCFunction
)lock_PyThread_release_lock
,
112 METH_NOARGS
, release_doc
},
113 {"release", (PyCFunction
)lock_PyThread_release_lock
,
114 METH_NOARGS
, release_doc
},
115 {"locked_lock", (PyCFunction
)lock_locked_lock
,
116 METH_NOARGS
, locked_doc
},
117 {"locked", (PyCFunction
)lock_locked_lock
,
118 METH_NOARGS
, locked_doc
},
119 {"__enter__", (PyCFunction
)lock_PyThread_acquire_lock
,
120 METH_VARARGS
, acquire_doc
},
121 {"__exit__", (PyCFunction
)lock_PyThread_release_lock
,
122 METH_VARARGS
, release_doc
},
123 {NULL
} /* sentinel */
126 static PyTypeObject Locktype
= {
127 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
128 "thread.lock", /*tp_name*/
129 sizeof(lockobject
), /*tp_size*/
132 (destructor
)lock_dealloc
, /*tp_dealloc*/
138 0, /* tp_as_number */
139 0, /* tp_as_sequence */
140 0, /* tp_as_mapping */
146 0, /* tp_as_buffer */
147 Py_TPFLAGS_HAVE_WEAKREFS
, /* tp_flags */
151 0, /* tp_richcompare */
152 offsetof(lockobject
, in_weakreflist
), /* tp_weaklistoffset */
155 lock_methods
, /* tp_methods */
162 self
= PyObject_New(lockobject
, &Locktype
);
165 self
->lock_lock
= PyThread_allocate_lock();
166 self
->in_weakreflist
= NULL
;
167 if (self
->lock_lock
== NULL
) {
170 PyErr_SetString(ThreadError
, "can't allocate lock");
175 /* Thread-local objects */
177 #include "structmember.h"
188 local_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kw
)
193 if (type
->tp_init
== PyBaseObject_Type
.tp_init
194 && ((args
&& PyObject_IsTrue(args
))
195 || (kw
&& PyObject_IsTrue(kw
)))) {
196 PyErr_SetString(PyExc_TypeError
,
197 "Initialization arguments are not supported");
201 self
= (localobject
*)type
->tp_alloc(type
, 0);
209 self
->dict
= NULL
; /* making sure */
210 self
->key
= PyString_FromFormat("thread.local.%p", self
);
211 if (self
->key
== NULL
)
214 self
->dict
= PyDict_New();
215 if (self
->dict
== NULL
)
218 tdict
= PyThreadState_GetDict();
220 PyErr_SetString(PyExc_SystemError
,
221 "Couldn't get thread-state dictionary");
225 if (PyDict_SetItem(tdict
, self
->key
, self
->dict
) < 0)
228 return (PyObject
*)self
;
236 local_traverse(localobject
*self
, visitproc visit
, void *arg
)
238 Py_VISIT(self
->args
);
240 Py_VISIT(self
->dict
);
245 local_clear(localobject
*self
)
247 Py_CLEAR(self
->args
);
249 Py_CLEAR(self
->dict
);
254 local_dealloc(localobject
*self
)
256 PyThreadState
*tstate
;
258 && (tstate
= PyThreadState_Get())
260 for(tstate
= PyInterpreterState_ThreadHead(tstate
->interp
);
262 tstate
= PyThreadState_Next(tstate
))
264 PyDict_GetItem(tstate
->dict
, self
->key
))
265 PyDict_DelItem(tstate
->dict
, self
->key
);
268 Py_XDECREF(self
->key
);
270 Py_TYPE(self
)->tp_free((PyObject
*)self
);
274 _ldict(localobject
*self
)
276 PyObject
*tdict
, *ldict
;
278 tdict
= PyThreadState_GetDict();
280 PyErr_SetString(PyExc_SystemError
,
281 "Couldn't get thread-state dictionary");
285 ldict
= PyDict_GetItem(tdict
, self
->key
);
287 ldict
= PyDict_New(); /* we own ldict */
292 int i
= PyDict_SetItem(tdict
, self
->key
, ldict
);
293 Py_DECREF(ldict
); /* now ldict is borrowed */
298 Py_CLEAR(self
->dict
);
300 self
->dict
= ldict
; /* still borrowed */
302 if (Py_TYPE(self
)->tp_init
!= PyBaseObject_Type
.tp_init
&&
303 Py_TYPE(self
)->tp_init((PyObject
*)self
,
304 self
->args
, self
->kw
) < 0) {
305 /* we need to get rid of ldict from thread so
306 we create a new one the next time we do an attr
308 PyDict_DelItem(tdict
, self
->key
);
314 /* The call to tp_init above may have caused another thread to run.
315 Install our ldict again. */
316 if (self
->dict
!= ldict
) {
317 Py_CLEAR(self
->dict
);
326 local_setattro(localobject
*self
, PyObject
*name
, PyObject
*v
)
330 ldict
= _ldict(self
);
334 return PyObject_GenericSetAttr((PyObject
*)self
, name
, v
);
338 local_getdict(localobject
*self
, void *closure
)
340 if (self
->dict
== NULL
) {
341 PyErr_SetString(PyExc_AttributeError
, "__dict__");
345 Py_INCREF(self
->dict
);
349 static PyGetSetDef local_getset
[] = {
350 {"__dict__", (getter
)local_getdict
, (setter
)NULL
,
351 "Local-data dictionary", NULL
},
352 {NULL
} /* Sentinel */
355 static PyObject
*local_getattro(localobject
*, PyObject
*);
357 static PyTypeObject localtype
= {
358 PyVarObject_HEAD_INIT(NULL
, 0)
359 /* tp_name */ "thread._local",
360 /* tp_basicsize */ sizeof(localobject
),
362 /* tp_dealloc */ (destructor
)local_dealloc
,
368 /* tp_as_number */ 0,
369 /* tp_as_sequence */ 0,
370 /* tp_as_mapping */ 0,
374 /* tp_getattro */ (getattrofunc
)local_getattro
,
375 /* tp_setattro */ (setattrofunc
)local_setattro
,
376 /* tp_as_buffer */ 0,
377 /* tp_flags */ Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
,
378 /* tp_doc */ "Thread-local data",
379 /* tp_traverse */ (traverseproc
)local_traverse
,
380 /* tp_clear */ (inquiry
)local_clear
,
381 /* tp_richcompare */ 0,
382 /* tp_weaklistoffset */ 0,
387 /* tp_getset */ local_getset
,
389 /* tp_dict */ 0, /* internal use */
390 /* tp_descr_get */ 0,
391 /* tp_descr_set */ 0,
392 /* tp_dictoffset */ offsetof(localobject
, dict
),
395 /* tp_new */ local_new
,
396 /* tp_free */ 0, /* Low-level free-mem routine */
397 /* tp_is_gc */ 0, /* For PyObject_IS_GC */
401 local_getattro(localobject
*self
, PyObject
*name
)
403 PyObject
*ldict
, *value
;
405 ldict
= _ldict(self
);
409 if (Py_TYPE(self
) != &localtype
)
410 /* use generic lookup for subtypes */
411 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
413 /* Optimization: just look in dict ourselves */
414 value
= PyDict_GetItem(ldict
, name
);
416 /* Fall back on generic to get __class__ and __dict__ */
417 return PyObject_GenericGetAttr((PyObject
*)self
, name
);
423 /* Module functions */
426 PyInterpreterState
*interp
;
433 t_bootstrap(void *boot_raw
)
435 struct bootstate
*boot
= (struct bootstate
*) boot_raw
;
436 PyThreadState
*tstate
;
439 tstate
= PyThreadState_New(boot
->interp
);
441 PyEval_AcquireThread(tstate
);
442 res
= PyEval_CallObjectWithKeywords(
443 boot
->func
, boot
->args
, boot
->keyw
);
445 if (PyErr_ExceptionMatches(PyExc_SystemExit
))
450 "Unhandled exception in thread started by ");
451 file
= PySys_GetObject("stderr");
453 PyFile_WriteObject(boot
->func
, file
, 0);
455 PyObject_Print(boot
->func
, stderr
, 0);
456 PySys_WriteStderr("\n");
462 Py_DECREF(boot
->func
);
463 Py_DECREF(boot
->args
);
464 Py_XDECREF(boot
->keyw
);
466 PyThreadState_Clear(tstate
);
467 PyThreadState_DeleteCurrent();
468 PyThread_exit_thread();
472 thread_PyThread_start_new_thread(PyObject
*self
, PyObject
*fargs
)
474 PyObject
*func
, *args
, *keyw
= NULL
;
475 struct bootstate
*boot
;
478 if (!PyArg_UnpackTuple(fargs
, "start_new_thread", 2, 3,
479 &func
, &args
, &keyw
))
481 if (!PyCallable_Check(func
)) {
482 PyErr_SetString(PyExc_TypeError
,
483 "first arg must be callable");
486 if (!PyTuple_Check(args
)) {
487 PyErr_SetString(PyExc_TypeError
,
488 "2nd arg must be a tuple");
491 if (keyw
!= NULL
&& !PyDict_Check(keyw
)) {
492 PyErr_SetString(PyExc_TypeError
,
493 "optional 3rd arg must be a dictionary");
496 boot
= PyMem_NEW(struct bootstate
, 1);
498 return PyErr_NoMemory();
499 boot
->interp
= PyThreadState_GET()->interp
;
506 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
507 ident
= PyThread_start_new_thread(t_bootstrap
, (void*) boot
);
509 PyErr_SetString(ThreadError
, "can't start new thread");
516 return PyInt_FromLong(ident
);
519 PyDoc_STRVAR(start_new_doc
,
520 "start_new_thread(function, args[, kwargs])\n\
521 (start_new() is an obsolete synonym)\n\
523 Start a new thread and return its identifier. The thread will call the\n\
524 function with positional arguments from the tuple args and keyword arguments\n\
525 taken from the optional dictionary kwargs. The thread exits when the\n\
526 function returns; the return value is ignored. The thread will also exit\n\
527 when the function raises an unhandled exception; a stack trace will be\n\
528 printed unless the exception is SystemExit.\n");
531 thread_PyThread_exit_thread(PyObject
*self
)
533 PyErr_SetNone(PyExc_SystemExit
);
537 PyDoc_STRVAR(exit_doc
,
539 (PyThread_exit_thread() is an obsolete synonym)\n\
541 This is synonymous to ``raise SystemExit''. It will cause the current\n\
542 thread to exit silently unless the exception is caught.");
545 thread_PyThread_interrupt_main(PyObject
* self
)
547 PyErr_SetInterrupt();
552 PyDoc_STRVAR(interrupt_doc
,
555 Raise a KeyboardInterrupt in the main thread.\n\
556 A subthread can use this function to interrupt the main thread."
561 thread_PyThread_exit_prog(PyObject
*self
, PyObject
*args
)
564 if (!PyArg_ParseTuple(args
, "i:exit_prog", &sts
))
566 Py_Exit(sts
); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */
567 for (;;) { } /* Should not be reached */
571 static lockobject
*newlockobject(void);
574 thread_PyThread_allocate_lock(PyObject
*self
)
576 return (PyObject
*) newlockobject();
579 PyDoc_STRVAR(allocate_doc
,
580 "allocate_lock() -> lock object\n\
581 (allocate() is an obsolete synonym)\n\
583 Create a new lock object. See LockType.__doc__ for information about locks.");
586 thread_get_ident(PyObject
*self
)
589 ident
= PyThread_get_thread_ident();
591 PyErr_SetString(ThreadError
, "no current thread ident");
594 return PyInt_FromLong(ident
);
597 PyDoc_STRVAR(get_ident_doc
,
598 "get_ident() -> integer\n\
600 Return a non-zero integer that uniquely identifies the current thread\n\
601 amongst other threads that exist simultaneously.\n\
602 This may be used to identify per-thread resources.\n\
603 Even though on some platforms threads identities may appear to be\n\
604 allocated consecutive numbers starting at 1, this behavior should not\n\
605 be relied upon, and the number should be seen purely as a magic cookie.\n\
606 A thread's identity may be reused for another thread after it exits.");
609 thread_stack_size(PyObject
*self
, PyObject
*args
)
612 Py_ssize_t new_size
= 0;
615 if (!PyArg_ParseTuple(args
, "|n:stack_size", &new_size
))
619 PyErr_SetString(PyExc_ValueError
,
620 "size must be 0 or a positive value");
624 old_size
= PyThread_get_stacksize();
626 rc
= PyThread_set_stacksize((size_t) new_size
);
628 PyErr_Format(PyExc_ValueError
,
629 "size not valid: %zd bytes",
634 PyErr_SetString(ThreadError
,
635 "setting stack size not supported");
639 return PyInt_FromSsize_t((Py_ssize_t
) old_size
);
642 PyDoc_STRVAR(stack_size_doc
,
643 "stack_size([size]) -> size\n\
645 Return the thread stack size used when creating new threads. The\n\
646 optional size argument specifies the stack size (in bytes) to be used\n\
647 for subsequently created threads, and must be 0 (use platform or\n\
648 configured default) or a positive integer value of at least 32,768 (32k).\n\
649 If changing the thread stack size is unsupported, a ThreadError\n\
650 exception is raised. If the specified size is invalid, a ValueError\n\
651 exception is raised, and the stack size is unmodified. 32k bytes\n\
652 currently the minimum supported stack size value to guarantee\n\
653 sufficient stack space for the interpreter itself.\n\
655 Note that some platforms may have particular restrictions on values for\n\
656 the stack size, such as requiring a minimum stack size larger than 32kB or\n\
657 requiring allocation in multiples of the system memory page size\n\
658 - platform documentation should be referred to for more information\n\
659 (4kB pages are common; using multiples of 4096 for the stack size is\n\
660 the suggested approach in the absence of more specific information).");
662 static PyMethodDef thread_methods
[] = {
663 {"start_new_thread", (PyCFunction
)thread_PyThread_start_new_thread
,
666 {"start_new", (PyCFunction
)thread_PyThread_start_new_thread
,
669 {"allocate_lock", (PyCFunction
)thread_PyThread_allocate_lock
,
670 METH_NOARGS
, allocate_doc
},
671 {"allocate", (PyCFunction
)thread_PyThread_allocate_lock
,
672 METH_NOARGS
, allocate_doc
},
673 {"exit_thread", (PyCFunction
)thread_PyThread_exit_thread
,
674 METH_NOARGS
, exit_doc
},
675 {"exit", (PyCFunction
)thread_PyThread_exit_thread
,
676 METH_NOARGS
, exit_doc
},
677 {"interrupt_main", (PyCFunction
)thread_PyThread_interrupt_main
,
678 METH_NOARGS
, interrupt_doc
},
679 {"get_ident", (PyCFunction
)thread_get_ident
,
680 METH_NOARGS
, get_ident_doc
},
681 {"stack_size", (PyCFunction
)thread_stack_size
,
685 {"exit_prog", (PyCFunction
)thread_PyThread_exit_prog
,
688 {NULL
, NULL
} /* sentinel */
692 /* Initialization function */
694 PyDoc_STRVAR(thread_doc
,
695 "This module provides primitive operations to write multi-threaded programs.\n\
696 The 'threading' module provides a more convenient interface.");
698 PyDoc_STRVAR(lock_doc
,
699 "A lock object is a synchronization primitive. To create a lock,\n\
700 call the PyThread_allocate_lock() function. Methods are:\n\
702 acquire() -- lock the lock, possibly blocking until it can be obtained\n\
703 release() -- unlock of the lock\n\
704 locked() -- test whether the lock is currently locked\n\
706 A lock is not owned by the thread that locked it; another thread may\n\
707 unlock it. A thread attempting to lock a lock that it has already locked\n\
708 will block until another thread unlocks it. Deadlocks may ensue.");
715 /* Initialize types: */
716 if (PyType_Ready(&localtype
) < 0)
719 /* Create the module and add the functions */
720 m
= Py_InitModule3("thread", thread_methods
, thread_doc
);
724 /* Add a symbolic constant */
725 d
= PyModule_GetDict(m
);
726 ThreadError
= PyErr_NewException("thread.error", NULL
, NULL
);
727 PyDict_SetItemString(d
, "error", ThreadError
);
728 Locktype
.tp_doc
= lock_doc
;
729 if (PyType_Ready(&Locktype
) < 0)
731 Py_INCREF(&Locktype
);
732 PyDict_SetItemString(d
, "LockType", (PyObject
*)&Locktype
);
734 Py_INCREF(&localtype
);
735 if (PyModule_AddObject(m
, "_local", (PyObject
*)&localtype
) < 0)
738 /* Initialize the C thread library */
739 PyThread_init_thread();