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

Commit27bd082

Browse files
Revert "gh-128639: Don't assume one thread in subinterpreter finalization (gh-128640)" (gh-134256)
This reverts commit9859791.The original change broke the iOS and android buildbots, where the tests are run single-process.
1 parent871d269 commit27bd082

File tree

6 files changed

+38
-99
lines changed

6 files changed

+38
-99
lines changed

‎Lib/test/test_interpreters/test_api.py

Lines changed: 2 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -647,59 +647,6 @@ def test_created_with_capi(self):
647647
self.interp_exists(interpid))
648648

649649

650-
deftest_remaining_threads(self):
651-
r_interp,w_interp=self.pipe()
652-
653-
FINISHED=b'F'
654-
655-
# It's unlikely, but technically speaking, it's possible
656-
# that the thread could've finished before interp.close() is
657-
# reached, so this test might not properly exercise the case.
658-
# However, it's quite unlikely and I'm too lazy to deal with it.
659-
interp=interpreters.create()
660-
interp.exec(f"""if True:
661-
import os
662-
import threading
663-
import time
664-
665-
def task():
666-
time.sleep(1)
667-
os.write({w_interp},{FINISHED!r})
668-
669-
threads = [threading.Thread(target=task) for _ in range(3)]
670-
for t in threads:
671-
t.start()
672-
""")
673-
interp.close()
674-
675-
self.assertEqual(os.read(r_interp,1),FINISHED)
676-
677-
deftest_remaining_daemon_threads(self):
678-
interp=_interpreters.create(
679-
types.SimpleNamespace(
680-
use_main_obmalloc=False,
681-
allow_fork=False,
682-
allow_exec=False,
683-
allow_threads=True,
684-
allow_daemon_threads=True,
685-
check_multi_interp_extensions=True,
686-
gil='own',
687-
)
688-
)
689-
_interpreters.exec(interp,f"""if True:
690-
import threading
691-
import time
692-
693-
def task():
694-
time.sleep(100)
695-
696-
threads = [threading.Thread(target=task, daemon=True) for _ in range(3)]
697-
for t in threads:
698-
t.start()
699-
""")
700-
_interpreters.destroy(interp)
701-
702-
703650
classTestInterpreterPrepareMain(TestBase):
704651

705652
deftest_empty(self):
@@ -808,10 +755,7 @@ def script():
808755
spam.eggs()
809756
810757
interp = interpreters.create()
811-
try:
812-
interp.exec(script)
813-
finally:
814-
interp.close()
758+
interp.exec(script)
815759
""")
816760

817761
stdout,stderr=self.assert_python_failure(scriptfile)
@@ -820,7 +764,7 @@ def script():
820764
# File "{interpreters.__file__}", line 179, in exec
821765
self.assertEqual(stderr,dedent(f"""\
822766
Traceback (most recent call last):
823-
File "{scriptfile}", line10, in <module>
767+
File "{scriptfile}", line9, in <module>
824768
interp.exec(script)
825769
~~~~~~~~~~~^^^^^^^^
826770
{interpmod_line.strip()}

‎Lib/test/test_interpreters/test_lifecycle.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,6 @@ def test_sys_path_0(self):
132132
'sub': sys.path[0],
133133
}}, indent=4), flush=True)
134134
""")
135-
interp.close()
136135
'''
137136
# <tmp>/
138137
# pkg/
@@ -173,10 +172,7 @@ def test_gh_109793(self):
173172
argv= [sys.executable,'-c','''if True:
174173
from test.support import interpreters
175174
interp = interpreters.create()
176-
try:
177-
raise Exception
178-
finally:
179-
interp.close()
175+
raise Exception
180176
''']
181177
proc=subprocess.run(argv,capture_output=True,text=True)
182178
self.assertIn('Traceback',proc.stderr)

‎Lib/test/test_threading.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1689,7 +1689,10 @@ def f():
16891689
16901690
_testcapi.run_in_subinterp(%r)
16911691
"""% (subinterp_code,)
1692-
assert_python_ok("-c",script)
1692+
withtest.support.SuppressCrashReport():
1693+
rc,out,err=assert_python_failure("-c",script)
1694+
self.assertIn("Fatal Python error: Py_EndInterpreter: "
1695+
"not the last thread",err.decode())
16931696

16941697
def_check_allowed(self,before_start='',*,
16951698
allowed=True,

‎Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-12-52-47.gh-issue-128640.9nbh9z.rst

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎Programs/_testembed.c

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,12 +1395,9 @@ static int test_audit_subinterpreter(void)
13951395
PySys_AddAuditHook(_audit_subinterpreter_hook,NULL);
13961396
_testembed_initialize();
13971397

1398-
PyThreadState*tstate=PyThreadState_Get();
1399-
for (inti=0;i<3;++i)
1400-
{
1401-
Py_EndInterpreter(Py_NewInterpreter());
1402-
PyThreadState_Swap(tstate);
1403-
}
1398+
Py_NewInterpreter();
1399+
Py_NewInterpreter();
1400+
Py_NewInterpreter();
14041401

14051402
Py_Finalize();
14061403

‎Python/pylifecycle.c

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,7 +1992,6 @@ resolve_final_tstate(_PyRuntimeState *runtime)
19921992
}
19931993
else {
19941994
/* Fall back to the current tstate. It's better than nothing. */
1995-
// XXX No it's not
19961995
main_tstate=tstate;
19971996
}
19981997
}
@@ -2038,16 +2037,6 @@ _Py_Finalize(_PyRuntimeState *runtime)
20382037

