/src/cpython/Modules/atexitmodule.c
Line | Count | Source |
1 | | /* |
2 | | * atexit - allow programmer to define multiple exit functions to be executed |
3 | | * upon normal program termination. |
4 | | * |
5 | | * Translated from atexit.py by Collin Winter. |
6 | | + Copyright 2007 Python Software Foundation. |
7 | | */ |
8 | | |
9 | | #include "Python.h" |
10 | | #include "pycore_atexit.h" // export _Py_AtExit() |
11 | | #include "pycore_initconfig.h" // _PyStatus_NO_MEMORY |
12 | | #include "pycore_interp.h" // PyInterpreterState.atexit |
13 | | #include "pycore_pystate.h" // _PyInterpreterState_GET |
14 | | |
15 | | /*[clinic input] |
16 | | module atexit |
17 | | [clinic start generated code]*/ |
18 | | /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ac8fd67d15bf23fc]*/ |
19 | | |
20 | | #include "clinic/atexitmodule.c.h" |
21 | | |
22 | | /* ===================================================================== */ |
23 | | /* Callback machinery. */ |
24 | | |
25 | | static inline struct atexit_state* |
26 | | get_atexit_state(void) |
27 | 10 | { |
28 | 10 | PyInterpreterState *interp = _PyInterpreterState_GET(); |
29 | 10 | return &interp->atexit; |
30 | 10 | } |
31 | | |
32 | | |
33 | | int |
34 | | PyUnstable_AtExit(PyInterpreterState *interp, |
35 | | atexit_datacallbackfunc func, void *data) |
36 | 0 | { |
37 | 0 | PyThreadState *tstate = _PyThreadState_GET(); |
38 | 0 | _Py_EnsureTstateNotNULL(tstate); |
39 | 0 | assert(tstate->interp == interp); |
40 | |
|
41 | 0 | atexit_callback *callback = PyMem_Malloc(sizeof(atexit_callback)); |
42 | 0 | if (callback == NULL) { |
43 | 0 | PyErr_NoMemory(); |
44 | 0 | return -1; |
45 | 0 | } |
46 | 0 | callback->func = func; |
47 | 0 | callback->data = data; |
48 | 0 | callback->next = NULL; |
49 | |
|
50 | 0 | struct atexit_state *state = &interp->atexit; |
51 | 0 | _PyAtExit_LockCallbacks(state); |
52 | 0 | atexit_callback *top = state->ll_callbacks; |
53 | 0 | if (top == NULL) { |
54 | 0 | state->ll_callbacks = callback; |
55 | 0 | } |
56 | 0 | else { |
57 | 0 | callback->next = top; |
58 | 0 | state->ll_callbacks = callback; |
59 | 0 | } |
60 | 0 | _PyAtExit_UnlockCallbacks(state); |
61 | 0 | return 0; |
62 | 0 | } |
63 | | |
64 | | |
65 | | /* Clear all callbacks without calling them */ |
66 | | static void |
67 | | atexit_cleanup(struct atexit_state *state) |
68 | 0 | { |
69 | 0 | PyList_Clear(state->callbacks); |
70 | 0 | } |
71 | | |
72 | | |
73 | | PyStatus |
74 | | _PyAtExit_Init(PyInterpreterState *interp) |
75 | 37 | { |
76 | 37 | struct atexit_state *state = &interp->atexit; |
77 | | // _PyAtExit_Init() must only be called once |
78 | 37 | assert(state->callbacks == NULL); |
79 | | |
80 | 37 | state->callbacks = PyList_New(0); |
81 | 37 | if (state->callbacks == NULL) { |
82 | 0 | return _PyStatus_NO_MEMORY(); |
83 | 0 | } |
84 | 37 | return _PyStatus_OK(); |
85 | 37 | } |
86 | | |
87 | | void |
88 | | _PyAtExit_Fini(PyInterpreterState *interp) |
89 | 0 | { |
90 | | // In theory, there shouldn't be any threads left by now, so we |
91 | | // won't lock this. |
92 | 0 | struct atexit_state *state = &interp->atexit; |
93 | 0 | atexit_cleanup(state); |
94 | 0 | Py_CLEAR(state->callbacks); |
95 | |
|
96 | 0 | atexit_callback *next = state->ll_callbacks; |
97 | 0 | state->ll_callbacks = NULL; |
98 | 0 | while (next != NULL) { |
99 | 0 | atexit_callback *callback = next; |
100 | 0 | next = callback->next; |
101 | 0 | atexit_datacallbackfunc exitfunc = callback->func; |
102 | 0 | void *data = callback->data; |
103 | | // It was allocated in _PyAtExit_AddCallback(). |
104 | 0 | PyMem_Free(callback); |
105 | 0 | exitfunc(data); |
106 | 0 | } |
107 | 0 | } |
108 | | |
109 | | static void |
110 | | atexit_callfuncs(struct atexit_state *state) |
111 | 0 | { |
112 | 0 | assert(!PyErr_Occurred()); |
113 | 0 | assert(state->callbacks != NULL); |
114 | 0 | assert(PyList_CheckExact(state->callbacks)); |
115 | | |
116 | | // Create a copy of the list for thread safety |
117 | 0 | PyObject *copy = PyList_GetSlice(state->callbacks, 0, PyList_GET_SIZE(state->callbacks)); |
118 | 0 | if (copy == NULL) |
119 | 0 | { |
120 | 0 | PyErr_FormatUnraisable("Exception ignored while " |
121 | 0 | "copying atexit callbacks"); |
122 | 0 | atexit_cleanup(state); |
123 | 0 | return; |
124 | 0 | } |
125 | | |
126 | 0 | for (Py_ssize_t i = 0; i < PyList_GET_SIZE(copy); ++i) { |
127 | | // We don't have to worry about evil borrowed references, because |
128 | | // no other threads can access this list. |
129 | 0 | PyObject *tuple = PyList_GET_ITEM(copy, i); |
130 | 0 | assert(PyTuple_CheckExact(tuple)); |
131 | |
|
132 | 0 | PyObject *func = PyTuple_GET_ITEM(tuple, 0); |
133 | 0 | PyObject *args = PyTuple_GET_ITEM(tuple, 1); |
134 | 0 | PyObject *kwargs = PyTuple_GET_ITEM(tuple, 2); |
135 | |
|
136 | 0 | PyObject *res = PyObject_Call(func, |
137 | 0 | args, |
138 | 0 | kwargs == Py_None ? NULL : kwargs); |
139 | 0 | if (res == NULL) { |
140 | 0 | PyErr_FormatUnraisable( |
141 | 0 | "Exception ignored in atexit callback %R", func); |
142 | 0 | } |
143 | 0 | else { |
144 | 0 | Py_DECREF(res); |
145 | 0 | } |
146 | 0 | } |
147 | |
|
148 | 0 | Py_DECREF(copy); |
149 | 0 | atexit_cleanup(state); |
150 | |
|
151 | 0 | assert(!PyErr_Occurred()); |
152 | 0 | } |
153 | | |
154 | | |
155 | | void |
156 | | _PyAtExit_Call(PyInterpreterState *interp) |
157 | 0 | { |
158 | 0 | struct atexit_state *state = &interp->atexit; |
159 | 0 | atexit_callfuncs(state); |
160 | 0 | } |
161 | | |
162 | | |
163 | | /* ===================================================================== */ |
164 | | /* Module methods. */ |
165 | | |
166 | | |
167 | | /*[clinic input] |
168 | | atexit.register |
169 | | |
170 | | func: object |
171 | | / |
172 | | *args: tuple |
173 | | **kwargs: dict |
174 | | |
175 | | Register a function to be executed upon normal program termination |
176 | | |
177 | | func - function to be called at exit |
178 | | args - optional arguments to pass to func |
179 | | kwargs - optional keyword arguments to pass to func |
180 | | |
181 | | func is returned to facilitate usage as a decorator. |
182 | | [clinic start generated code]*/ |
183 | | |
184 | | static PyObject * |
185 | | atexit_register_impl(PyObject *module, PyObject *func, PyObject *args, |
186 | | PyObject *kwargs) |
187 | | /*[clinic end generated code: output=c921286994bd8612 input=a682b5a343a82e4a]*/ |
188 | 10 | { |
189 | 10 | if (!PyCallable_Check(func)) { |
190 | 0 | PyErr_SetString(PyExc_TypeError, |
191 | 0 | "the first argument must be callable"); |
192 | 0 | return NULL; |
193 | 0 | } |
194 | 10 | PyObject *callback = PyTuple_Pack(3, func, args, kwargs); |
195 | 10 | if (callback == NULL) |
196 | 0 | { |
197 | 0 | return NULL; |
198 | 0 | } |
199 | | |
200 | 10 | struct atexit_state *state = get_atexit_state(); |
201 | | // atexit callbacks go in a LIFO order |
202 | 10 | if (PyList_Insert(state->callbacks, 0, callback) < 0) |
203 | 0 | { |
204 | 0 | Py_DECREF(callback); |
205 | 0 | return NULL; |
206 | 0 | } |
207 | 10 | Py_DECREF(callback); |
208 | | |
209 | 10 | return Py_NewRef(func); |
210 | 10 | } |
211 | | |
212 | | PyDoc_STRVAR(atexit_run_exitfuncs__doc__, |
213 | | "_run_exitfuncs($module, /)\n\ |
214 | | --\n\ |
215 | | \n\ |
216 | | Run all registered exit functions.\n\ |
217 | | \n\ |
218 | | If a callback raises an exception, it is logged with sys.unraisablehook."); |
219 | | |
220 | | static PyObject * |
221 | | atexit_run_exitfuncs(PyObject *module, PyObject *Py_UNUSED(dummy)) |
222 | 0 | { |
223 | 0 | struct atexit_state *state = get_atexit_state(); |
224 | 0 | atexit_callfuncs(state); |
225 | 0 | Py_RETURN_NONE; |
226 | 0 | } |
227 | | |
228 | | PyDoc_STRVAR(atexit_clear__doc__, |
229 | | "_clear($module, /)\n\ |
230 | | --\n\ |
231 | | \n\ |
232 | | Clear the list of previously registered exit functions."); |
233 | | |
234 | | static PyObject * |
235 | | atexit_clear(PyObject *module, PyObject *Py_UNUSED(dummy)) |
236 | 0 | { |
237 | 0 | atexit_cleanup(get_atexit_state()); |
238 | 0 | Py_RETURN_NONE; |
239 | 0 | } |
240 | | |
241 | | PyDoc_STRVAR(atexit_ncallbacks__doc__, |
242 | | "_ncallbacks($module, /)\n\ |
243 | | --\n\ |
244 | | \n\ |
245 | | Return the number of registered exit functions."); |
246 | | |
247 | | static PyObject * |
248 | | atexit_ncallbacks(PyObject *module, PyObject *Py_UNUSED(dummy)) |
249 | 0 | { |
250 | 0 | struct atexit_state *state = get_atexit_state(); |
251 | 0 | assert(state->callbacks != NULL); |
252 | 0 | assert(PyList_CheckExact(state->callbacks)); |
253 | 0 | return PyLong_FromSsize_t(PyList_GET_SIZE(state->callbacks)); |
254 | 0 | } |
255 | | |
256 | | static int |
257 | | atexit_unregister_locked(PyObject *callbacks, PyObject *func) |
258 | 0 | { |
259 | 0 | for (Py_ssize_t i = PyList_GET_SIZE(callbacks) - 1; i >= 0; --i) { |
260 | 0 | PyObject *tuple = Py_NewRef(PyList_GET_ITEM(callbacks, i)); |
261 | 0 | assert(PyTuple_CheckExact(tuple)); |
262 | 0 | PyObject *to_compare = PyTuple_GET_ITEM(tuple, 0); |
263 | 0 | int cmp = PyObject_RichCompareBool(func, to_compare, Py_EQ); |
264 | 0 | if (cmp < 0) { |
265 | 0 | Py_DECREF(tuple); |
266 | 0 | return -1; |
267 | 0 | } |
268 | 0 | if (cmp == 1) { |
269 | | // We found a callback! |
270 | | // But its index could have changed if it or other callbacks were |
271 | | // unregistered during the comparison. |
272 | 0 | Py_ssize_t j = PyList_GET_SIZE(callbacks) - 1; |
273 | 0 | j = Py_MIN(j, i); |
274 | 0 | for (; j >= 0; --j) { |
275 | 0 | if (PyList_GET_ITEM(callbacks, j) == tuple) { |
276 | | // We found the callback index! For real! |
277 | 0 | if (PyList_SetSlice(callbacks, j, j + 1, NULL) < 0) { |
278 | 0 | Py_DECREF(tuple); |
279 | 0 | return -1; |
280 | 0 | } |
281 | 0 | i = j; |
282 | 0 | break; |
283 | 0 | } |
284 | 0 | } |
285 | 0 | } |
286 | 0 | Py_DECREF(tuple); |
287 | 0 | if (i >= PyList_GET_SIZE(callbacks)) { |
288 | 0 | i = PyList_GET_SIZE(callbacks); |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | 0 | return 0; |
293 | 0 | } |
294 | | |
295 | | PyDoc_STRVAR(atexit_unregister__doc__, |
296 | | "unregister($module, func, /)\n\ |
297 | | --\n\ |
298 | | \n\ |
299 | | Unregister an exit function which was previously registered using\n\ |
300 | | atexit.register\n\ |
301 | | \n\ |
302 | | func - function to be unregistered"); |
303 | | |
304 | | static PyObject * |
305 | | atexit_unregister(PyObject *module, PyObject *func) |
306 | 0 | { |
307 | 0 | struct atexit_state *state = get_atexit_state(); |
308 | 0 | int result; |
309 | 0 | Py_BEGIN_CRITICAL_SECTION(state->callbacks); |
310 | 0 | result = atexit_unregister_locked(state->callbacks, func); |
311 | 0 | Py_END_CRITICAL_SECTION(); |
312 | 0 | return result < 0 ? NULL : Py_None; |
313 | 0 | } |
314 | | |
315 | | |
316 | | static PyMethodDef atexit_methods[] = { |
317 | | ATEXIT_REGISTER_METHODDEF |
318 | | {"_clear", atexit_clear, METH_NOARGS, atexit_clear__doc__}, |
319 | | {"unregister", atexit_unregister, METH_O, atexit_unregister__doc__}, |
320 | | {"_run_exitfuncs", atexit_run_exitfuncs, METH_NOARGS, |
321 | | atexit_run_exitfuncs__doc__}, |
322 | | {"_ncallbacks", atexit_ncallbacks, METH_NOARGS, |
323 | | atexit_ncallbacks__doc__}, |
324 | | {NULL, NULL} /* sentinel */ |
325 | | }; |
326 | | |
327 | | |
328 | | /* ===================================================================== */ |
329 | | /* Initialization function. */ |
330 | | |
331 | | PyDoc_STRVAR(atexit__doc__, |
332 | | "allow programmer to define multiple exit functions to be executed\n\ |
333 | | upon normal program termination.\n\ |
334 | | \n\ |
335 | | Two public functions, register and unregister, are defined.\n\ |
336 | | "); |
337 | | |
338 | | static PyModuleDef_Slot atexitmodule_slots[] = { |
339 | | _Py_ABI_SLOT, |
340 | | {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, |
341 | | {Py_mod_gil, Py_MOD_GIL_NOT_USED}, |
342 | | {0, NULL} |
343 | | }; |
344 | | |
345 | | static struct PyModuleDef atexitmodule = { |
346 | | PyModuleDef_HEAD_INIT, |
347 | | .m_name = "atexit", |
348 | | .m_doc = atexit__doc__, |
349 | | .m_size = 0, |
350 | | .m_methods = atexit_methods, |
351 | | .m_slots = atexitmodule_slots, |
352 | | }; |
353 | | |
354 | | PyMODINIT_FUNC |
355 | | PyInit_atexit(void) |
356 | 8 | { |
357 | 8 | return PyModuleDef_Init(&atexitmodule); |
358 | 8 | } |