bpo-42639: Move atexit state to PyInterpreterState (GH-23763) · python/cpython@b8fa135
@@ -7,38 +7,26 @@
77 */
8899#include "Python.h"
10-#include "pycore_interp.h" // PyInterpreterState.atexit_func
10+#include "pycore_initconfig.h" // _PyStatus_NO_MEMORY
11+#include "pycore_interp.h" // PyInterpreterState.atexit
1112#include "pycore_pystate.h" // _PyInterpreterState_GET
12131314/* ===================================================================== */
1415/* Callback machinery. */
151616-typedef struct {
17-PyObject *func;
18-PyObject *args;
19-PyObject *kwargs;
20-} atexit_callback;
21-22-struct atexit_state {
23-atexit_callback **atexit_callbacks;
24-int ncallbacks;
25-int callback_len;
26-};
27-2817static inline struct atexit_state*
29-get_atexit_state(PyObject *module)
18+get_atexit_state(void)
3019{
31-void *state = PyModule_GetState(module);
32-assert(state != NULL);
33-return (struct atexit_state *)state;
20+PyInterpreterState *interp = _PyInterpreterState_GET();
21+return &interp->atexit;
3422}
352336243725static void
3826atexit_delete_cb(struct atexit_state *state, int i)
3927{
40-atexit_callback *cb = state->atexit_callbacks[i];
41-state->atexit_callbacks[i] = NULL;
28+atexit_callback *cb = state->callbacks[i];
29+state->callbacks[i] = NULL;
42304331Py_DECREF(cb->func);
4432Py_DECREF(cb->args);
@@ -53,7 +41,7 @@ atexit_cleanup(struct atexit_state *state)
5341{
5442atexit_callback *cb;
5543for (int i = 0; i < state->ncallbacks; i++) {
56-cb = state->atexit_callbacks[i];
44+cb = state->callbacks[i];
5745if (cb == NULL)
5846continue;
5947@@ -62,25 +50,45 @@ atexit_cleanup(struct atexit_state *state)
6250state->ncallbacks = 0;
6351}
645265-/* Installed into pylifecycle.c's atexit mechanism */
665367-static void
68-atexit_callfuncs(PyObject *module, int ignore_exc)
54+PyStatus
55+_PyAtExit_Init(PyThreadState *tstate)
6956{
70-assert(!PyErr_Occurred());
57+struct atexit_state *state = &tstate->interp->atexit;
58+// _PyAtExit_Init() must only be called once
59+assert(state->callbacks == NULL);
716072-if (module == NULL) {
73-return;
61+state->callback_len = 32;
62+state->ncallbacks = 0;
63+state->callbacks = PyMem_New(atexit_callback*, state->callback_len);
64+if (state->callbacks == NULL) {
65+return _PyStatus_NO_MEMORY();
7466 }
67+return _PyStatus_OK();
68+}
69+70+71+void
72+_PyAtExit_Fini(PyInterpreterState *interp)
73+{
74+struct atexit_state *state = &interp->atexit;
75+atexit_cleanup(state);
76+PyMem_Free(state->callbacks);
77+}
78+79+80+static void
81+atexit_callfuncs(struct atexit_state *state, int ignore_exc)
82+{
83+assert(!PyErr_Occurred());
758476-struct atexit_state *state = get_atexit_state(module);
7785if (state->ncallbacks == 0) {
7886return;
7987 }
80888189PyObject *exc_type = NULL, *exc_value, *exc_tb;
8290for (int i = state->ncallbacks - 1; i >= 0; i--) {
83-atexit_callback *cb = state->atexit_callbacks[i];
91+atexit_callback *cb = state->callbacks[i];
8492if (cb == NULL) {
8593continue;
8694 }
@@ -125,15 +133,17 @@ atexit_callfuncs(PyObject *module, int ignore_exc)
125133126134127135void
128-_PyAtExit_Call(PyObject *module)
136+_PyAtExit_Call(PyThreadState *tstate)
129137{
130-atexit_callfuncs(module, 1);
138+struct atexit_state *state = &tstate->interp->atexit;
139+atexit_callfuncs(state, 1);
131140}
132141133142134143/* ===================================================================== */
135144/* Module methods. */
136145146+137147PyDoc_STRVAR(atexit_register__doc__,
138148"register(func, *args, **kwargs) -> func\n\
139149\n\
@@ -161,15 +171,15 @@ atexit_register(PyObject *module, PyObject *args, PyObject *kwargs)
161171return NULL;
162172 }
163173164-struct atexit_state *state = get_atexit_state(module);
174+struct atexit_state *state = get_atexit_state();
165175if (state->ncallbacks >= state->callback_len) {
166176atexit_callback **r;
167177state->callback_len += 16;
168-r = (atexit_callback**)PyMem_Realloc(state->atexit_callbacks,
169- sizeof(atexit_callback*) * state->callback_len);
178+size_t size = sizeof(atexit_callback*) * (size_t)state->callback_len;
179+r = (atexit_callback**)PyMem_Realloc(state->callbacks, size);
170180if (r == NULL)
171181return PyErr_NoMemory();
172-state->atexit_callbacks = r;
182+state->callbacks = r;
173183 }
174184175185atexit_callback *callback = PyMem_Malloc(sizeof(atexit_callback));
@@ -185,7 +195,7 @@ atexit_register(PyObject *module, PyObject *args, PyObject *kwargs)
185195callback->func = Py_NewRef(func);
186196callback->kwargs = Py_XNewRef(kwargs);
187197188-state->atexit_callbacks[state->ncallbacks++] = callback;
198+state->callbacks[state->ncallbacks++] = callback;
189199190200return Py_NewRef(func);
191201}
@@ -198,7 +208,8 @@ Run all registered exit functions.");
198208static PyObject *
199209atexit_run_exitfuncs(PyObject *module, PyObject *unused)
200210{
201-atexit_callfuncs(module, 0);
211+struct atexit_state *state = get_atexit_state();
212+atexit_callfuncs(state, 0);
202213if (PyErr_Occurred()) {
203214return NULL;
204215 }
@@ -213,7 +224,7 @@ Clear the list of previously registered exit functions.");
213224static PyObject *
214225atexit_clear(PyObject *module, PyObject *unused)
215226{
216-atexit_cleanup(get_atexit_state(module));
227+atexit_cleanup(get_atexit_state());
217228Py_RETURN_NONE;
218229}
219230@@ -225,41 +236,10 @@ Return the number of registered exit functions.");
225236static PyObject *
226237atexit_ncallbacks(PyObject *module, PyObject *unused)
227238{
228-struct atexit_state *state = get_atexit_state(module);
239+struct atexit_state *state = get_atexit_state();
229240return PyLong_FromSsize_t(state->ncallbacks);
230241}
231242232-static int
233-atexit_m_traverse(PyObject *module, visitproc visit, void *arg)
234-{
235-struct atexit_state *state = (struct atexit_state *)PyModule_GetState(module);
236-for (int i = 0; i < state->ncallbacks; i++) {
237-atexit_callback *cb = state->atexit_callbacks[i];
238-if (cb == NULL)
239-continue;
240-Py_VISIT(cb->func);
241-Py_VISIT(cb->args);
242-Py_VISIT(cb->kwargs);
243- }
244-return 0;
245-}
246-247-static int
248-atexit_m_clear(PyObject *module)
249-{
250-struct atexit_state *state = (struct atexit_state *)PyModule_GetState(module);
251-atexit_cleanup(state);
252-return 0;
253-}
254-255-static void
256-atexit_free(PyObject *module)
257-{
258-struct atexit_state *state = (struct atexit_state *)PyModule_GetState(module);
259-atexit_cleanup(state);
260-PyMem_Free(state->atexit_callbacks);
261-}
262-263243PyDoc_STRVAR(atexit_unregister__doc__,
264244"unregister(func) -> None\n\
265245\n\
@@ -271,10 +251,10 @@ atexit.register\n\
271251static PyObject *
272252atexit_unregister(PyObject *module, PyObject *func)
273253{
274-struct atexit_state *state = get_atexit_state(module);
254+struct atexit_state *state = get_atexit_state();
275255for (int i = 0; i < state->ncallbacks; i++)
276256 {
277-atexit_callback *cb = state->atexit_callbacks[i];
257+atexit_callback *cb = state->callbacks[i];
278258if (cb == NULL) {
279259continue;
280260 }
@@ -305,6 +285,7 @@ static PyMethodDef atexit_methods[] = {
305285 {NULL, NULL} /* sentinel */
306286};
307287288+308289/* ===================================================================== */
309290/* Initialization function. */
310291@@ -315,37 +296,12 @@ upon normal program termination.\n\
315296Two public functions, register and unregister, are defined.\n\
316297");
317298318-static int
319-atexit_exec(PyObject *module)
320-{
321-struct atexit_state *state = get_atexit_state(module);
322-state->callback_len = 32;
323-state->ncallbacks = 0;
324-state->atexit_callbacks = PyMem_New(atexit_callback*, state->callback_len);
325-if (state->atexit_callbacks == NULL) {
326-return -1;
327- }
328-329-PyInterpreterState *interp = _PyInterpreterState_GET();
330-interp->atexit_module = module;
331-return 0;
332-}
333-334-static PyModuleDef_Slot atexit_slots[] = {
335- {Py_mod_exec, atexit_exec},
336- {0, NULL}
337-};
338-339299static struct PyModuleDef atexitmodule = {
340300PyModuleDef_HEAD_INIT,
341301 .m_name = "atexit",
342302 .m_doc = atexit__doc__,
343- .m_size = sizeof(struct atexit_state),
303+ .m_size = 0,
344304 .m_methods = atexit_methods,
345- .m_slots = atexit_slots,
346- .m_traverse = atexit_m_traverse,
347- .m_clear = atexit_m_clear,
348- .m_free = (freefunc)atexit_free
349305};
350306351307PyMODINIT_FUNC