bpo-42639: Move atexit state to PyInterpreterState (GH-23763) · python/cpython@b8fa135 · GitHub
Skip to content

Commit b8fa135

Browse files
vstinnercorona10
andauthored
bpo-42639: Move atexit state to PyInterpreterState (GH-23763)
* Add _PyAtExit_Call() function and remove pyexitfunc and pyexitmodule members of PyInterpreterState. The function logs atexit callback errors using _PyErr_WriteUnraisableMsg(). * Add _PyAtExit_Init() and _PyAtExit_Fini() functions. * Remove traverse, clear and free functions of the atexit module. Co-authored-by: Dong-hee Na <donghee.na@python.org>
1 parent 8473cf8 commit b8fa135

7 files changed

Lines changed: 101 additions & 113 deletions

File tree

Include/internal/pycore_interp.h

Lines changed: 15 additions & 3 deletions

Include/internal/pycore_pylifecycle.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ extern PyStatus _PyTypes_Init(void);
5555
extern PyStatus _PyTypes_InitSlotDefs(void);
5656
extern PyStatus _PyImportZip_Init(PyThreadState *tstate);
5757
extern PyStatus _PyGC_Init(PyThreadState *tstate);
58+
extern PyStatus _PyAtExit_Init(PyThreadState *tstate);
5859

5960

6061
/* Various internal finalizers */
@@ -85,6 +86,7 @@ extern void _PyHash_Fini(void);
8586
extern void _PyTraceMalloc_Fini(void);
8687
extern void _PyWarnings_Fini(PyInterpreterState *interp);
8788
extern void _PyAST_Fini(PyInterpreterState *interp);
89+
extern void _PyAtExit_Fini(PyInterpreterState *interp);
8890

8991
extern PyStatus _PyGILState_Init(PyThreadState *tstate);
9092
extern void _PyGILState_Fini(PyThreadState *tstate);
@@ -109,7 +111,7 @@ PyAPI_FUNC(void) _PyErr_Display(PyObject *file, PyObject *exception,
109111

110112
PyAPI_FUNC(void) _PyThreadState_DeleteCurrent(PyThreadState *tstate);
111113

112-
extern void _PyAtExit_Call(PyObject *module);
114+
extern void _PyAtExit_Call(PyThreadState *tstate);
113115

114116
#ifdef __cplusplus
115117
}

Lib/test/test_atexit.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,24 @@ def f(msg):
170170
self.assertEqual(res.out.decode().splitlines(), ["two", "one"])
171171
self.assertFalse(res.err)
172172

173+
def test_atexit_instances(self):
174+
# bpo-42639: It is safe to have more than one atexit instance.
175+
code = textwrap.dedent("""
176+
import sys
177+
import atexit as atexit1
178+
del sys.modules['atexit']
179+
import atexit as atexit2
180+
del sys.modules['atexit']
181+
182+
assert atexit2 is not atexit1
183+
184+
atexit1.register(print, "atexit1")
185+
atexit2.register(print, "atexit2")
186+
""")
187+
res = script_helper.assert_python_ok("-c", code)
188+
self.assertEqual(res.out.decode().splitlines(), ["atexit2", "atexit1"])
189+
self.assertFalse(res.err)
190+
173191

174192
@support.cpython_only
175193
class SubinterpreterTest(unittest.TestCase):
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Make the :mod:`atexit` module state per-interpreter. It is now safe have more
2+
than one :mod:`atexit` module instance.
3+
Patch by Dong-hee Na and Victor Stinner.

Modules/atexitmodule.c

Lines changed: 53 additions & 97 deletions

0 commit comments

Comments
 (0)