Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf53d9f2

Browse files
bpo-32604: Swap threads only if the interpreter is different. (gh-5778)
The CPython runtime assumes that there is a one-to-one relationship (for a given interpreter) between PyThreadState and OS threads. Sending and receiving on a channel in the same interpreter was causing crashes because of this (specifically due to a check in PyThreadState_Swap()). The solution is to not switch threads if the interpreter is the same.
1 parent80d20b9 commitf53d9f2

File tree

3 files changed

+77
-14
lines changed

3 files changed

+77
-14
lines changed

‎Lib/test/test__xxsubinterpreters.py‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
importpickle
44
fromtextwrapimportdedent,indent
55
importthreading
6+
importtime
67
importunittest
78

89
fromtestimportsupport
@@ -1147,6 +1148,54 @@ def test_send_recv_different_interpreters(self):
11471148

11481149
self.assertEqual(obj,b'spam')
11491150

1151+
deftest_send_recv_different_threads(self):
1152+
cid=interpreters.channel_create()
1153+
1154+
deff():
1155+
whileTrue:
1156+
try:
1157+
obj=interpreters.channel_recv(cid)
1158+
break
1159+
exceptinterpreters.ChannelEmptyError:
1160+
time.sleep(0.1)
1161+
interpreters.channel_send(cid,obj)
1162+
t=threading.Thread(target=f)
1163+
t.start()
1164+
1165+
interpreters.channel_send(cid,b'spam')
1166+
t.join()
1167+
obj=interpreters.channel_recv(cid)
1168+
1169+
self.assertEqual(obj,b'spam')
1170+
1171+
deftest_send_recv_different_interpreters_and_threads(self):
1172+
cid=interpreters.channel_create()
1173+
id1=interpreters.create()
1174+
out=None
1175+
1176+
deff():
1177+
nonlocalout
1178+
out=_run_output(id1,dedent(f"""
1179+
import time
1180+
import _xxsubinterpreters as _interpreters
1181+
while True:
1182+
try:
1183+
obj = _interpreters.channel_recv({int(cid)})
1184+
break
1185+
except _interpreters.ChannelEmptyError:
1186+
time.sleep(0.1)
1187+
assert(obj == b'spam')
1188+
_interpreters.channel_send({int(cid)}, b'eggs')
1189+
"""))
1190+
t=threading.Thread(target=f)
1191+
t.start()
1192+
1193+
interpreters.channel_send(cid,b'spam')
1194+
t.join()
1195+
obj=interpreters.channel_recv(cid)
1196+
1197+
self.assertEqual(obj,b'eggs')
1198+
11501199
deftest_send_not_found(self):
11511200
withself.assertRaises(interpreters.ChannelNotFoundError):
11521201
interpreters.channel_send(10,b'spam')

‎Modules/_xxsubinterpretersmodule.c‎

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,8 +1759,13 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr,
17591759
}
17601760

17611761
// Switch to interpreter.
1762-
PyThreadState*tstate=PyInterpreterState_ThreadHead(interp);
1763-
PyThreadState*save_tstate=PyThreadState_Swap(tstate);
1762+
PyThreadState*save_tstate=NULL;
1763+
if (interp!=PyThreadState_Get()->interp) {
1764+
// XXX Using the "head" thread isn't strictly correct.
1765+
PyThreadState*tstate=PyInterpreterState_ThreadHead(interp);
1766+
// XXX Possible GILState issues?
1767+
save_tstate=PyThreadState_Swap(tstate);
1768+
}
17641769

17651770
// Run the script.
17661771
_sharedexception*exc=NULL;
@@ -2079,9 +2084,9 @@ interp_create(PyObject *self, PyObject *args)
20792084
}
20802085

20812086
// Create and initialize the new interpreter.
2082-
PyThreadState*tstate,*save_tstate;
2083-
save_tstate=PyThreadState_Swap(NULL);
2084-
tstate=Py_NewInterpreter();
2087+
PyThreadState*save_tstate=PyThreadState_Swap(NULL);
2088+
// XXX Possible GILState issues?
2089+
PyThreadState*tstate=Py_NewInterpreter();
20852090
PyThreadState_Swap(save_tstate);
20862091
if (tstate==NULL) {
20872092
/* Since no new thread state was created, there is no exception to
@@ -2096,6 +2101,7 @@ interp_create(PyObject *self, PyObject *args)
20962101
return_get_id(tstate->interp);
20972102

20982103
error:
2104+
// XXX Possible GILState issues?
20992105
save_tstate=PyThreadState_Swap(tstate);
21002106
Py_EndInterpreter(tstate);
21012107
PyThreadState_Swap(save_tstate);
@@ -2146,9 +2152,9 @@ interp_destroy(PyObject *self, PyObject *args)
21462152

21472153
// Destroy the interpreter.
21482154
//PyInterpreterState_Delete(interp);
2149-
PyThreadState*tstate,*save_tstate;
2150-
tstate=PyInterpreterState_ThreadHead(interp);
2151-
save_tstate=PyThreadState_Swap(tstate);
2155+
PyThreadState*tstate=PyInterpreterState_ThreadHead(interp);
2156+
// XXX Possible GILState issues?
2157+
PyThreadState*save_tstate=PyThreadState_Swap(tstate);
21522158
Py_EndInterpreter(tstate);
21532159
PyThreadState_Swap(save_tstate);
21542160

‎Python/pystate.c‎

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,10 @@ _PyInterpreterState_IDDecref(PyInterpreterState *interp)
331331
PyThread_release_lock(interp->id_mutex);
332332

333333
if (refcount==0) {
334-
PyThreadState*tstate,*save_tstate;
335-
tstate=PyInterpreterState_ThreadHead(interp);
336-
save_tstate=PyThreadState_Swap(tstate);
334+
// XXX Using the "head" thread isn't strictly correct.
335+
PyThreadState*tstate=PyInterpreterState_ThreadHead(interp);
336+
// XXX Possible GILState issues?
337+
PyThreadState*save_tstate=PyThreadState_Swap(tstate);
337338
Py_EndInterpreter(tstate);
338339
PyThreadState_Swap(save_tstate);
339340
}
@@ -1213,8 +1214,14 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
12131214
}
12141215
return;
12151216
}
1216-
PyThreadState*tstate=PyInterpreterState_ThreadHead(interp);
1217-
PyThreadState*save_tstate=PyThreadState_Swap(tstate);
1217+
1218+
PyThreadState*save_tstate=NULL;
1219+
if (interp!=PyThreadState_Get()->interp) {
1220+
// XXX Using the "head" thread isn't strictly correct.
1221+
PyThreadState*tstate=PyInterpreterState_ThreadHead(interp);
1222+
// XXX Possible GILState issues?
1223+
save_tstate=PyThreadState_Swap(tstate);
1224+
}
12181225

12191226
// "Release" the data and/or the object.
12201227
if (data->free!=NULL) {
@@ -1223,8 +1230,9 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
12231230
Py_XDECREF(data->obj);
12241231

12251232
// Switch back.
1226-
if (save_tstate!=NULL)
1233+
if (save_tstate!=NULL) {
12271234
PyThreadState_Swap(save_tstate);
1235+
}
12281236
}
12291237

12301238
PyObject*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp