blob: 9f6c80edd03ebd6b5694d40bd3c320d8c3bd9176 [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
11/* ===================================================================== */
12/* Callback machinery. */
13
14typedef struct {
15 PyObject *func;
16 PyObject *args;
17 PyObject *kwargs;
18} atexit_callback;
19
Neal Norwitz7d71fb82007-03-21 04:45:04 +000020static atexit_callback **atexit_callbacks;
21static int ncallbacks = 0;
22static int callback_len = 32;
Collin Winter670e6922007-03-21 02:57:17 +000023
24/* Installed into pythonrun.c's atexit mechanism */
25
26void
27atexit_callfuncs(void)
28{
29 PyObject *exc_type = NULL, *exc_value, *exc_tb, *r;
30 atexit_callback *cb;
31 int i;
32
33 if (ncallbacks == 0)
34 return;
35
Neal Norwitz7d71fb82007-03-21 04:45:04 +000036 for (i = ncallbacks - 1; i >= 0; i--)
Collin Winter670e6922007-03-21 02:57:17 +000037 {
38 cb = atexit_callbacks[i];
39 if (cb == NULL)
40 continue;
41
42 r = PyObject_Call(cb->func, cb->args, cb->kwargs);
43 Py_XDECREF(r);
44 if (r == NULL) {
Neal Norwitz7d71fb82007-03-21 04:45:04 +000045 /* Maintain the last exception, but don't leak if there are
46 multiple exceptions. */
Collin Winter670e6922007-03-21 02:57:17 +000047 if (exc_type) {
48 Py_DECREF(exc_type);
Neal Norwitz7d71fb82007-03-21 04:45:04 +000049 Py_XDECREF(exc_value);
50 Py_XDECREF(exc_tb);
Collin Winter670e6922007-03-21 02:57:17 +000051 }
52 PyErr_Fetch(&exc_type, &exc_value, &exc_tb);
53 if (!PyErr_ExceptionMatches(PyExc_SystemExit)) {
54 PySys_WriteStderr("Error in atexit._run_exitfuncs:\n");
55 PyErr_Display(exc_type, exc_value, exc_tb);
56 }
57 }
58 }
59
60 if (exc_type)
61 PyErr_Restore(exc_type, exc_value, exc_tb);
62}
63
64void
65atexit_delete_cb(int i)
66{
67 atexit_callback *cb = atexit_callbacks[i];
68 atexit_callbacks[i] = NULL;
69 Py_DECREF(cb->func);
70 Py_DECREF(cb->args);
71 Py_XDECREF(cb->kwargs);
72 PyMem_Free(cb);
73}
74
75/* ===================================================================== */
76/* Module methods. */
77
78PyDoc_STRVAR(atexit_register__doc__,
79"register(func, *args, **kwargs) -> func\n\
80\n\
81Register a function to be executed upon normal program termination\n\
82\n\
83 func - function to be called at exit\n\
84 args - optional arguments to pass to func\n\
85 kwargs - optional keyword arguments to pass to func\n\
86\n\
87 func is returned to facilitate usage as a decorator.");
88
89static PyObject *
90atexit_register(PyObject *self, PyObject *args, PyObject *kwargs)
91{
92 atexit_callback *new_callback;
93 PyObject *func = NULL;
94
95 if (ncallbacks >= callback_len) {
96 callback_len += 16;
Neal Norwitz7d71fb82007-03-21 04:45:04 +000097 /* XXX(nnorwitz): this leaks if realloc() fails. It also
98 doesn't verify realloc() returns a valid (non-NULL) pointer. */
Collin Winter670e6922007-03-21 02:57:17 +000099 atexit_callbacks = PyMem_Realloc(atexit_callbacks,
100 sizeof(atexit_callback*) * callback_len);
101
102 }
103
104 if (PyTuple_GET_SIZE(args) == 0) {
105 PyErr_SetString(PyExc_TypeError,
106 "register() takes at least 1 argument (0 given)");
107 return NULL;
108 }
109
110 func = PyTuple_GET_ITEM(args, 0);
111 if (!PyCallable_Check(func)) {
112 PyErr_SetString(PyExc_TypeError,
113 "the first argument must be callable");
114 return NULL;
115 }
116
117 new_callback = PyMem_Malloc(sizeof(atexit_callback));
118 if (new_callback == NULL)
119 return PyErr_NoMemory();
120
121 new_callback->args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args));
122 if (new_callback->args == NULL) {
123 PyMem_Free(new_callback);
124 return NULL;
125 }
126 new_callback->func = func;
127 new_callback->kwargs = kwargs;
128 Py_INCREF(func);
129 Py_XINCREF(kwargs);
130
131 atexit_callbacks[ncallbacks++] = new_callback;
132
133 Py_INCREF(func);
134 return func;
135}
136
137static PyObject *
138atexit_run_exitfuncs(PyObject *self)
139{
140 atexit_callfuncs();
141 if (PyErr_Occurred())
142 return NULL;
143 Py_RETURN_NONE;
144}
145
146static PyObject *
147atexit_clear(PyObject *self)
148{
149 atexit_callback *cb;
150 int i;
151
Neal Norwitz7d71fb82007-03-21 04:45:04 +0000152 for (i = 0; i < ncallbacks; i++)
Collin Winter670e6922007-03-21 02:57:17 +0000153 {
154 cb = atexit_callbacks[i];
155 if (cb == NULL)
156 continue;
157
158 atexit_delete_cb(i);
159 }
160 ncallbacks = 0;
161 Py_RETURN_NONE;
162}
163
164static PyObject *
165atexit_unregister(PyObject *self, PyObject *func)
166{
167 atexit_callback *cb;
168 int i, eq;
169
Neal Norwitz7d71fb82007-03-21 04:45:04 +0000170 for (i = 0; i < ncallbacks; i++)
Collin Winter670e6922007-03-21 02:57:17 +0000171 {
172 cb = atexit_callbacks[i];
173 if (cb == NULL)
174 continue;
175
176 eq = PyObject_RichCompareBool(cb->func, func, Py_EQ);
177 if (eq < 0)
178 return NULL;
179 if (eq)
180 atexit_delete_cb(i);
181 }
182 Py_RETURN_NONE;
183}
184
185static PyMethodDef atexit_methods[] = {
186 {"register", (PyCFunction) atexit_register, METH_VARARGS|METH_KEYWORDS,
187 atexit_register__doc__},
188 {"_clear", (PyCFunction) atexit_clear, METH_NOARGS,
189 NULL},
190 {"unregister", (PyCFunction) atexit_unregister, METH_O,
191 NULL},
192 {"_run_exitfuncs", (PyCFunction) atexit_run_exitfuncs, METH_NOARGS,
193 NULL},
194 {NULL, NULL} /* sentinel */
195};
196
197/* ===================================================================== */
198/* Initialization function. */
199
200PyDoc_STRVAR(atexit__doc__,
201"atexit.py - allow programmer to define multiple exit functions to be executed\
202upon normal program termination.\n\
203\n\
204One public function, register, is defined.\n\
205");
206
207PyMODINIT_FUNC
208initatexit(void)
209{
210 PyObject *m;
211
212 atexit_callbacks = PyMem_New(atexit_callback*, callback_len);
213 if (atexit_callbacks == NULL)
214 return;
215
216 m = Py_InitModule3("atexit", atexit_methods, atexit__doc__);
217 if (m == NULL)
218 return;
219
Neal Norwitz7d71fb82007-03-21 04:45:04 +0000220 /* XXX(nnorwitz): probably best to register a callback that will free
221 atexit_callbacks, otherwise valgrind will report memory leaks.
222 Need to call atexit_clear() first. */
Collin Winter670e6922007-03-21 02:57:17 +0000223 _Py_PyAtExit(atexit_callfuncs);
224}