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