20392038
_PyAtExit_Call(tstate->interp);
20402039

2041-
/* Clean up any lingering subinterpreters.
2042-
2043-
Two preconditions need to be met here:
2044-
2045-
- This has to happen before _PyRuntimeState_SetFinalizing is
2046-
called, or else threads might get prematurely blocked.
2047-
- The world must not be stopped, as finalizers can run.
2048-
*/
2049-
finalize_subinterpreters();
2050-
20512040
assert(_PyThreadState_GET()==tstate);
20522041

20532042
/* Copy the core config, PyInterpreterState_Delete() free
@@ -2135,6 +2124,9 @@ _Py_Finalize(_PyRuntimeState *runtime)
21352124
_PyImport_FiniExternal(tstate->interp);
21362125
finalize_modules(tstate);
21372126

2127+
/* Clean up any lingering subinterpreters. */
2128+
finalize_subinterpreters();
2129+
21382130
/* Print debug stats if any */
21392131
_PyEval_Fini();
21402132

@@ -2418,8 +2410,9 @@ Py_NewInterpreter(void)
24182410
returntstate;
24192411
}
24202412

2421-
/* Delete an interpreter. This requires that the given thread state
2422-
is current, and that the thread has no remaining frames.
2413+
/* Delete an interpreter and its last thread. This requires that the
2414+
given thread state is current, that the thread has no remaining
2415+
frames, and that it is its interpreter's only remaining thread.
24232416
It is a fatal error to violate these constraints.
24242417
24252418
(Py_FinalizeEx() doesn't have these constraints -- it zaps
@@ -2449,15 +2442,14 @@ Py_EndInterpreter(PyThreadState *tstate)
24492442
_Py_FinishPendingCalls(tstate);
24502443

24512444
_PyAtExit_Call(tstate->interp);
2452-
_PyRuntimeState*runtime=interp->runtime;
2453-
_PyEval_StopTheWorldAll(runtime);
2454-
PyThreadState*list=_PyThreadState_RemoveExcept(tstate);
2445+
2446+
if (tstate!=interp->threads.head||tstate->next!=NULL) {
2447+
Py_FatalError("not the last thread");
2448+
}
24552449

24562450
/* Remaining daemon threads will automatically exit
24572451
when they attempt to take the GIL (ex: PyEval_RestoreThread()). */
24582452
_PyInterpreterState_SetFinalizing(interp,tstate);
2459-
_PyEval_StartTheWorldAll(runtime);
2460-
_PyThreadState_DeleteList(list,/*is_after_fork=*/0);
24612453

24622454
// XXX Call something like _PyImport_Disable() here?
24632455

@@ -2488,8 +2480,6 @@ finalize_subinterpreters(void)
24882480
PyInterpreterState*main_interp=_PyInterpreterState_Main();
24892481
assert(final_tstate->interp==main_interp);
24902482
_PyRuntimeState*runtime=main_interp->runtime;
2491-
assert(!runtime->stoptheworld.world_stopped);
2492-
assert(_PyRuntimeState_GetFinalizing(runtime)==NULL);
24932483
structpyinterpreters*interpreters=&runtime->interpreters;
24942484

24952485
/* Get the first interpreter in the list. */
@@ -2518,17 +2508,27 @@ finalize_subinterpreters(void)
25182508

25192509
/* Clean up all remaining subinterpreters. */
25202510
while (interp!=NULL) {
2521-
/* Make a tstate for finalization. */
2522-
PyThreadState*tstate=_PyThreadState_NewBound(interp,_PyThreadState_WHENCE_FINI);
2523-
if (tstate==NULL) {
2524-
// XXX Some graceful way to always get a thread state?
2525-
Py_FatalError("thread state allocation failed");
2511+
assert(!_PyInterpreterState_IsRunningMain(interp));
2512+
2513+
/* Find the tstate to use for fini. We assume the interpreter
2514+
will have at most one tstate at this point. */
2515+
PyThreadState*tstate=interp->threads.head;
2516+
if (tstate!=NULL) {
2517+
/* Ideally we would be able to use tstate as-is, and rely
2518+
on it being in a ready state: no exception set, not
2519+
running anything (tstate->current_frame), matching the
2520+
current thread ID (tstate->thread_id). To play it safe,
2521+
we always delete it and use a fresh tstate instead. */
2522+
assert(tstate!=final_tstate);
2523+
_PyThreadState_Attach(tstate);
2524+
PyThreadState_Clear(tstate);
2525+
_PyThreadState_Detach(tstate);
2526+
PyThreadState_Delete(tstate);
25262527
}
2527-
2528-
/* Enter the subinterpreter. */
2529-
_PyThreadState_Attach(tstate);
2528+
tstate=_PyThreadState_NewBound(interp,_PyThreadState_WHENCE_FINI);
25302529

25312530
/* Destroy the subinterpreter. */
2531+
_PyThreadState_Attach(tstate);
25322532
Py_EndInterpreter(tstate);
25332533
assert(_PyThreadState_GET()==NULL);
25342534

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp