ยปCore Development>Code coverage>Modules/atexitmodule.c

Python code coverage for Modules/atexitmodule.c

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