blob: 5b073cbc01151be2abec158acc98a901c261ab6a [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
Skip Montanaro28a181c2007-08-06 20:59:28 +0000148PyDoc_STRVAR(atexit_run_exitfuncs__doc__,
149"_run_exitfuncs() -> None\n\
150\n\
151Run all registered exit functions.");
152
Collin Winter670e6922007-03-21 02:57:17 +0000153static PyObject *
154atexit_run_exitfuncs(PyObject *self)
155{
156 atexit_callfuncs();
157 if (PyErr_Occurred())
158 return NULL;
159 Py_RETURN_NONE;
160}
161
Skip Montanaro28a181c2007-08-06 20:59:28 +0000162PyDoc_STRVAR(atexit_clear__doc__,
163"_clear() -> None\n\
164\n\
165Clear the list of previously registered exit functions.");
166
Collin Winter670e6922007-03-21 02:57:17 +0000167static PyObject *
168atexit_clear(PyObject *self)
169{
170 atexit_callback *cb;
171 int i;
172
Neal Norwitz7d71fb82007-03-21 04:45:04 +0000173 for (i = 0; i < ncallbacks; i++)
Collin Winter670e6922007-03-21 02:57:17 +0000174 {
175 cb = atexit_callbacks[i];
176 if (cb == NULL)
177 continue;
178
179 atexit_delete_cb(i);
180 }
181 ncallbacks = 0;
182 Py_RETURN_NONE;
183}
184
Skip Montanaro28a181c2007-08-06 20:59:28 +0000185PyDoc_STRVAR(atexit_unregister__doc__,
186"unregister(func) -> None\n\
187\n\
188Unregister a exit function which was previously registered using\n\
189atexit.register\n\
190\n\
191 func - function to be unregistered");
192
Collin Winter670e6922007-03-21 02:57:17 +0000193static PyObject *
194atexit_unregister(PyObject *self, PyObject *func)
195{
196 atexit_callback *cb;
197 int i, eq;
198
Neal Norwitz7d71fb82007-03-21 04:45:04 +0000199 for (i = 0; i < ncallbacks; i++)
Collin Winter670e6922007-03-21 02:57:17 +0000200 {
201 cb = atexit_callbacks[i];
202 if (cb == NULL)
203 continue;
204
205 eq = PyObject_RichCompareBool(cb->func, func, Py_EQ);
206 if (eq < 0)
207 return NULL;
208 if (eq)
209 atexit_delete_cb(i);
210 }
211 Py_RETURN_NONE;
212}
213
214static PyMethodDef atexit_methods[] = {
215 {"register", (PyCFunction) atexit_register, METH_VARARGS|METH_KEYWORDS,
216 atexit_register__doc__},
217 {"_clear", (PyCFunction) atexit_clear, METH_NOARGS,
Skip Montanaro28a181c2007-08-06 20:59:28 +0000218 atexit_clear__doc__},
Collin Winter670e6922007-03-21 02:57:17 +0000219 {"unregister", (PyCFunction) atexit_unregister, METH_O,
Skip Montanaro28a181c2007-08-06 20:59:28 +0000220 atexit_unregister__doc__},
Collin Winter670e6922007-03-21 02:57:17 +0000221 {"_run_exitfuncs", (PyCFunction) atexit_run_exitfuncs, METH_NOARGS,
Skip Montanaro28a181c2007-08-06 20:59:28 +0000222 atexit_run_exitfuncs__doc__},
Collin Winter670e6922007-03-21 02:57:17 +0000223 {NULL, NULL} /* sentinel */
224};
225
226/* ===================================================================== */
227/* Initialization function. */
228
229PyDoc_STRVAR(atexit__doc__,
Skip Montanaro28a181c2007-08-06 20:59:28 +0000230"allow programmer to define multiple exit functions to be executed\
Collin Winter670e6922007-03-21 02:57:17 +0000231upon normal program termination.\n\
232\n\
Skip Montanaro28a181c2007-08-06 20:59:28 +0000233Two public functions, register and unregister, are defined.\n\
Collin Winter670e6922007-03-21 02:57:17 +0000234");
235
Martin v. Löwis1a214512008-06-11 05:26:20 +0000236
237static struct PyModuleDef atexitmodule = {
238 PyModuleDef_HEAD_INIT,
239 "atexit",
240 atexit__doc__,
241 -1,
242 atexit_methods,
243 NULL,
244 NULL,
245 NULL,
246 NULL
247};
248
Collin Winter670e6922007-03-21 02:57:17 +0000249PyMODINIT_FUNC
Martin v. Löwis1a214512008-06-11 05:26:20 +0000250PyInit_atexit(void)
Collin Winter670e6922007-03-21 02:57:17 +0000251{
252 PyObject *m;
253
254 atexit_callbacks = PyMem_New(atexit_callback*, callback_len);
255 if (atexit_callbacks == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +0000256 return NULL;
Collin Winter670e6922007-03-21 02:57:17 +0000257
Martin v. Löwis1a214512008-06-11 05:26:20 +0000258 m = PyModule_Create(&atexitmodule);
Collin Winter670e6922007-03-21 02:57:17 +0000259 if (m == NULL)
Martin v. Löwis1a214512008-06-11 05:26:20 +0000260 return NULL;
Collin Winter670e6922007-03-21 02:57:17 +0000261
Collin Winter670e6922007-03-21 02:57:17 +0000262 _Py_PyAtExit(atexit_callfuncs);
Collin Winter3e81ec82007-03-23 22:46:49 +0000263 /* Register a callback that will free
264 atexit_callbacks, otherwise valgrind will report memory leaks. */
265 Py_AtExit(atexit_cleanup);
Martin v. Löwis1a214512008-06-11 05:26:20 +0000266 return m;
Collin Winter670e6922007-03-21 02:57:17 +0000267}