1/* 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#include "pycore_initconfig.h" // _PyStatus_NO_MEMORY 11#include "pycore_interp.h" // PyInterpreterState.atexit 12#include "pycore_pystate.h" // _PyInterpreterState_GET 13 14/* ===================================================================== */ 15/* Callback machinery. */ 16 17static inline struct atexit_state* 18get_atexit_state(void) 19{ 20 PyInterpreterState *interp = _PyInterpreterState_GET(); 21 return &interp->atexit; 22} 23 24 25static void 26atexit_delete_cb(struct atexit_state *state, int i) 27{ 28 atexit_callback *cb = state->callbacks[i]; 29 state->callbacks[i] = NULL; 30 31 Py_DECREF(cb->func); 32 Py_DECREF(cb->args); 33 Py_XDECREF(cb->kwargs); 34 PyMem_Free(cb); 35} 36 37 38/* Clear all callbacks without calling them */ 39static void 40atexit_cleanup(struct atexit_state *state) 41{ 42 atexit_callback *cb; 43 for (int i = 0; i < state->ncallbacks; i++) { 44 cb = state->callbacks[i]; 45 if (cb == NULL) 46 continue; 47 48 atexit_delete_cb(state, i); 49 } 50 state->ncallbacks = 0; 51} 52 53 54PyStatus 55_PyAtExit_Init(PyInterpreterState *interp) 56{ 57 struct atexit_state *state = &interp->atexit; 58 // _PyAtExit_Init() must only be called once 59 assert(state->callbacks == NULL); 60 61 state->callback_len = 32; 62 state->ncallbacks = 0; 63 state->callbacks = PyMem_New(atexit_callback*, state->callback_len); 64 if (state->callbacks == NULL) { 65 return _PyStatus_NO_MEMORY(); 66 } 67 return _PyStatus_OK(); 68} 69 70 71void 72_PyAtExit_Fini(PyInterpreterState *interp) 73{ 74 struct atexit_state *state = &interp->atexit; 75 atexit_cleanup(state); 76 PyMem_Free(state->callbacks); 77 state->callbacks = NULL; 78} 79 80 81static void 82atexit_callfuncs(struct atexit_state *state) 83{ 84 assert(!PyErr_Occurred()); 85 86 if (state->ncallbacks == 0) { 87 return; 88 } 89 90 for (int i = state->ncallbacks - 1; i >= 0; i--) { 91 atexit_callback *cb = state->callbacks[i]; 92 if (cb == NULL) { 93 continue; 94 } 95 96 // bpo-46025: Increment the refcount of cb->func as the call itself may unregister it 97 PyObject* the_func = Py_NewRef(cb->func); 98 PyObject *res = PyObject_Call(cb->func, cb->args, cb->kwargs); 99 if (res == NULL) { 100 _PyErr_WriteUnraisableMsg("in atexit callback", the_func); 101 } 102 else { 103 Py_DECREF(res); 104 } 105 Py_DECREF(the_func); 106 } 107 108 atexit_cleanup(state); 109 110 assert(!PyErr_Occurred()); 111} 112 113 114void 115_PyAtExit_Call(PyInterpreterState *interp) 116{ 117 struct atexit_state *state = &interp->atexit; 118 atexit_callfuncs(state); 119} 120 121 122/* ===================================================================== */ 123/* Module methods. */ 124 125 126PyDoc_STRVAR(atexit_register__doc__, 127"register(func, *args, **kwargs) -> func\n\ 128\n\ 129Register a function to be executed upon normal program termination\n\ 130\n\ 131 func - function to be called at exit\n\ 132 args - optional arguments to pass to func\n\ 133 kwargs - optional keyword arguments to pass to func\n\ 134\n\ 135 func is returned to facilitate usage as a decorator."); 136 137static PyObject * 138atexit_register(PyObject *module, PyObject *args, PyObject *kwargs) 139{ 140 if (PyTuple_GET_SIZE(args) == 0) { 141 PyErr_SetString(PyExc_TypeError, 142 "register() takes at least 1 argument (0 given)"); 143 return NULL; 144 } 145 146 PyObject *func = PyTuple_GET_ITEM(args, 0); 147 if (!PyCallable_Check(func)) { 148 PyErr_SetString(PyExc_TypeError, 149 "the first argument must be callable"); 150 return NULL; 151 } 152 153 struct atexit_state *state = get_atexit_state(); 154 if (state->ncallbacks >= state->callback_len) { 155 atexit_callback **r; 156 state->callback_len += 16; 157 size_t size = sizeof(atexit_callback*) * (size_t)state->callback_len; 158 r = (atexit_callback**)PyMem_Realloc(state->callbacks, size); 159 if (r == NULL) { 160 return PyErr_NoMemory(); 161 } 162 state->callbacks = r; 163 } 164 165 atexit_callback *callback = PyMem_Malloc(sizeof(atexit_callback)); 166 if (callback == NULL) { 167 return PyErr_NoMemory(); 168 } 169 170 callback->args = PyTuple_GetSlice(args, 1, PyTuple_GET_SIZE(args)); 171 if (callback->args == NULL) { 172 PyMem_Free(callback); 173 return NULL; 174 } 175 callback->func = Py_NewRef(func); 176 callback->kwargs = Py_XNewRef(kwargs); 177 178 state->callbacks[state->ncallbacks++] = callback; 179 180 return Py_NewRef(func); 181} 182 183PyDoc_STRVAR(atexit_run_exitfuncs__doc__, 184"_run_exitfuncs() -> None\n\ 185\n\ 186Run all registered exit functions.\n\ 187\n\ 188If a callback raises an exception, it is logged with sys.unraisablehook."); 189 190static PyObject * 191atexit_run_exitfuncs(PyObject *module, PyObject *unused) 192{ 193 struct atexit_state *state = get_atexit_state(); 194 atexit_callfuncs(state); 195 Py_RETURN_NONE; 196} 197 198PyDoc_STRVAR(atexit_clear__doc__, 199"_clear() -> None\n\ 200\n\ 201Clear the list of previously registered exit functions."); 202 203static PyObject * 204atexit_clear(PyObject *module, PyObject *unused) 205{ 206 atexit_cleanup(get_atexit_state()); 207 Py_RETURN_NONE; 208} 209 210PyDoc_STRVAR(atexit_ncallbacks__doc__, 211"_ncallbacks() -> int\n\ 212\n\ 213Return the number of registered exit functions."); 214 215static PyObject * 216atexit_ncallbacks(PyObject *module, PyObject *unused) 217{ 218 struct atexit_state *state = get_atexit_state(); 219 return PyLong_FromSsize_t(state->ncallbacks); 220} 221 222PyDoc_STRVAR(atexit_unregister__doc__, 223"unregister(func) -> None\n\ 224\n\ 225Unregister an exit function which was previously registered using\n\ 226atexit.register\n\ 227\n\ 228 func - function to be unregistered"); 229 230static PyObject * 231atexit_unregister(PyObject *module, PyObject *func) 232{ 233 struct atexit_state *state = get_atexit_state(); 234 for (int i = 0; i < state->ncallbacks; i++) 235 { 236 atexit_callback *cb = state->callbacks[i]; 237 if (cb == NULL) { 238 continue; 239 } 240 241 int eq = PyObject_RichCompareBool(cb->func, func, Py_EQ); 242 if (eq < 0) { 243 return NULL; 244 } 245 if (eq) { 246 atexit_delete_cb(state, i); 247 } 248 } 249 Py_RETURN_NONE; 250} 251 252 253static PyMethodDef atexit_methods[] = { 254 {"register", _PyCFunction_CAST(atexit_register), METH_VARARGS|METH_KEYWORDS, 255 atexit_register__doc__}, 256 {"_clear", (PyCFunction) atexit_clear, METH_NOARGS, 257 atexit_clear__doc__}, 258 {"unregister", (PyCFunction) atexit_unregister, METH_O, 259 atexit_unregister__doc__}, 260 {"_run_exitfuncs", (PyCFunction) atexit_run_exitfuncs, METH_NOARGS, 261 atexit_run_exitfuncs__doc__}, 262 {"_ncallbacks", (PyCFunction) atexit_ncallbacks, METH_NOARGS, 263 atexit_ncallbacks__doc__}, 264 {NULL, NULL} /* sentinel */ 265}; 266 267 268/* ===================================================================== */ 269/* Initialization function. */ 270 271PyDoc_STRVAR(atexit__doc__, 272"allow programmer to define multiple exit functions to be executed\n\ 273upon normal program termination.\n\ 274\n\ 275Two public functions, register and unregister, are defined.\n\ 276"); 277 278static struct PyModuleDef atexitmodule = { 279 PyModuleDef_HEAD_INIT, 280 .m_name = "atexit", 281 .m_doc = atexit__doc__, 282 .m_size = 0, 283 .m_methods = atexit_methods, 284}; 285 286PyMODINIT_FUNC 287PyInit_atexit(void) 288{ 289 return PyModuleDef_Init(&atexitmodule); 290} 291