@@ -957,7 +957,7 @@ _PyMem_Strdup(const char *str)
957957
958958// A pointer to be freed once the QSBR read sequence reaches qsbr_goal.
959959struct _mem_work_item {
960- void * ptr ;
960+ void * ptr ; // lowest bit tagged 1 for objects freed with PyObject_Free
961961 uint64_t qsbr_goal ;
962962};
963963
@@ -971,16 +971,26 @@ struct _mem_work_chunk {
971971 struct _mem_work_item array [WORK_ITEMS_PER_CHUNK ];
972972};
973973
974- void
975- _PyMem_FreeDelayed (void * ptr )
974+ void free_work_item (void * ptr )
975+ {
976+ if (((uintptr_t )ptr ) & 0x01 ) {
977+ PyObject_Free (((char * )ptr ) - 1 );
978+ }
979+ else {
980+ PyMem_Free (ptr );
981+ }
982+ }
983+
984+ static void
985+ free_delayed (void * ptr )
976986{
977987#ifndef Py_GIL_DISABLED
978- PyMem_Free (ptr );
988+ free_work_item (ptr );
979989#else
980990 if (_PyRuntime .stoptheworld .world_stopped ) {
981991 // Free immediately if the world is stopped, including during
982992 // interpreter shutdown.
983- PyMem_Free (ptr );
993+ free_work_item (ptr );
984994 return ;
985995 }
986996
@@ -1007,7 +1017,7 @@ _PyMem_FreeDelayed(void *ptr)
10071017 if (buf == NULL ) {
10081018 // failed to allocate a buffer, free immediately
10091019 _PyEval_StopTheWorld (tstate -> base .interp );
1010- PyMem_Free (ptr );
1020+ free_work_item (ptr );
10111021 _PyEval_StartTheWorld (tstate -> base .interp );
10121022 return ;
10131023 }
@@ -1024,6 +1034,20 @@ _PyMem_FreeDelayed(void *ptr)
10241034#endif
10251035}
10261036
1037+ void
1038+ _PyMem_FreeDelayed (void * ptr )
1039+ {
1040+ assert (!((uintptr_t )ptr & 0x01 ));
1041+ free_delayed (ptr );
1042+ }
1043+
1044+
1045+ void _PyObject_FreeDelayed (void * ptr )
1046+ {
1047+ assert (!((uintptr_t )ptr & 0x01 ));
1048+ free_delayed ((void * )(((uintptr_t )ptr )|0x01 ));
1049+ }
1050+
10271051static struct _mem_work_chunk *
10281052work_queue_first (struct llist_node * head )
10291053{
@@ -1043,7 +1067,7 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
10431067 return ;
10441068 }
10451069
1046- PyMem_Free (item -> ptr );
1070+ free_work_item (item -> ptr );
10471071 buf -> rd_idx ++ ;
10481072 }
10491073
@@ -1119,6 +1143,23 @@ _PyMem_AbandonDelayed(PyThreadState *tstate)
11191143 assert (llist_empty (queue )); // the thread's queue is now empty
11201144}
11211145
1146+ void
1147+ _PyMem_ProcessAllDelayed (PyInterpreterState * interp )
1148+ {
1149+ PyThreadState * tstate = PyInterpreterState_ThreadHead (interp );
1150+ while (tstate != NULL ) {
1151+ _PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )tstate ;
1152+
1153+ // Process thread-local work
1154+ process_queue (& tstate_impl -> mem_free_queue , tstate_impl -> qsbr , true);
1155+
1156+ tstate = PyThreadState_Next (tstate );
1157+ }
1158+
1159+ // Process shared interpreter work
1160+ process_interp_queue (& interp -> mem_free_queue , ((_PyThreadStateImpl * )_PyThreadState_GET ())-> qsbr );
1161+ }
1162+
11221163void
11231164_PyMem_FiniDelayed (PyInterpreterState * interp )
11241165{
@@ -1130,7 +1171,7 @@ _PyMem_FiniDelayed(PyInterpreterState *interp)
11301171 // Free the remaining items immediately. There should be no other
11311172 // threads accessing the memory at this point during shutdown.
11321173 struct _mem_work_item * item = & buf -> array [buf -> rd_idx ];
1133- PyMem_Free (item -> ptr );
1174+ free_work_item (item -> ptr );
11341175 buf -> rd_idx ++ ;
11351176 }
11361177
0 commit comments