@@ -1093,10 +1093,20 @@ struct _mem_work_chunk {
1093
1093
};
1094
1094
1095
1095
static void
1096
- free_work_item (uintptr_t ptr )
1096
+ free_work_item (uintptr_t ptr , delayed_dealloc_cb cb , void * state )
1097
1097
{
1098
1098
if (ptr & 0x01 ) {
1099
- Py_DECREF ((PyObject * )(char * )(ptr - 1 ));
1099
+ PyObject * obj = (PyObject * )(char * )(ptr - 1 );
1100
+ if (cb == NULL ) {
1101
+ assert (!_PyInterpreterState_GET ()-> stoptheworld .world_stopped );
1102
+ Py_DECREF (obj );
1103
+ return ;
1104
+ }
1105
+
1106
+ Py_ssize_t refcount = _Py_ExplicitMergeRefcount (obj , -1 );
1107
+ if (refcount == 0 ) {
1108
+ cb (obj , state );
1109
+ }
1100
1110
}
1101
1111
else {
1102
1112
PyMem_Free ((void * )ptr );
@@ -1107,15 +1117,16 @@ static void
1107
1117
free_delayed (uintptr_t ptr )
1108
1118
{
1109
1119
#ifndef Py_GIL_DISABLED
1110
- free_work_item (ptr );
1120
+ free_work_item (ptr , NULL , NULL );
1111
1121
#else
1112
1122
PyInterpreterState * interp = _PyInterpreterState_GET ();
1113
1123
if (_PyInterpreterState_GetFinalizing (interp ) != NULL ||
1114
1124
interp -> stoptheworld .world_stopped )
1115
1125
{
1116
1126
// Free immediately during interpreter shutdown or if the world is
1117
1127
// stopped.
1118
- free_work_item (ptr );
1128
+ assert (!interp -> stoptheworld .world_stopped || !(ptr & 0x01 ));
1129
+ free_work_item (ptr , NULL , NULL );
1119
1130
return ;
1120
1131
}
1121
1132
@@ -1142,7 +1153,8 @@ free_delayed(uintptr_t ptr)
1142
1153
if (buf == NULL ) {
1143
1154
// failed to allocate a buffer, free immediately
1144
1155
_PyEval_StopTheWorld (tstate -> base .interp );
1145
- free_work_item (ptr );
1156
+ // TODO: Fix me
1157
+ free_work_item (ptr , NULL , NULL );
1146
1158
_PyEval_StartTheWorld (tstate -> base .interp );
1147
1159
return ;
1148
1160
}
@@ -1185,7 +1197,7 @@ work_queue_first(struct llist_node *head)
1185
1197
1186
1198
static void
1187
1199
process_queue (struct llist_node * head , struct _qsbr_thread_state * qsbr ,
1188
- bool keep_empty )
1200
+ bool keep_empty , delayed_dealloc_cb cb , void * state )
1189
1201
{
1190
1202
while (!llist_empty (head )) {
1191
1203
struct _mem_work_chunk * buf = work_queue_first (head );
@@ -1196,7 +1208,7 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
1196
1208
return ;
1197
1209
}
1198
1210
1199
- free_work_item (item -> ptr );
1211
+ free_work_item (item -> ptr , cb , state );
1200
1212
buf -> rd_idx ++ ;
1201
1213
}
1202
1214
@@ -1214,15 +1226,16 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
1214
1226
1215
1227
static void
1216
1228
process_interp_queue (struct _Py_mem_interp_free_queue * queue ,
1217
- struct _qsbr_thread_state * qsbr )
1229
+ struct _qsbr_thread_state * qsbr , delayed_dealloc_cb cb ,
1230
+ void * state )
1218
1231
{
1219
1232
if (!_Py_atomic_load_int_relaxed (& queue -> has_work )) {
1220
1233
return ;
1221
1234
}
1222
1235
1223
1236
// Try to acquire the lock, but don't block if it's already held.
1224
1237
if (_PyMutex_LockTimed (& queue -> mutex , 0 , 0 ) == PY_LOCK_ACQUIRED ) {
1225
- process_queue (& queue -> head , qsbr , false);
1238
+ process_queue (& queue -> head , qsbr , false, cb , state );
1226
1239
1227
1240
int more_work = !llist_empty (& queue -> head );
1228
1241
_Py_atomic_store_int_relaxed (& queue -> has_work , more_work );
@@ -1238,10 +1251,23 @@ _PyMem_ProcessDelayed(PyThreadState *tstate)
1238
1251
_PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )tstate ;
1239
1252
1240
1253
// Process thread-local work
1241
- process_queue (& tstate_impl -> mem_free_queue , tstate_impl -> qsbr , true);
1254
+ process_queue (& tstate_impl -> mem_free_queue , tstate_impl -> qsbr , true, NULL , NULL );
1255
+
1256
+ // Process shared interpreter work
1257
+ process_interp_queue (& interp -> mem_free_queue , tstate_impl -> qsbr , NULL , NULL );
1258
+ }
1259
+
1260
+ void
1261
+ _PyMem_ProcessDelayedNoDealloc (PyThreadState * tstate , delayed_dealloc_cb cb , void * state )
1262
+ {
1263
+ PyInterpreterState * interp = tstate -> interp ;
1264
+ _PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )tstate ;
1265
+
1266
+ // Process thread-local work
1267
+ process_queue (& tstate_impl -> mem_free_queue , tstate_impl -> qsbr , true, cb , state );
1242
1268
1243
1269
// Process shared interpreter work
1244
- process_interp_queue (& interp -> mem_free_queue , tstate_impl -> qsbr );
1270
+ process_interp_queue (& interp -> mem_free_queue , tstate_impl -> qsbr , cb , state );
1245
1271
}
1246
1272
1247
1273
void
@@ -1283,7 +1309,7 @@ _PyMem_FiniDelayed(PyInterpreterState *interp)
1283
1309
// Free the remaining items immediately. There should be no other
1284
1310
// threads accessing the memory at this point during shutdown.
1285
1311
struct _mem_work_item * item = & buf -> array [buf -> rd_idx ];
1286
- free_work_item (item -> ptr );
1312
+ free_work_item (item -> ptr , NULL , NULL );
1287
1313
buf -> rd_idx ++ ;
1288
1314
}
1289
1315
0 commit comments