@@ -1093,10 +1093,24 @@ 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
+ #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
1100
1114
}
1101
1115
else {
1102
1116
PyMem_Free ((void * )ptr );
@@ -1107,15 +1121,16 @@ static void
1107
1121
free_delayed (uintptr_t ptr )
1108
1122
{
1109
1123
#ifndef Py_GIL_DISABLED
1110
- free_work_item (ptr );
1124
+ free_work_item (ptr , NULL , NULL );
1111
1125
#else
1112
1126
PyInterpreterState * interp = _PyInterpreterState_GET ();
1113
1127
if (_PyInterpreterState_GetFinalizing (interp ) != NULL ||
1114
1128
interp -> stoptheworld .world_stopped )
1115
1129
{
1116
1130
// Free immediately during interpreter shutdown or if the world is
1117
1131
// stopped.
1118
- free_work_item (ptr );
1132
+ assert (!interp -> stoptheworld .world_stopped || !(ptr & 0x01 ));
1133
+ free_work_item (ptr , NULL , NULL );
1119
1134
return ;
1120
1135
}
1121
1136
@@ -1142,7 +1157,8 @@ free_delayed(uintptr_t ptr)
1142
1157
if (buf == NULL ) {
1143
1158
// failed to allocate a buffer, free immediately
1144
1159
_PyEval_StopTheWorld (tstate -> base .interp );
1145
- free_work_item (ptr );
1160
+ // TODO: Fix me
1161
+ free_work_item (ptr , NULL , NULL );
1146
1162
_PyEval_StartTheWorld (tstate -> base .interp );
1147
1163
return ;
1148
1164
}
@@ -1185,7 +1201,7 @@ work_queue_first(struct llist_node *head)
1185
1201
1186
1202
static void
1187
1203
process_queue (struct llist_node * head , struct _qsbr_thread_state * qsbr ,
1188
- bool keep_empty )
1204
+ bool keep_empty , delayed_dealloc_cb cb , void * state )
1189
1205
{
1190
1206
while (!llist_empty (head )) {
1191
1207
struct _mem_work_chunk * buf = work_queue_first (head );
@@ -1196,7 +1212,7 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
1196
1212
return ;
1197
1213
}
1198
1214
1199
- free_work_item (item -> ptr );
1215
+ free_work_item (item -> ptr , cb , state );
1200
1216
buf -> rd_idx ++ ;
1201
1217
}
1202
1218
@@ -1214,15 +1230,16 @@ process_queue(struct llist_node *head, struct _qsbr_thread_state *qsbr,
1214
1230
1215
1231
static void
1216
1232
process_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 )
1218
1235
{
1219
1236
if (!_Py_atomic_load_int_relaxed (& queue -> has_work )) {
1220
1237
return ;
1221
1238
}
1222
1239
1223
1240
// Try to acquire the lock, but don't block if it's already held.
1224
1241
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 );
1226
1243
1227
1244
int more_work = !llist_empty (& queue -> head );
1228
1245
_Py_atomic_store_int_relaxed (& queue -> has_work , more_work );
@@ -1238,10 +1255,23 @@ _PyMem_ProcessDelayed(PyThreadState *tstate)
1238
1255
_PyThreadStateImpl * tstate_impl = (_PyThreadStateImpl * )tstate ;
1239
1256
1240
1257
// 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 );
1242
1272
1243
1273
// 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 );
1245
1275
}
1246
1276
1247
1277
void
@@ -1283,7 +1313,7 @@ _PyMem_FiniDelayed(PyInterpreterState *interp)
1283
1313
// Free the remaining items immediately. There should be no other
1284
1314
// threads accessing the memory at this point during shutdown.
1285
1315
struct _mem_work_item * item = & buf -> array [buf -> rd_idx ];
1286
- free_work_item (item -> ptr );
1316
+ free_work_item (item -> ptr , NULL , NULL );
1287
1317
buf -> rd_idx ++ ;
1288
1318
}
1289
1319
0 commit comments