/src/Python-3.8.3/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  |  |  | 
11  |  | /* Forward declaration (for atexit_cleanup) */  | 
12  |  | static PyObject *atexit_clear(PyObject*, PyObject*);  | 
13  |  | /* Forward declaration of module object */  | 
14  |  | static struct PyModuleDef atexitmodule;  | 
15  |  |  | 
16  |  | /* ===================================================================== */  | 
17  |  | /* Callback machinery. */  | 
18  |  |  | 
19  |  | typedef struct { | 
20  |  |     PyObject *func;  | 
21  |  |     PyObject *args;  | 
22  |  |     PyObject *kwargs;  | 
23  |  | } atexit_callback;  | 
24  |  |  | 
25  |  | typedef struct { | 
26  |  |     atexit_callback **atexit_callbacks;  | 
27  |  |     int ncallbacks;  | 
28  |  |     int callback_len;  | 
29  |  | } atexitmodule_state;  | 
30  |  |  | 
31  | 2  | #define GET_ATEXIT_STATE(mod) ((atexitmodule_state*)PyModule_GetState(mod))  | 
32  |  |  | 
33  |  |  | 
34  |  | static void  | 
35  |  | atexit_delete_cb(atexitmodule_state *modstate, int i)  | 
36  | 0  | { | 
37  | 0  |     atexit_callback *cb;  | 
38  |  | 
  | 
39  | 0  |     cb = modstate->atexit_callbacks[i];  | 
40  | 0  |     modstate->atexit_callbacks[i] = NULL;  | 
41  | 0  |     Py_DECREF(cb->func);  | 
42  | 0  |     Py_DECREF(cb->args);  | 
43  | 0  |     Py_XDECREF(cb->kwargs);  | 
44  | 0  |     PyMem_Free(cb);  | 
45  | 0  | }  | 
46  |  |  | 
47  |  | /* Clear all callbacks without calling them */  | 
48  |  | static void  | 
49  |  | atexit_cleanup(atexitmodule_state *modstate)  | 
50  | 0  | { | 
51  | 0  |     atexit_callback *cb;  | 
52  | 0  |     int i;  | 
53  | 0  |     for (i = 0; i < modstate->ncallbacks; i++) { | 
54  | 0  |         cb = modstate->atexit_callbacks[i];  | 
55  | 0  |         if (cb == NULL)  | 
56  | 0  |             continue;  | 
57  |  |  | 
58  | 0  |         atexit_delete_cb(modstate, i);  | 
59  | 0  |     }  | 
60  | 0  |     modstate->ncallbacks = 0;  | 
61  | 0  | }  | 
62  |  |  | 
63  |  | /* Installed into pylifecycle.c's atexit mechanism */  | 
64  |  |  | 
65  |  | static void  | 
66  |  | atexit_callfuncs(PyObject *module)  | 
67  | 0  | { | 
68  | 0  |     PyObject *exc_type = NULL, *exc_value, *exc_tb, *r;  | 
69  | 0  |     atexit_callback *cb;  | 
70  | 0  |     atexitmodule_state *modstate;  | 
71  | 0  |     int i;  | 
72  |  | 
  | 
73  | 0  |     if (module == NULL)  | 
74  | 0  |         return;  | 
75  | 0  |     modstate = GET_ATEXIT_STATE(module);  | 
76  |  | 
  | 
77  | 0  |     if (modstate->ncallbacks == 0)  | 
78  | 0  |         return;  | 
79  |  |  | 
80  |  |  | 
81  | 0  |     for (i = modstate->ncallbacks - 1; i >= 0; i--)  | 
82  | 0  |     { | 
83  | 0  |         cb = modstate->atexit_callbacks[i];  | 
84  | 0  |         if (cb == NULL)  | 
85  | 0  |             continue;  | 
86  |  |  | 
87  | 0  |         r = PyObject_Call(cb->func, cb->args, cb->kwargs);  | 
88  | 0  |         Py_XDECREF(r);  | 
89  | 0  |         if (r == NULL) { | 
90  |  |             /* Maintain the last exception, but don't leak if there are  | 
91  |  |                multiple exceptions. */  | 
92  | 0  |             if (exc_type) { | 
93  | 0  |                 Py_DECREF(exc_type);  | 
94  | 0  |                 Py_XDECREF(exc_value);  | 
95  | 0  |                 Py_XDECREF(exc_tb);  | 
96  | 0  |             }  | 
97  | 0  |             PyErr_Fetch(&exc_type, &exc_value, &exc_tb);  | 
98  | 0  |             if (!PyErr_GivenExceptionMatches(exc_type, PyExc_SystemExit)) { | 
99  | 0  |                 PySys_WriteStderr("Error in atexit._run_exitfuncs:\n"); | 
100  | 0  |                 PyErr_NormalizeException(&exc_type, &exc_value, &exc_tb);  | 
101  | 0  |                 PyErr_Display(exc_type, exc_value, exc_tb);  | 
102  | 0  |             }  | 
103  | 0  |         }  | 
104  | 0  |     }  | 
105  |  | 
  | 
106  | 0  |     atexit_cleanup(modstate);  | 
107  |  | 
  | 
108  | 0  |     if (exc_type)  | 
109  | 0  |         PyErr_Restore(exc_type, exc_value, exc_tb);  | 
110  | 0  | }  | 
111  |  |  | 
112  |  | /* ===================================================================== */  | 
113  |  | /* Module methods. */  | 
114  |  |  | 
115  |  | PyDoc_STRVAR(atexit_register__doc__,  | 
116  |  | "register(func, *args, **kwargs) -> func\n\  | 
117  |  | \n\  | 
118  |  | Register a function to be executed upon normal program termination\n\  | 
119  |  | \n\  | 
120  |  |     func - function to be called at exit\n\  | 
121  |  |     args - optional arguments to pass to func\n\  | 
122  |  |     kwargs - optional keyword arguments to pass to func\n\  | 
123  |  | \n\  | 
124  |  |     func is returned to facilitate usage as a decorator.");  | 
125  |  |  | 
126  |  | static PyObject *  | 
127  |  | atexit_register(PyObject *self, PyObject *args, PyObject *kwargs)  | 
128  | 1  | { | 
129  | 1  |     atexitmodule_state *modstate;  | 
130  | 1  |     atexit_callback *new_callback;  | 
131  | 1  |     PyObject *func = NULL;  | 
132  |  |  | 
133  | 1  |     modstate = GET_ATEXIT_STATE(self);  | 
134  |  |  | 
135  | 1  |     if (modstate->ncallbacks >= modstate->callback_len) { | 
136  | 0  |         atexit_callback **r;  | 
137  | 0  |         modstate->callback_len += 16;  | 
138  | 0  |         r = (atexit_callback**)PyMem_Realloc(modstate->atexit_callbacks,  | 
139  | 0  |                                       sizeof(atexit_callback*) * modstate->callback_len);  | 
140  | 0  |         if (r == NULL)  | 
141  | 0  |             return PyErr_NoMemory();  | 
142  | 0  |         modstate->atexit_callbacks = r;  | 
143  | 0  |     }  | 
144  |  |  | 
145  | 1  |     if (PyTuple_GET_SIZE(args) == 0) { | 
146  | 0  |         PyErr_SetString(PyExc_TypeError,  | 
147  | 0  |                 "register() takes at least 1 argument (0 given)");  | 
148  | 0  |         return NULL;  | 
149  | 0  |     }  | 
150  |  |  | 
151  | 1  |     func = PyTuple_GET_ITEM(args, 0);  | 
152  | 1  |     if (!PyCallable_Check(func)) { | 
153  | 0  |         PyErr_SetString(PyExc_TypeError,  | 
154  | 0  |                 "the first argument must be callable");  | 
155  | 0  |         return NULL;  | 
156  | 0  |     }  | 
157  |  |  | 
158  | 1  |     new_callback = PyMem_Malloc(sizeof(atexit_callback));  | 
159  | 1  |     if (new_callback == NULL)  | 
160  | 0  |         return PyErr_NoMemory();  | 
161  |  |  | 
162  | 1  |     new_callback->args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));  | 
163  | 1  |     if (new_callback->args == NULL) { | 
164  | 0  |         PyMem_Free(new_callback);  | 
165  | 0  |         return NULL;  | 
166  | 0  |     }  | 
167  | 1  |     new_callback->func = func;  | 
168  | 1  |     new_callback->kwargs = kwargs;  | 
169  | 1  |     Py_INCREF(func);  | 
170  | 1  |     Py_XINCREF(kwargs);  | 
171  |  |  | 
172  | 1  |     modstate->atexit_callbacks[modstate->ncallbacks++] = new_callback;  | 
173  |  |  | 
174  | 1  |     Py_INCREF(func);  | 
175  | 1  |     return func;  | 
176  | 1  | }  | 
177  |  |  | 
178  |  | PyDoc_STRVAR(atexit_run_exitfuncs__doc__,  | 
179  |  | "_run_exitfuncs() -> None\n\  | 
180  |  | \n\  | 
181  |  | Run all registered exit functions.");  | 
182  |  |  | 
183  |  | static PyObject *  | 
184  |  | atexit_run_exitfuncs(PyObject *self, PyObject *unused)  | 
185  | 0  | { | 
186  | 0  |     atexit_callfuncs(self);  | 
187  | 0  |     if (PyErr_Occurred())  | 
188  | 0  |         return NULL;  | 
189  | 0  |     Py_RETURN_NONE;  | 
190  | 0  | }  | 
191  |  |  | 
192  |  | PyDoc_STRVAR(atexit_clear__doc__,  | 
193  |  | "_clear() -> None\n\  | 
194  |  | \n\  | 
195  |  | Clear the list of previously registered exit functions.");  | 
196  |  |  | 
197  |  | static PyObject *  | 
198  |  | atexit_clear(PyObject *self, PyObject *unused)  | 
199  | 0  | { | 
200  | 0  |     atexit_cleanup(GET_ATEXIT_STATE(self));  | 
201  | 0  |     Py_RETURN_NONE;  | 
202  | 0  | }  | 
203  |  |  | 
204  |  | PyDoc_STRVAR(atexit_ncallbacks__doc__,  | 
205  |  | "_ncallbacks() -> int\n\  | 
206  |  | \n\  | 
207  |  | Return the number of registered exit functions.");  | 
208  |  |  | 
209  |  | static PyObject *  | 
210  |  | atexit_ncallbacks(PyObject *self, PyObject *unused)  | 
211  | 0  | { | 
212  | 0  |     atexitmodule_state *modstate;  | 
213  |  | 
  | 
214  | 0  |     modstate = GET_ATEXIT_STATE(self);  | 
215  |  | 
  | 
216  | 0  |     return PyLong_FromSsize_t(modstate->ncallbacks);  | 
217  | 0  | }  | 
218  |  |  | 
219  |  | static int  | 
220  |  | atexit_m_traverse(PyObject *self, visitproc visit, void *arg)  | 
221  | 0  | { | 
222  | 0  |     int i;  | 
223  | 0  |     atexitmodule_state *modstate;  | 
224  |  | 
  | 
225  | 0  |     modstate = GET_ATEXIT_STATE(self);  | 
226  | 0  |     if (modstate != NULL) { | 
227  | 0  |         for (i = 0; i < modstate->ncallbacks; i++) { | 
228  | 0  |             atexit_callback *cb = modstate->atexit_callbacks[i];  | 
229  | 0  |             if (cb == NULL)  | 
230  | 0  |                 continue;  | 
231  | 0  |             Py_VISIT(cb->func);  | 
232  | 0  |             Py_VISIT(cb->args);  | 
233  | 0  |             Py_VISIT(cb->kwargs);  | 
234  | 0  |         }  | 
235  | 0  |     }  | 
236  | 0  |     return 0;  | 
237  | 0  | }  | 
238  |  |  | 
239  |  | static int  | 
240  |  | atexit_m_clear(PyObject *self)  | 
241  | 0  | { | 
242  | 0  |     atexitmodule_state *modstate;  | 
243  | 0  |     modstate = GET_ATEXIT_STATE(self);  | 
244  | 0  |     if (modstate != NULL) { | 
245  | 0  |         atexit_cleanup(modstate);  | 
246  | 0  |     }  | 
247  | 0  |     return 0;  | 
248  | 0  | }  | 
249  |  |  | 
250  |  | static void  | 
251  |  | atexit_free(PyObject *m)  | 
252  | 0  | { | 
253  | 0  |     atexitmodule_state *modstate;  | 
254  | 0  |     modstate = GET_ATEXIT_STATE(m);  | 
255  | 0  |     if (modstate != NULL) { | 
256  | 0  |         atexit_cleanup(modstate);  | 
257  | 0  |         PyMem_Free(modstate->atexit_callbacks);  | 
258  | 0  |     }  | 
259  | 0  | }  | 
260  |  |  | 
261  |  | PyDoc_STRVAR(atexit_unregister__doc__,  | 
262  |  | "unregister(func) -> None\n\  | 
263  |  | \n\  | 
264  |  | Unregister an exit function which was previously registered using\n\  | 
265  |  | atexit.register\n\  | 
266  |  | \n\  | 
267  |  |     func - function to be unregistered");  | 
268  |  |  | 
269  |  | static PyObject *  | 
270  |  | atexit_unregister(PyObject *self, PyObject *func)  | 
271  | 0  | { | 
272  | 0  |     atexitmodule_state *modstate;  | 
273  | 0  |     atexit_callback *cb;  | 
274  | 0  |     int i, eq;  | 
275  |  | 
  | 
276  | 0  |     modstate = GET_ATEXIT_STATE(self);  | 
277  |  | 
  | 
278  | 0  |     for (i = 0; i < modstate->ncallbacks; i++)  | 
279  | 0  |     { | 
280  | 0  |         cb = modstate->atexit_callbacks[i];  | 
281  | 0  |         if (cb == NULL)  | 
282  | 0  |             continue;  | 
283  |  |  | 
284  | 0  |         eq = PyObject_RichCompareBool(cb->func, func, Py_EQ);  | 
285  | 0  |         if (eq < 0)  | 
286  | 0  |             return NULL;  | 
287  | 0  |         if (eq)  | 
288  | 0  |             atexit_delete_cb(modstate, i);  | 
289  | 0  |     }  | 
290  | 0  |     Py_RETURN_NONE;  | 
291  | 0  | }  | 
292  |  |  | 
293  |  | static PyMethodDef atexit_methods[] = { | 
294  |  |     {"register", (PyCFunction)(void(*)(void)) atexit_register, METH_VARARGS|METH_KEYWORDS, | 
295  |  |         atexit_register__doc__},  | 
296  |  |     {"_clear", (PyCFunction) atexit_clear, METH_NOARGS, | 
297  |  |         atexit_clear__doc__},  | 
298  |  |     {"unregister", (PyCFunction) atexit_unregister, METH_O, | 
299  |  |         atexit_unregister__doc__},  | 
300  |  |     {"_run_exitfuncs", (PyCFunction) atexit_run_exitfuncs, METH_NOARGS, | 
301  |  |         atexit_run_exitfuncs__doc__},  | 
302  |  |     {"_ncallbacks", (PyCFunction) atexit_ncallbacks, METH_NOARGS, | 
303  |  |         atexit_ncallbacks__doc__},  | 
304  |  |     {NULL, NULL}        /* sentinel */ | 
305  |  | };  | 
306  |  |  | 
307  |  | /* ===================================================================== */  | 
308  |  | /* Initialization function. */  | 
309  |  |  | 
310  |  | PyDoc_STRVAR(atexit__doc__,  | 
311  |  | "allow programmer to define multiple exit functions to be executed\  | 
312  |  | upon normal program termination.\n\  | 
313  |  | \n\  | 
314  |  | Two public functions, register and unregister, are defined.\n\  | 
315  |  | ");  | 
316  |  |  | 
317  |  | static int  | 
318  | 1  | atexit_exec(PyObject *m) { | 
319  | 1  |     atexitmodule_state *modstate;  | 
320  |  |  | 
321  | 1  |     modstate = GET_ATEXIT_STATE(m);  | 
322  | 1  |     modstate->callback_len = 32;  | 
323  | 1  |     modstate->ncallbacks = 0;  | 
324  | 1  |     modstate->atexit_callbacks = PyMem_New(atexit_callback*,  | 
325  | 1  |                                            modstate->callback_len);  | 
326  | 1  |     if (modstate->atexit_callbacks == NULL)  | 
327  | 0  |         return -1;  | 
328  |  |  | 
329  | 1  |     _Py_PyAtExit(atexit_callfuncs, m);  | 
330  | 1  |     return 0;  | 
331  | 1  | }  | 
332  |  |  | 
333  |  | static PyModuleDef_Slot atexit_slots[] = { | 
334  |  |     {Py_mod_exec, atexit_exec}, | 
335  |  |     {0, NULL} | 
336  |  | };  | 
337  |  |  | 
338  |  | static struct PyModuleDef atexitmodule = { | 
339  |  |     PyModuleDef_HEAD_INIT,  | 
340  |  |     "atexit",  | 
341  |  |     atexit__doc__,  | 
342  |  |     sizeof(atexitmodule_state),  | 
343  |  |     atexit_methods,  | 
344  |  |     atexit_slots,  | 
345  |  |     atexit_m_traverse,  | 
346  |  |     atexit_m_clear,  | 
347  |  |     (freefunc)atexit_free  | 
348  |  | };  | 
349  |  |  | 
350  |  | PyMODINIT_FUNC  | 
351  |  | PyInit_atexit(void)  | 
352  | 1  | { | 
353  | 1  |     return PyModuleDef_Init(&atexitmodule);  | 
354  | 1  | }  |