gh-101659: Add _Py_AtExit() (gh-103298)

The function is like Py_AtExit() but for a single interpreter.  This is a companion to the atexit module's register() function, taking a C callback instead of a Python one.

We also update the _xxinterpchannels module to use _Py_AtExit(), which is the motivating case.  (This is inspired by pain points felt while working on gh-101660.)
This commit is contained in:
Eric Snow 2023-04-05 18:42:02 -06:00 committed by GitHub
parent 4ec8dd10bd
commit 03089fdccc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 268 additions and 67 deletions

View file

@ -2937,23 +2937,23 @@ wait_for_thread_shutdown(PyThreadState *tstate)
Py_DECREF(threading);
}
#define NEXITFUNCS 32
int Py_AtExit(void (*func)(void))
{
if (_PyRuntime.nexitfuncs >= NEXITFUNCS)
if (_PyRuntime.atexit.ncallbacks >= NEXITFUNCS)
return -1;
_PyRuntime.exitfuncs[_PyRuntime.nexitfuncs++] = func;
_PyRuntime.atexit.callbacks[_PyRuntime.atexit.ncallbacks++] = func;
return 0;
}
static void
call_ll_exitfuncs(_PyRuntimeState *runtime)
{
while (runtime->nexitfuncs > 0) {
struct _atexit_runtime_state *state = &runtime->atexit;
while (state->ncallbacks > 0) {
/* pop last function from the list */
runtime->nexitfuncs--;
void (*exitfunc)(void) = runtime->exitfuncs[runtime->nexitfuncs];
runtime->exitfuncs[runtime->nexitfuncs] = NULL;
state->ncallbacks--;
atexit_callbackfunc exitfunc = state->callbacks[state->ncallbacks];
state->callbacks[state->ncallbacks] = NULL;
exitfunc();
}