@@ -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{
10981098    if  (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    }
11011115    else  {
11021116        PyMem_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 
11121126    PyInterpreterState  * interp  =  _PyInterpreterState_GET ();
11131127    if  (_PyInterpreterState_GetFinalizing (interp ) !=  NULL  || 
11141128        interp -> 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 );
11191134        return ;
11201135    }
11211136
@@ -1142,7 +1157,8 @@ free_delayed(uintptr_t ptr)
11421157    if  (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 );
11471163        return ;
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{
11901206    while  (!llist_empty (head )) {
11911207        struct  _mem_work_chunk  * buf  =  work_queue_first (head );
@@ -1196,7 +1212,7 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
11961212                return ;
11971213            }
11981214
1199-             free_work_item (item -> ptr );
1215+             free_work_item (item -> ptr ,  cb ,  state );
12001216            buf -> 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{
12191236    if  (!_Py_atomic_load_int_relaxed (& queue -> has_work )) {
12201237        return ;
12211238    }
12221239
12231240    // Try to acquire the lock, but don't block if it's already held. 
12241241    if  (_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
12271244        int  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. 
12851315            struct  _mem_work_item  * item  =  & buf -> array [buf -> rd_idx ];
1286-             free_work_item (item -> ptr );
1316+             free_work_item (item -> ptr ,  NULL ,  NULL );
12871317            buf -> rd_idx ++ ;
12881318        }
12891319
0 commit comments