8000 Merge branch 'gh-113964-thread-shutdown' into nogil-integration · colesbury/cpython@5f059ae · GitHub
[go: up one dir, main page]

Skip to content

Commit 5f059ae

Browse files
committed
Merge branch 'pythongh-113964-thread-shutdown' into nogil-integration
2 parents 9552433 + 27e4bc5 commit 5f059ae

File tree

8 files changed

+57
-27
lines changed

8 files changed

+57
-27
lines changed

Lib/test/test_os.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5357,20 +5357,21 @@ def test_fork_warns_when_non_python_thread_exists(self):
53575357
self.assertEqual(err.decode("utf-8"), "")
53585358
self.assertEqual(out.decode("utf-8"), "")
53595359

5360-
def test_fork_at_exit(self):
5360+
def test_fork_at_finalization(self):
53615361
code = """if 1:
53625362
import atexit
53635363
import os
53645364
5365-
def exit_handler():
5366-
pid = os.fork()
5367-
if pid != 0:
5368-
print("shouldn't be printed")
5369-
5370-
atexit.register(exit_handler)
5365+
class AtFinalization:
5366+
def __del__(self):
5367+
print("OK")
5368+
pid = os.fork()
5369+
if pid != 0:
5370+
print("shouldn't be printed")
5371+
at_finalization = AtFinalization()
53715372
"""
53725373
_, out, err = assert_python_ok("-c", code)
5373-
self.assertEqual(b"", out)
5374+
self.assertEqual(b"OK\n", out)
53745375
self.assertIn(b"can't fork at interpreter shutdown", err)
53755376

53765377

