blob: 64cd9a097b48858abf0c0cd12c064ac7f1d43422 [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) */
12static PyObject *atexit_clear(PyObject*);
13
Collin Winter670e6922007-03-21 02:57:17 +000014/* ===================================================================== */
15/* Callback machinery. */
16
17typedef struct {
18 PyObject *func;
19 PyObject *args;
20 PyObject *kwargs;
21} atexit_callback;
22
Neal Norwitz7d71fb82007-03-21 04:45:04 +000023static atexit_callback **atexit_callbacks;
24static int ncallbacks = 0;
25static int callback_len = 32;
Collin Winter670e6922007-03-21 02:57:17 +000026
27/* Installed into pythonrun.c's atexit mechanism */
28
29void
30atexit_callfuncs(void)
31{
32 PyObject *exc_type = NULL, *exc_value, *exc_tb, *r;
33 atexit_callback *cb;
34 int i;
35
36 if (ncallbacks == 0)
37 return;
38
Neal Norwitz7d71fb82007-03-21 04:45:04 +000039 for (i = ncallbacks - 1; i >= 0; i--)
Collin Winter670e6922007-03-21 02:57:17 +000040 {
41 cb = atexit_callbacks[i];
42 if (cb == NULL)
43 continue;
44
45 r = PyObject_Call(cb->func, cb->args, cb->kwargs);
46 Py_XDECREF(r);
47 if (r == NULL) {
Neal Norwitz7d71fb82007-03-21 04:45:04 +000048 /* Maintain the last exception, but don't leak if there are
49 multiple exceptions. */
Collin Winter670e6922007-03-21 02:57:17 +000050 if (exc_type) {
51 Py_DECREF(exc_type);
Neal Norwitz7d71fb82007-03-21 04:45:04 +000052 Py_XDECREF(exc_value);
53 Py_XDECREF(exc_tb);
Collin Winter670e6922007-03-21 02:57:17 +000054 }
55 PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
56 if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {
57 PySys_WriteStderr("Error in atexit._run_exitfuncs:\n");
58 PyErr_Display(exc_type, exc_value, exc_tb);
59 }
60 }
61 }
62
63 if (exc_type)
64 PyErr_Restore(exc_type, exc_value, exc_tb);
65}
66
67void
68atexit_delete_cb(int i)
69{
70 atexit_callback *cb = atexit_callbacks[i];
71 atexit_callbacks[i] = NULL;
72 Py_DECREF(cb->func);
73 Py_DECREF(cb->args);
74 Py_XDECREF(cb->kwargs);
75 PyMem_Free(cb);
76}
77
Collin Winter3e81ec82007-03-23 22:46:49 +000078void
79atexit_cleanup(void)
80{
81 PyObject *r = atexit_clear(NULL);
82 Py_DECREF(r);
83}
84
Collin Winter670e6922007-03-21 02:57:17 +000085/* ===================================================================== */
86/* Module methods. */
87
88PyDoc_STRVAR(atexit_register__doc__,
89"register(func, *args, **kwargs) -> func\n\
90\n\
91Register a function to be executed upon normal program termination\n\
92\n\
93 func - function to be called at exit\n\
94 args - optional arguments to pass to func\n\
95 kwargs - optional keyword arguments to pass to func\n\
96\n\
97 func is returned to facilitate usage as a decorator.");
98
99static PyObject *
100atexit_register(PyObject *self, PyObject *args, PyObject *kwargs)
101{
102 atexit_callback *new_callback;
103 PyObject *func = NULL;
104
105 if (ncallbacks >= callback_len) {
Collin Winter3e81ec82007-03-23 22:46:49 +0000106 atexit_callback **r;
Collin Winter670e6922007-03-21 02:57:17 +0000107 callback_len += 16;
Collin Winter3e81ec82007-03-23 22:46:49 +0000108 r = (atexit_callback**)PyMem_Realloc(atexit_callbacks,
109 sizeof(atexit_callback*) * callback_len);
110 if (r == NULL)
111 return PyErr_NoMemory();
112 atexit_callbacks = r;
Collin Winter670e6922007-03-21 02:57:17 +0000113 }
114
115 if (PyTuple_GET_SIZE(args) == 0) {
116 PyErr_SetString(PyExc_TypeError,
117 "register() takes at least 1 argument (0 given)");
118 return NULL;
119 }
120
121 func = PyTuple_GET_ITEM(args, 0);
122 if (!PyCallable_Check(func)) {
123 PyErr_SetString(PyExc_TypeError,
124 "the first argument must be callable");
125 return NULL;
126 }
127
128 new_callback = PyMem_Malloc(sizeof(atexit_callback));
129 if (new_callback == NULL)
130 return PyErr_NoMemory();
131
132 new_callback->args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
133 if (new_callback->args == NULL) {
134 PyMem_Free(new_callback);
135 return NULL;
136 }
137 new_callback->func = func;
138 new_callback->kwargs = kwargs;
139 Py_INCREF(func);
140 Py_XINCREF(kwargs);
141
142 atexit_callbacks[ncallbacks++] = new_callback;
143
144 Py_INCREF(func);
145 return func;
146}
147
148static PyObject *
149atexit_run_exitfuncs(PyObject *self)
150{
151 atexit_callfuncs();
152 if (PyErr_Occurred())
153 return NULL;
154 Py_RETURN_NONE;
155}
156
157static PyObject *
158atexit_clear(PyObject *self)
159{
160 atexit_callback *cb;
161 int i;
162
Neal Norwitz7d71fb82007-03-21 04:45:04 +0000163 for (i = 0; i < ncallbacks; i++)
Collin Winter670e6922007-03-21 02:57:17 +0000164 {
165 cb = atexit_callbacks[i];
166 if (cb == NULL)
167 continue;
168
169 atexit_delete_cb(i);
170 }
171 ncallbacks = 0;
172 Py_RETURN_NONE;
173}
174
175static PyObject *
176atexit_unregister(PyObject *self, PyObject *func)
177{
178 atexit_callback *cb;
179 int i, eq;
180
Neal Norwitz7d71fb82007-03-21 04:45:04 +0000181 for (i = 0; i < ncallbacks; i++)
Collin Winter670e6922007-03-21 02:57:17 +0000182 {
183 cb = atexit_callbacks[i];
184 if (cb == NULL)
185 continue;
186
187 eq = PyObject_RichCompareBool(cb->func, func, Py_EQ);
188 if (eq < 0)
189 return NULL;
190 if (eq)
191 atexit_delete_cb(i);
192 }
193 Py_RETURN_NONE;
194}
195
196static PyMethodDef atexit_methods[] = {
197 {"register", (PyCFunction) atexit_register, METH_VARARGS|METH_KEYWORDS,
198 atexit_register__doc__},
199 {"_clear", (PyCFunction) atexit_clear, METH_NOARGS,
200 NULL},
201 {"unregister", (PyCFunction) atexit_unregister, METH_O,
202 NULL},
203 {"_run_exitfuncs", (PyCFunction) atexit_run_exitfuncs, METH_NOARGS,
204 NULL},
205 {NULL, NULL} /* sentinel */
206};
207
208/* ===================================================================== */
209/* Initialization function. */
210
211PyDoc_STRVAR(atexit__doc__,
212"atexit.py - allow programmer to define multiple exit functions to be executed\
213upon normal program termination.\n\
214\n\
215One public function, register, is defined.\n\
216");
217
218PyMODINIT_FUNC
219initatexit(void)
220{
221 PyObject *m;
222
223 atexit_callbacks = PyMem_New(atexit_callback*, callback_len);
224 if (atexit_callbacks == NULL)
225 return;
226
227 m = Py_InitModule3("atexit", atexit_methods, atexit__doc__);
228 if (m == NULL)
229 return;
230
Collin Winter670e6922007-03-21 02:57:17 +0000231 _Py_PyAtExit(atexit_callfuncs);
Collin Winter3e81ec82007-03-23 22:46:49 +0000232 /* Register a callback that will free
233 atexit_callbacks, otherwise valgrind will report memory leaks. */
234 Py_AtExit(atexit_cleanup);
Collin Winter670e6922007-03-21 02:57:17 +0000235}