summaryrefslogtreecommitdiffstats
path: root/Modules/_testcapimodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r--Modules/_testcapimodule.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 26f6869..8d86b53 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3353,6 +3353,53 @@ type_freeze(PyObject *module, PyObject *args)
Py_RETURN_NONE;
}
+struct atexit_data {
+ int called;
+ PyThreadState *tstate;
+ PyInterpreterState *interp;
+};
+
+static void
+atexit_callback(void *data)
+{
+ struct atexit_data *at_data = (struct atexit_data *)data;
+ // Ensure that the callback is from the same interpreter
+ assert(PyThreadState_Get() == at_data->tstate);
+ assert(PyInterpreterState_Get() == at_data->interp);
+ ++at_data->called;
+}
+
+static PyObject *
+test_atexit(PyObject *self, PyObject *Py_UNUSED(args))
+{
+ PyThreadState *oldts = PyThreadState_Swap(NULL);
+ PyThreadState *tstate = Py_NewInterpreter();
+
+ struct atexit_data data = {0};
+ data.tstate = PyThreadState_Get();
+ data.interp = PyInterpreterState_Get();
+
+ int amount = 10;
+ for (int i = 0; i < amount; ++i)
+ {
+ int res = PyUnstable_AtExit(tstate->interp, atexit_callback, (void *)&data);
+ if (res < 0) {
+ Py_EndInterpreter(tstate);
+ PyThreadState_Swap(oldts);
+ PyErr_SetString(PyExc_RuntimeError, "atexit callback failed");
+ return NULL;
+ }
+ }
+
+ Py_EndInterpreter(tstate);
+ PyThreadState_Swap(oldts);
+
+ if (data.called != amount) {
+ PyErr_SetString(PyExc_RuntimeError, "atexit callback not called");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
static PyMethodDef TestMethods[] = {
{"set_errno", set_errno, METH_VARARGS},
@@ -3495,6 +3542,7 @@ static PyMethodDef TestMethods[] = {
{"test_critical_sections", test_critical_sections, METH_NOARGS},
{"finalize_thread_hang", finalize_thread_hang, METH_O, NULL},
{"type_freeze", type_freeze, METH_VARARGS},
+ {"test_atexit", test_atexit, METH_NOARGS},
{NULL, NULL} /* sentinel */
};