Lib/test/test_subprocess.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3382,14 +3382,15 @@ def test_preexec_at_exit(self):
33823382
def dummy():
33833383
pass
33843384
3385-
def exit_handler():
3386-
subprocess.Popen({ZERO_RETURN_CMD}, preexec_fn=dummy)
3387-
print("shouldn't be printed")
3388-
3389-
atexit.register(exit_handler)
8000 3385+
class AtFinalization:
3386+
def __del__(self):
3387+
print("OK")
3388+
subprocess.Popen({ZERO_RETURN_CMD}, preexec_fn=dummy)
3389+
print("shouldn't be printed")
3390+
at_finalization = AtFinalization()
33903391
"""
33913392
_, out, err = assert_python_ok("-c", code)
3392-
self.assertEqual(out, b'')
3393+
self.assertEqual(out.strip(), b"OK")
33933394
self.assertIn(b"preexec_fn not supported at interpreter shutdown", err)
33943395

33953396
@unittest.skipIf(not sysconfig.get_config_var("HAVE_VFORK"),

Lib/test/test_threading.py

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,21 +1143,21 @@ def import_threading():
11431143
self.assertEqual(out, b'')
11441144
self.assertEqual(err, b'')
11451145

1146-
def test_start_new_thread_at_exit(self):
1146+
def test_start_new_thread_at_finalization(self):
11471147
code = """if 1:
1148-
import atexit
11491148
import _thread
11501149
11511150
def f():
11521151
print("shouldn't be printed")
11531152
1154-
def exit_handler():
1155-
_thread.start_new_thread(f, ())
1156-
1157-
atexit.register(exit_handler)
1153+
class AtFinalization:
1154+
def __del__(self):
1155+
print("OK")
1156+
_thread.start_new_thread(f, ())
1157+
at_finalization = AtFinalization()
11581158
"""
11591159
_, out, err = assert_python_ok("-c", code)
1160-
self.assertEqual(out, b'')
1160+
self.assertEqual(out.strip(), b"OK")
11611161
self.assertIn(b"can't create new thread at interpreter shutdown", err)
11621162

11631163
class ThreadJoinOnShutdown(BaseTestCase):
@@ -1281,6 +1281,30 @@ def main():
12811281
rc, out, err = assert_python_ok('-c', script)
12821282
self.assertFalse(err)
12831283

1284+
def test_thread_from_thread(self):
1285+
script = """if True:
1286+
import threading
1287+
import time
1288+
1289+
def thread2():
1290+
time.sleep(0.05)
1291+
print("OK")
1292+
1293+
def thread1():
1294+
time.sleep(0.05)
1295+
t2 = threading.Thread(target=thread2)
1296+
t2.start()
1297+
1298+
t = threading.Thread(target=thread1)
1299+
t.start()
1300+
# do not join() -- the interpreter waits for non-daemon threads to
1301+
# finish.
1302+
"""
1303+
rc, out, err = assert_python_ok('-c', script)
1304+
self.assertEqual(err, b"")
1305+
self.assertEqual(out.strip(), b"OK")
1306+
self.assertEqual(rc, 0)
1307+
12841308
@skip_unless_reliable_fork
12851309
def test_reinit_tls_after_fork(self):
12861310
# Issue #13817: fork() would deadlock in a multithreaded program with
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Starting new threads and process creation through :func:`os.fork` are now
2+
only prevented once all non-daemon threads exit.

Modules/_posixsubprocess.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1031,7 +1031,9 @@ subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
10311031
Py_ssize_t fds_to_keep_len = PyTuple_GET_SIZE F438 (py_fds_to_keep);
10321032

10331033
PyInterpreterState *interp = _PyInterpreterState_GET();
1034-
if ((preexec_fn != Py_None) && interp->finalizing) {
1034+
if ((preexec_fn != Py_None) &&
1035+
_PyInterpreterState_GetFinalizing(interp) != NULL)
1036+
{
10351037
PyErr_SetString(PyExc_PythonFinalizationError,
10361038
"preexec_fn not supported at interpreter shutdown");
10371039
return NULL;

Modules/_threadmodule.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1719,7 +1719,7 @@ do_start_new_thread(thread_module_state *state, PyObject *func, PyObject *args,
17191719
"thread is not supported for isolated subinterpreters");
17201720
return -1;
17211721
}
1722-
if (interp->finalizing) {
1722+
if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
17231723
PyErr_SetString(PyExc_PythonFinalizationError,
17241724
"can't create new thread at interpreter shutdown");
17251725
return -1;

Modules/posixmodule.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7848,7 +7848,7 @@ os_fork1_impl(PyObject *module)
78487848
pid_t pid;
78497849

78507850
PyInterpreterState *interp = _PyInterpreterState_GET();
7851-
if (interp->finalizing) {
7851+
if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
78527852
PyErr_SetString(PyExc_PythonFinalizationError,
78537853
"can't fork at interpreter shutdown");
78547854
return NULL;
@@ -7892,7 +7892,7 @@ os_fork_impl(PyObject *module)
78927892
{
78937893
pid_t pid;
78947894
PyInterpreterState *interp = _PyInterpreterState_GET();
7895-
if (interp->finalizing) {
7895+
if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
78967896
PyErr_SetString(PyExc_PythonFinalizationError,
78977897
"can't fork at interpreter shutdown");
78987898
return NULL;
@@ -8725,7 +8725,7 @@ os_forkpty_impl(PyObject *module)
87258725
pid_t pid;
87268726

87278727
PyInterpreterState *interp = _PyInterpreterState_GET();
8728-
if (interp->finalizing) {
8728+
if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
87298729
PyErr_SetString(PyExc_PythonFinalizationError,
87308730
"can't fork at interpreter shutdown");
87318731
return NULL;

Objects/unicodeobject.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ unicode_check_encoding_errors(const char *encoding, const char *errors)
505505

506506
/* Disable checks during Python finalization. For example, it allows to
507507
call _PyObject_Dump() during finalization for debugging purpose. */
508-
if (interp->finalizing) {
508+
if (_PyInterpreterState_GetFinalizing(interp) != NULL) {
509509
return 0;
510510
}
511511

0 commit comments

Comments
 (0)
0