summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
Diffstat (limited to 'Python')
-rw-r--r--Python/ceval.c18
-rw-r--r--Python/pystate.c47
2 files changed, 57 insertions, 8 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index cbc0fab..d32b6fb 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -362,29 +362,28 @@ PyEval_ReleaseThread(PyThreadState *tstate)
drop_gil(tstate);
}
-/* This function is called from PyOS_AfterFork to ensure that newly
- created child processes don't hold locks referring to threads which
- are not running in the child process. (This could also be done using
- pthread_atfork mechanism, at least for the pthreads implementation.) */
+/* This function is called from PyOS_AfterFork to destroy all threads which are
+ * not running in the child process, and clear internal locks which might be
+ * held by those threads. (This could also be done using pthread_atfork
+ * mechanism, at least for the pthreads implementation.) */
void
PyEval_ReInitThreads(void)
{
_Py_IDENTIFIER(_after_fork);
PyObject *threading, *result;
- PyThreadState *tstate = PyThreadState_GET();
+ PyThreadState *current_tstate = PyThreadState_GET();
if (!gil_created())
return;
recreate_gil();
pending_lock = PyThread_allocate_lock();
- take_gil(tstate);
+ take_gil(current_tstate);
main_thread = PyThread_get_thread_ident();
/* Update the threading module with the new state.
*/
- tstate = PyThreadState_GET();
- threading = PyMapping_GetItemString(tstate->interp->modules,
+ threading = PyMapping_GetItemString(current_tstate->interp->modules,
"threading");
if (threading == NULL) {
/* threading not imported */
@@ -397,6 +396,9 @@ PyEval_ReInitThreads(void)
else
Py_DECREF(result);
Py_DECREF(threading);
+
+ /* Destroy all threads except the current one */
+ _PyThreadState_DeleteExcept(current_tstate);
}
#else
diff --git a/Python/pystate.c b/Python/pystate.c
index 7003893..2a6f16c 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -414,6 +414,53 @@ PyThreadState_DeleteCurrent()
#endif /* WITH_THREAD */
+/*
+ * Delete all thread states except the one passed as argument.
+ * Note that, if there is a current thread state, it *must* be the one
+ * passed as argument. Also, this won't touch any other interpreters
+ * than the current one, since we don't know which thread state should
+ * be kept in those other interpreteres.
+ */
+void
+_PyThreadState_DeleteExcept(PyThreadState *tstate)
+{
+ PyInterpreterState *interp = tstate->interp;
+ PyThreadState *p, *next, *garbage;
+ HEAD_LOCK();
+ /* Remove all thread states, except tstate, from the linked list of
+ thread states. This will allow calling PyThreadState_Clear()
+ without holding the lock.
+ XXX This would be simpler with a doubly-linked list. */
+ garbage = interp->tstate_head;
+ interp->tstate_head = tstate;
+ if (garbage == tstate) {
+ garbage = garbage->next;
+ tstate->next = NULL;
+ }
+ else {
+ for (p = garbage; p; p = p->next) {
+ if (p->next == tstate) {
+ p->next = tstate->next;
+ tstate->next = NULL;
+ break;
+ }
+ }
+ }
+ if (tstate->next != NULL)
+ Py_FatalError("_PyThreadState_DeleteExcept: tstate not found "
+ "in interpreter thread states");
+ HEAD_UNLOCK();
+ /* Clear and deallocate all stale thread states. Even if this
+ executes Python code, we should be safe since it executes
+ in the current thread, not one of the stale threads. */
+ for (p = garbage; p; p = next) {
+ next = p->next;
+ PyThreadState_Clear(p);
+ free(p);
+ }
+}
+
+
PyThreadState *
PyThreadState_Get(void)
{