blob: 1382133e0a82606ecd90cba5c8ea24b5e1314cde [file] [log] [blame]
Collin Winter670e6922007-03-21 02:57:17 +00001/*
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
Collin Winter3e81ec82007-03-23 22:46:49 +000011/* Forward declaration (for atexit_cleanup) */
Christian Heimes9c94ba42008-10-30 21:34:02 +000012static PyObject *atexit_clear(PyObject*, PyObject*);
Skip Montanaro711552b2008-09-23 00:52:29 +000013/* Forward declaration (for atexit_callfuncs) */
Christian Heimes9c94ba42008-10-30 21:34:02 +000014static void atexit_cleanup(PyObject*);
15/* Forward declaration of module object */
16static struct PyModuleDef atexitmodule;
Collin Winter3e81ec82007-03-23 22:46:49 +000017
Collin Winter670e6922007-03-21 02:57:17 +000018/* ===================================================================== */
19/* Callback machinery. */
20
21typedef struct {
22 PyObject *func;
23 PyObject *args;
24 PyObject *kwargs;
25} atexit_callback;
26
Christian Heimes9c94ba42008-10-30 21:34:02 +000027typedef 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
Collin Winter670e6922007-03-21 02:57:17 +000035
36/* Installed into pythonrun.c's atexit mechanism */
37
Skip Montanaro711552b2008-09-23 00:52:29 +000038static void
Collin Winter670e6922007-03-21 02:57:17 +000039atexit_callfuncs(void)
40{
41 PyObject *exc_type = NULL, *exc_value, *exc_tb, *r;
42 atexit_callback *cb;
Christian Heimes9c94ba42008-10-30 21:34:02 +000043 PyObject *module;
44 atexitmodule_state *modstate;
Collin Winter670e6922007-03-21 02:57:17 +000045 int i;
Christian Heimes9c94ba42008-10-30 21:34:02 +000046
47 module = PyState_FindModule(&atexitmodule);
48 if (module == NULL)
Collin Winter670e6922007-03-21 02:57:17 +000049 return;
Christian Heimes9c94ba42008-10-30 21:34:02 +000050 modstate = GET_ATEXIT_STATE(module);
51
52 if (modstate->ncallbacks == 0)
53 return;
54
55
56 for (i = modstate->ncallbacks - 1; i >= 0; i--)
Collin Winter670e6922007-03-21 02:57:17 +000057 {
Christian Heimes9c94ba42008-10-30 21:34:02 +000058 cb = modstate->atexit_callbacks[i];
Collin Winter670e6922007-03-21 02:57:17 +000059 if (cb == NULL)
60 continue;
61
62 r = PyObject_Call(cb->func, cb->args, cb->kwargs);
63 Py_XDECREF(r);
64 if (r == NULL) {
Neal Norwitz7d71fb82007-03-21 04:45:04 +000065 /* Maintain the last exception, but don't leak if there are
66 multiple exceptions. */
Collin Winter670e6922007-03-21 02:57:17 +000067 if (exc_type) {
68 Py_DECREF(exc_type);
Neal Norwitz7d71fb82007-03-21 04:45:04 +000069 Py_XDECREF(exc_value);
70 Py_XDECREF(exc_tb);
Collin Winter670e6922007-03-21 02:57:17 +000071 }
72 PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
73 if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {
74 PySys_WriteStderr("Error in atexit._run_exitfuncs:\n");
75 PyErr_Display(exc_type, exc_value, exc_tb);
76 }
77 }
78 }
Christian Heimes9c94ba42008-10-30 21:34:02 +000079
80 atexit_cleanup(module);
Skip Montanaro711552b2008-09-23 00:52:29 +000081
Collin Winter670e6922007-03-21 02:57:17 +000082 if (exc_type)
83 PyErr_Restore(exc_type, exc_value, exc_tb);
84}
85
Skip Montanaro711552b2008-09-23 00:52:29 +000086static void
Christian Heimes9c94ba42008-10-30 21:34:02 +000087atexit_delete_cb(PyObject *self, int i)
Collin Winter670e6922007-03-21 02:57:17 +000088{
Christian Heimes9c94ba42008-10-30 21:34:02 +000089 atexitmodule_state *modstate;
90 atexit_callback *cb;
91
92 modstate = GET_ATEXIT_STATE(self);
93 cb = modstate->atexit_callbacks[i];
94 modstate->atexit_callbacks[i] = NULL;
Collin Winter670e6922007-03-21 02:57:17 +000095 Py_DECREF(cb->func);
96 Py_DECREF(cb->args);
97 Py_XDECREF(cb->kwargs);
Christian Heimes9c94ba42008-10-30 21:34:02 +000098 PyMem_Free(cb);
Collin Winter670e6922007-03-21 02:57:17 +000099}
100
Skip Montanaro711552b2008-09-23 00:52:29 +0000101static void
Christian Heimes9c94ba42008-10-30 21:34:02 +0000102atexit_cleanup(PyObject *self)
Collin Winter3e81ec82007-03-23 22:46:49 +0000103{
Christian Heimes9c94ba42008-10-30 21:34:02 +0000104 PyObject *r = atexit_clear(self, NULL);
Collin Winter3e81ec82007-03-23 22:46:49 +0000105 Py_DECREF(r);
106}
107
Collin Winter670e6922007-03-21 02:57:17 +0000108/* ===================================================================== */
109/* Module methods. */
110
111PyDoc_STRVAR(atexit_register__doc__,
112"register(func, *args, **kwargs) -> func\n\
113\n\
114Register a function to be executed upon normal program termination\n\
115\n\
116 func - function to be called at exit\n\
117 args - optional arguments to pass to func\n\
118 kwargs - optional keyword arguments to pass to func\n\
119\n\
120 func is returned to facilitate usage as a decorator.");
121
122static PyObject *
123atexit_register(PyObject *self, PyObject *args, PyObject *kwargs)
124{
Christian Heimes9c94ba42008-10-30 21:34:02 +0000125 atexitmodule_state *modstate;
Collin Winter670e6922007-03-21 02:57:17 +0000126 atexit_callback *new_callback;
127 PyObject *func = NULL;
Christian Heimes9c94ba42008-10-30 21:34:02 +0000128
129 modstate = GET_ATEXIT_STATE(self);
130
131 if (modstate->ncallbacks >= modstate->callback_len) {
Collin Winter3e81ec82007-03-23 22:46:49 +0000132 atexit_callback **r;
Christian Heimes9c94ba42008-10-30 21:34:02 +0000133 modstate->callback_len += 16;
134 r = (atexit_callback**)PyMem_Realloc(modstate->atexit_callbacks,
135 sizeof(atexit_callback*) * modstate->callback_len);
Collin Winter3e81ec82007-03-23 22:46:49 +0000136 if (r == NULL)
137 return PyErr_NoMemory();
Christian Heimes9c94ba42008-10-30 21:34:02 +0000138 modstate->atexit_callbacks = r;
Collin Winter670e6922007-03-21 02:57:17 +0000139 }
Christian Heimes9c94ba42008-10-30 21:34:02 +0000140
Collin Winter670e6922007-03-21 02:57:17 +0000141 if (PyTuple_GET_SIZE(args) == 0) {
142 PyErr_SetString(PyExc_TypeError,
143 "register() takes at least 1 argument (0 given)");
144 return NULL;
145 }
Christian Heimes9c94ba42008-10-30 21:34:02 +0000146
Collin Winter670e6922007-03-21 02:57:17 +0000147 func = PyTuple_GET_ITEM(args, 0);
148 if (!PyCallable_Check(func)) {
149 PyErr_SetString(PyExc_TypeError,
150 "the first argument must be callable");
151 return NULL;
152 }
Christian Heimes9c94ba42008-10-30 21:34:02 +0000153
Collin Winter670e6922007-03-21 02:57:17 +0000154 new_callback = PyMem_Malloc(sizeof(atexit_callback));
155 if (new_callback == NULL)
156 return PyErr_NoMemory();
157
158 new_callback->args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
159 if (new_callback->args == NULL) {
160 PyMem_Free(new_callback);
161 return NULL;
162 }
163 new_callback->func = func;
164 new_callback->kwargs = kwargs;
165 Py_INCREF(func);
166 Py_XINCREF(kwargs);
Christian Heimes9c94ba42008-10-30 21:34:02 +0000167
168 modstate->atexit_callbacks[modstate->ncallbacks++] = new_callback;
169
Collin Winter670e6922007-03-21 02:57:17 +0000170 Py_INCREF(func);
171 return func;
172}
173
Skip Montanaro28a181c2007-08-06 20:59:28 +0000174PyDoc_STRVAR(atexit_run_exitfuncs__doc__,
175"_run_exitfuncs() -> None\n\
176\n\
177Run all registered exit functions.");
178
Collin Winter670e6922007-03-21 02:57:17 +0000179static PyObject *
Christian Heimes9c94ba42008-10-30 21:34:02 +0000180atexit_run_exitfuncs(PyObject *self, PyObject *unused)
Collin Winter670e6922007-03-21 02:57:17 +0000181{
182 atexit_callfuncs();
183 if (PyErr_Occurred())
184 return NULL;
185 Py_RETURN_NONE;
186}
187
Skip Montanaro28a181c2007-08-06 20:59:28 +0000188PyDoc_STRVAR(atexit_clear__doc__,
189"_clear() -> None\n\
190\n\
191Clear the list of previously registered exit functions.");
192
Collin Winter670e6922007-03-21 02:57:17 +0000193static PyObject *
Christian Heimes9c94ba42008-10-30 21:34:02 +0000194atexit_clear(PyObject *self, PyObject *unused)
Collin Winter670e6922007-03-21 02:57:17 +0000195{
Christian Heimes9c94ba42008-10-30 21:34:02 +0000196 atexitmodule_state *modstate;
Collin Winter670e6922007-03-21 02:57:17 +0000197 atexit_callback *cb;
198 int i;
Christian Heimes9c94ba42008-10-30 21:34:02 +0000199
200 modstate = GET_ATEXIT_STATE(self);
201
202 for (i = 0; i < modstate->ncallbacks; i++) {
203 cb = modstate->atexit_callbacks[i];
Collin Winter670e6922007-03-21 02:57:17 +0000204 if (cb == NULL)
205 continue;
Christian Heimes9c94ba42008-10-30 21:34:02 +0000206
207 atexit_delete_cb(self, i);
Collin Winter670e6922007-03-21 02:57:17 +0000208 }
Christian Heimes9c94ba42008-10-30 21:34:02 +0000209 modstate->ncallbacks = 0;
Collin Winter670e6922007-03-21 02:57:17 +0000210 Py_RETURN_NONE;
211}
212
Skip Montanaro28a181c2007-08-06 20:59:28 +0000213PyDoc_STRVAR(atexit_unregister__doc__,
214"unregister(func) -> None\n\
215\n\
216Unregister a exit function which was previously registered using\n\
217atexit.register\n\
218\n\
219 func - function to be unregistered");
220
Collin Winter670e6922007-03-21 02:57:17 +0000221static PyObject *
222atexit_unregister(PyObject *self, PyObject *func)
223{
Christian Heimes9c94ba42008-10-30 21:34:02 +0000224 atexitmodule_state *modstate;
Collin Winter670e6922007-03-21 02:57:17 +0000225 atexit_callback *cb;
226 int i, eq;
Christian Heimes9c94ba42008-10-30 21:34:02 +0000227
228 modstate = GET_ATEXIT_STATE(self);
229
230 for (i = 0; i < modstate->ncallbacks; i++)
Collin Winter670e6922007-03-21 02:57:17 +0000231 {
Christian Heimes9c94ba42008-10-30 21:34:02 +0000232 cb = modstate->atexit_callbacks[i];
Collin Winter670e6922007-03-21 02:57:17 +0000233 if (cb == NULL)
234 continue;
Christian Heimes9c94ba42008-10-30 21:34:02 +0000235
Collin Winter670e6922007-03-21 02:57:17 +0000236 eq = PyObject_RichCompareBool(cb->func, func, Py_EQ);
237 if (eq < 0)
238 return NULL;
239 if (eq)
Christian Heimes9c94ba42008-10-30 21:34:02 +0000240 atexit_delete_cb(self, i);
Collin Winter670e6922007-03-21 02:57:17 +0000241 }
242 Py_RETURN_NONE;
243}
244
245static PyMethodDef atexit_methods[] = {
246 {"register", (PyCFunction) atexit_register, METH_VARARGS|METH_KEYWORDS,
247 atexit_register__doc__},
248 {"_clear", (PyCFunction) atexit_clear, METH_NOARGS,
Skip Montanaro28a181c2007-08-06 20:59:28 +0000249 atexit_clear__doc__},
Collin Winter670e6922007-03-21 02:57:17 +0000250 {"unregister", (PyCFunction) atexit_unregister, METH_O,
Skip Montanaro28a181c2007-08-06 20:59:28 +0000251 atexit_unregister__doc__},
Collin Winter670e6922007-03-21 02:57:17 +0000252 {"_run_exitfuncs", (PyCFunction) atexit_run_exitfuncs, METH_NOARGS,
Skip Montanaro28a181c2007-08-06 20:59:28 +0000253 atexit_run_exitfuncs__doc__},
Collin Winter670e6922007-03-21 02:57:17 +0000254 {NULL, NULL} /* sentinel */
255};
256
257/* ===================================================================== */
258/* Initialization function. */
259
260PyDoc_STRVAR(atexit__doc__,
Skip Montanaro28a181c2007-08-06 20:59:28 +0000261"allow programmer to define multiple exit functions to be executed\
Collin Winter670e6922007-03-21 02:57:17 +0000262upon normal program termination.\n\
263\n\
Skip Montanaro28a181c2007-08-06 20:59:28 +0000264Two public functions, register and unregister, are defined.\n\
Collin Winter670e6922007-03-21 02:57:17 +0000265");
266
Martin v. Löwis1a214512008-06-11 05:26:20 +0000267
268static struct PyModuleDef atexitmodule = {
269 PyModuleDef_HEAD_INIT,
270 "atexit",
271 atexit__doc__,
Christian Heimes9c94ba42008-10-30 21:34:02 +0000272 sizeof(atexitmodule_state),
Martin v. Löwis1a214512008-06-11 05:26:20 +0000273 atexit_methods,
274 NULL,
275 NULL,
276 NULL,
277 NULL
278};
279
Collin Winter670e6922007-03-21 02:57:17 +0000280PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000281PyInit_atexit(void)
Collin Winter670e6922007-03-21 02:57:17 +0000282{
283 PyObject *m;
Christian Heimes9c94ba42008-10-30 21:34:02 +0000284 atexitmodule_state *modstate;
Collin Winter670e6922007-03-21 02:57:17 +0000285
Martin v. Löwis1a214512008-06-11 05:26:20 +0000286 m = PyModule_Create(&atexitmodule);
Collin Winter670e6922007-03-21 02:57:17 +0000287 if (m == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +0000288 return NULL;
Christian Heimes9c94ba42008-10-30 21:34:02 +0000289
290 modstate = GET_ATEXIT_STATE(m);
291 modstate->callback_len = 32;
292 modstate->ncallbacks = 0;
293 modstate->atexit_callbacks = PyMem_New(atexit_callback*,
294 modstate->callback_len);
295 if (modstate->atexit_callbacks == NULL)
296 return NULL;
297
Collin Winter670e6922007-03-21 02:57:17 +0000298 _Py_PyAtExit(atexit_callfuncs);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000299 return m;
Collin Winter670e6922007-03-21 02:57:17 +0000300}