@@ -3353,6 +3353,53 @@ type_freeze(PyObject *module, PyObject *args)
3353
3353
Py_RETURN_NONE ;
3354
3354
}
3355
3355
3356
+ struct atexit_data {
3357
+ int called ;
3358
+ PyThreadState * tstate ;
3359
+ PyInterpreterState * interp ;
3360
+ };
3361
+
3362
+ static void
3363
+ atexit_callback (void * data )
3364
+ {
3365
+ struct atexit_data * at_data = (struct atexit_data * )data ;
3366
+ // Ensure that the callback is from the same interpreter
3367
+ assert (PyThreadState_Get () == at_data -> tstate );
3368
+ assert (PyInterpreterState_Get () == at_data -> interp );
3369
+ ++ at_data -> called ;
3370
+ }
3371
+
3372
+ static PyObject *
3373
+ test_atexit (PyObject * self , PyObject * Py_UNUSED (args ))
3374
+ {
3375
+ PyThreadState * oldts = PyThreadState_Swap (NULL );
3376
+ PyThreadState * tstate = Py_NewInterpreter ();
3377
+
3378
+ struct atexit_data data = {0 };
3379
+ data .tstate = PyThreadState_Get ();
3380
+ data .interp = PyInterpreterState_Get ();
3381
+
3382
+ int amount = 10 ;
3383
+ for (int i = 0 ; i < amount ; ++ i )
3384
+ {
3385
+ int res = PyUnstable_AtExit (tstate -> interp , atexit_callback , (void * )& data );
3386
+ if (res < 0 ) {
3387
+ Py_EndInterpreter (tstate );
3388
+ PyThreadState_Swap (oldts );
3389
+ PyErr_SetString (PyExc_RuntimeError , "atexit callback failed" );
3390
+ return NULL ;
3391
+ }
3392
+ }
3393
+
3394
+ Py_EndInterpreter (tstate );
3395
+ PyThreadState_Swap (oldts );
3396
+
3397
+ if (data .called != amount ) {
3398
+ PyErr_SetString (PyExc_RuntimeError , "atexit callback not called" );
3399
+ return NULL ;
3400
+ }
3401
+ Py_RETURN_NONE ;
3402
+ }
3356
3403
3357
3404
static PyMethodDef TestMethods [] = {
3358
3405
{"set_errno" , set_errno , METH_VARARGS },
@@ -3495,6 +3542,7 @@ static PyMethodDef TestMethods[] = {
3495
3542
{"test_critical_sections" , test_critical_sections , METH_NOARGS },
3496
3543
{"finalize_thread_hang" , finalize_thread_hang , METH_O , NULL },
3497
3544
{"type_freeze" , type_freeze , METH_VARARGS },
3545
+ {"test_atexit" , test_atexit , METH_NOARGS },
3498
3546
{NULL , NULL } /* sentinel */
3499
3547
};
3500
3548
0 commit comments