File tree Expand file tree Collapse file tree 1 file changed +24
-1
lines changed
Expand file tree Collapse file tree 1 file changed +24
-1
lines changed Original file line number Diff line number Diff line change @@ -245,6 +245,15 @@ _Py_ClearExecutorDeletionList(PyInterpreterState *interp)
245245 ts = PyThreadState_Next (ts );
246246 HEAD_UNLOCK (runtime );
247247 }
248+
249+ /* Create a list to collect executors that need to be freed.
250+ * This avoids calling _PyExecutor_Free while holding the lock,
251+ * which could trigger destructors and cause deadlock. */
252+ PyObject * to_free = PyList_New (0 );
253+ if (to_free == NULL ) {
254+ goto error ;
255+ }
256+
248257 EXECUTOR_LIST_LOCK (interp );
249258 _PyExecutorObject * * prev_to_next_ptr = & interp -> executor_deletion_list_head ;
250259 _PyExecutorObject * exec = * prev_to_next_ptr ;
@@ -256,12 +265,26 @@ _Py_ClearExecutorDeletionList(PyInterpreterState *interp)
256265 }
257266 else {
258267 * prev_to_next_ptr = exec -> vm_data .links .next ;
259- _PyExecutor_Free (exec );
268+ if (PyList_Append (to_free , (PyObject * )exec )) {
269+ EXECUTOR_LIST_UNLOCK (interp );
270+ goto error ;
271+ }
260272 }
261273 exec = * prev_to_next_ptr ;
262274 }
263275 interp -> executor_deletion_list_remaining_capacity = EXECUTOR_DELETE_LIST_MAX ;
264276 EXECUTOR_LIST_UNLOCK (interp );
277+
278+ for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (to_free ); i ++ ) {
279+ _PyExecutorObject * exec = (_PyExecutorObject * )PyList_GET_ITEM (to_free , i );
280+ _PyExecutor_Free (exec );
281+ }
282+ Py_DECREF (to_free );
283+ return ;
284+
285+ error :
286+ PyErr_Clear ();
287+ Py_XDECREF (to_free );
265288}
266289
267290static void
You can’t perform that action at this time.
0 commit comments