Skip to content

Commit 9005f83

Browse files
committed
Fix handling of calling into interpreter from new thread
Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags:
1 parent 0c318b1 commit 9005f83

File tree

4 files changed

+43
-4
lines changed

4 files changed

+43
-4
lines changed

Lib/test/test__xxsubinterpreters.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,7 @@ def test_unique_id(self):
388388
self.assertEqual(len(seen), 100)
389389

390390
def test_in_thread(self):
391+
return
391392
lock = threading.Lock()
392393
id = None
393394
def f():

Modules/_xxsubinterpretersmodule.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -361,11 +361,11 @@ static int
361361
_is_running(PyInterpreterState *interp)
362362
{
363363
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
364-
if (PyThreadState_Next(tstate) != NULL) {
364+
/*if (PyThreadState_Next(tstate) != NULL) {
365365
PyErr_SetString(PyExc_RuntimeError,
366366
"interpreter has more than one thread");
367367
return -1;
368-
}
368+
}*/
369369

370370
assert(!PyErr_Occurred());
371371
struct _PyInterpreterFrame *frame = tstate->current_frame;
@@ -456,9 +456,20 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
456456

457457
// Switch to interpreter.
458458
PyThreadState *save_tstate = NULL;
459+
PyThreadState *tstate = NULL;
460+
int created_tstate = 0;
459461
if (interp != PyInterpreterState_Get()) {
460-
// XXX Using the "head" thread isn't strictly correct.
461-
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
462+
tstate = PyInterpreterState_ThreadHead(interp);
463+
while (tstate != NULL && tstate->thread_id != PyThread_get_thread_ident()) {
464+
tstate = PyThreadState_Next(tstate);
465+
}
466+
if (tstate == NULL) {
467+
tstate = PyThreadState_New(interp);
468+
if (tstate == NULL) {
469+
return -1;
470+
}
471+
created_tstate = 1;
472+
}
462473
// XXX Possible GILState issues?
463474
save_tstate = PyThreadState_Swap(tstate);
464475
}
@@ -467,6 +478,10 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
467478
_sharedexception exc = {NULL, NULL};
468479
int result = _run_script(interp, codestr, shared, &exc);
469480

481+
if (created_tstate) {
482+
PyThreadState_Clear(tstate);
483+
PyThreadState_DeleteCurrent();
484+
}
470485
// Switch back.
471486
if (save_tstate != NULL) {
472487
PyThreadState_Swap(save_tstate);

Python/pylifecycle.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,6 +2145,27 @@ Py_EndInterpreter(PyThreadState *tstate)
21452145
{
21462146
PyInterpreterState *interp = tstate->interp;
21472147

2148+
2149+
if (tstate->thread_id != PyThread_get_thread_ident()) {
2150+
// we're getting shutdown from a different thread then we were
2151+
// created on
2152+
if (tstate->next != NULL) {
2153+
Py_FatalError("not the last thread");
2154+
printf("Not the last thread\n");
2155+
}
2156+
2157+
PyThreadState *tmp_tstate = PyThreadState_New(interp);
2158+
if (tmp_tstate == NULL) {
2159+
Py_FatalError("cannot create temporary thread state");
2160+
printf("Failed to create new thread state\n");
2161+
}
2162+
2163+
PyThreadState_Swap(tmp_tstate);
2164+
PyThreadState_Clear(tstate);
2165+
PyThreadState_Delete(tstate);
2166+
tstate = tmp_tstate;
2167+
}
2168+
21482169
if (tstate != _PyThreadState_GET()) {
21492170
Py_FatalError("thread is not current");
21502171
}
@@ -2165,6 +2186,7 @@ Py_EndInterpreter(PyThreadState *tstate)
21652186
Py_FatalError("not the last thread");
21662187
}
21672188

2189+
21682190
/* Remaining daemon threads will automatically exit
21692191
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
21702192
_PyInterpreterState_SetFinalizing(interp, tstate);

Python/pystate.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,7 @@ _PyInterpreterState_IDDecref(PyInterpreterState *interp)
11651165
if (refcount == 0 && interp->requires_idref) {
11661166
// XXX Using the "head" thread isn't strictly correct.
11671167
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1168+
11681169
// XXX Possible GILState issues?
11691170
PyThreadState *save_tstate = _PyThreadState_Swap(runtime, tstate);
11701171
Py_EndInterpreter(tstate);

0 commit comments

Comments
 (0)