@@ -1093,10 +1093,24 @@ struct _mem_work_chunk {
10931093};
10941094
10951095static void
1096- free_work_item (uintptr_t ptr )
1096+ free_work_item (uintptr_t ptr , delayed_dealloc_cb cb , void * state )
10971097{
10981098if (ptr & 0x01 ) {
1099- Py_DECREF ((PyObject * )(char * )(ptr - 1 ));
1099+ PyObject * obj = (PyObject * )(char * )(ptr - 1 );
1100+ #ifdef Py_GIL_DISABLED
1101+ if (cb == NULL ) {
1102+ assert (!_PyInterpreterState_GET ()-> stoptheworld .world_stopped );
1103+ Py_DECREF (obj );
1104+ return ;
1105+ }
1106+
1107+ Py_ssize_t refcount = _Py_ExplicitMergeRefcount (obj ,-1 );
1108+ if (refcount == 0 ) {
1109+ cb (obj ,state );
1110+ }
1111+ #else
1112+ Py_DECREF (obj );
1113+ #endif
11001114 }
11011115else {
11021116PyMem_Free ((void * )ptr );
@@ -1107,15 +1121,16 @@ static void
11071121free_delayed (uintptr_t ptr )
11081122{
11091123#ifndef Py_GIL_DISABLED
1110- free_work_item (ptr );
1124+ free_work_item (ptr , NULL , NULL );
11111125#else
11121126PyInterpreterState * interp = _PyInterpreterState_GET ();
11131127if (_PyInterpreterState_GetFinalizing (interp )!= NULL ||
11141128interp -> stoptheworld .world_stopped )
11151129 {
11161130// Free immediately during interpreter shutdown or if the world is
11171131// stopped.
1118- free_work_item (ptr );
1132+ assert (!interp -> stoptheworld .world_stopped || !(ptr & 0x01 ));
1133+ free_work_item (ptr ,NULL ,NULL );
11191134return ;
11201135 }
11211136
@@ -1142,7 +1157,8 @@ free_delayed(uintptr_t ptr)
11421157if (buf == NULL ) {
11431158// failed to allocate a buffer, free immediately
11441159_PyEval_StopTheWorld (tstate -> base .interp );
1145- free_work_item (ptr );
1160+ // TODO: Fix me
1161+ free_work_item (ptr ,NULL ,NULL );
11461162_PyEval_StartTheWorld (tstate -> base .interp );
11471163return ;
11481164 }
@@ -1185,7 +1201,7 @@ work_queue_first(struct llist_node *head)
11851201
11861202static void
11871203process_queue (struct llist_node * head ,struct _qsbr_thread_state * qsbr ,
1188- bool keep_empty )
1204+ bool keep_empty , delayed_dealloc_cb cb , void * state )
11891205{
11901206while (!llist_empty (head )) {
11911207struct _mem_work_chunk * buf = work_queue_first (head );
@@ -1196,7 +1212,7 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
11961212return ;
11971213 }
11981214
1199- free_work_item (item -> ptr );
1215+ free_work_item (item -> ptr , cb , state );
12001216buf -> rd_idx ++ ;
12011217 }
12021218
@@ -1214,15 +1230,16 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
12141230
12151231static void
12161232process_interp_queue (struct _Py_mem_interp_free_queue * queue ,
1217- struct _qsbr_thread_state * qsbr )
1233+ struct _qsbr_thread_state * qsbr ,delayed_dealloc_cb cb ,
1234+ void * state )
12181235{
12191236if (!_Py_atomic_load_int_relaxed (& queue -> has_work )) {
12201237return ;
12211238 }
12221239
12231240// Try to acquire the lock, but don't block if it's already held.
12241241if (_PyMutex_LockTimed (& queue -> mutex ,0 ,0 )== PY_LOCK_ACQUIRED ) {
1225- process_queue (& queue -> head ,qsbr , false);
1242+ process_queue (& queue -> head ,qsbr , false, cb , state );
12261243
12271244int more_work = !llist_empty (& queue -> head );
12281245_Py_atomic_store_int_relaxed (& queue -> has_work ,more_work );
@@ -1238,10 +1255,23 @@ _PyMem_ProcessDelayed(PyThreadState *tstate)
12381255_PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )tstate ;
12391256
12401257// Process thread-local work
1241- process_queue (& tstate_impl -> mem_free_queue ,tstate_impl -> qsbr , true);
1258+ process_queue (& tstate_impl -> mem_free_queue ,tstate_impl -> qsbr , true,NULL ,NULL );
1259+
1260+ // Process shared interpreter work
1261+ process_interp_queue (& interp -> mem_free_queue ,tstate_impl -> qsbr ,NULL ,NULL );
1262+ }
1263+
1264+ void
1265+ _PyMem_ProcessDelayedNoDealloc (PyThreadState * tstate ,delayed_dealloc_cb cb ,void * state )
1266+ {
1267+ PyInterpreterState * interp = tstate -> interp ;
1268+ _PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )tstate ;
1269+
1270+ // Process thread-local work
1271+ process_queue (& tstate_impl -> mem_free_queue ,tstate_impl -> qsbr , true,cb ,state );
12421272
12431273// Process shared interpreter work
1244- process_interp_queue (& interp -> mem_free_queue ,tstate_impl -> qsbr );
1274+ process_interp_queue (& interp -> mem_free_queue ,tstate_impl -> qsbr , cb , state );
12451275}
12461276
12471277void
@@ -1283,7 +1313,7 @@ _PyMem_FiniDelayed(PyInterpreterState *interp)
12831313// Free the remaining items immediately. There should be no other
12841314// threads accessing the memory at this point during shutdown.
12851315struct _mem_work_item * item = & buf -> array [buf -> rd_idx ];
1286- free_work_item (item -> ptr );
1316+ free_work_item (item -> ptr , NULL , NULL );
12871317buf -> rd_idx ++ ;
12881318 }
12891319