Skip to content

Commit 2fcee90

Browse files
committed
Fix the tests.
1 parent 0601a6d commit 2fcee90

File tree

2 files changed

+13
-10
lines changed

2 files changed

+13
-10
lines changed

Lib/test/test_atexit.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@ def test_atexit_instances(self):
5252
@unittest.skipUnless(support.Py_GIL_DISABLED, "only meaningful without the GIL")
5353
def test_atexit_thread_safety(self):
5454
# GH-126907: atexit was not thread safe on the free-threaded build
55-
56-
# I'm not certain this needs to be in a script runner, but
57-
# let's do it anyway.
58-
code = textwrap.dedent("""
5955
from threading import Thread
6056

6157
def dummy():
@@ -70,10 +66,9 @@ def thready():
7066
atexit.unregister(dummy)
7167

7268

73-
for x in range(100):
74-
Thread(target=thready, args=()).start()
75-
""")
76-
script_helper.assert_python_ok("-c", code)
69+
threads = [Thread(target=thready) for _ in range(100)]
70+
with threading_helper.start_threads(threads):
71+
pass
7772

7873

7974
@support.cpython_only

Modules/atexitmodule.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,12 @@ atexit_delete_cb(struct atexit_state *state, int i)
6262
atexit_py_callback *cb = state->callbacks[i];
6363
state->callbacks[i] = NULL;
6464

65+
// This can execute code via finalizers
66+
_PyAtExit_UNLOCK(state);
6567
Py_DECREF(cb->func);
6668
Py_DECREF(cb->args);
6769
Py_XDECREF(cb->kwargs);
70+
_PyAtExit_LOCK(state);
6871
PyMem_Free(cb);
6972
}
7073

@@ -143,8 +146,12 @@ atexit_callfuncs(struct atexit_state *state)
143146
}
144147

145148
// bpo-46025: Increment the refcount of cb->func as the call itself may unregister it
146-
PyObject* the_func = Py_NewRef(cb->func);
147-
PyObject *res = PyObject_Call(cb->func, cb->args, cb->kwargs);
149+
PyObject *the_func = Py_NewRef(cb->func);
150+
PyObject *the_args = cb->args;
151+
PyObject *the_kwargs = cb->kwargs;
152+
// Unlock for re-entrancy problems
153+
_PyAtExit_UNLOCK(state);
154+
PyObject *res = PyObject_Call(the_func, the_args, the_kwargs);
148155
if (res == NULL) {
149156
PyErr_FormatUnraisable(
150157
"Exception ignored in atexit callback %R", the_func);
@@ -153,6 +160,7 @@ atexit_callfuncs(struct atexit_state *state)
153160
Py_DECREF(res);
154161
}
155162
Py_DECREF(the_func);
163+
_PyAtExit_LOCK(state);
156164
}
157165

158166
atexit_cleanup(state);

0 commit comments

Comments
 (0)