Skip to content
Open
Prev Previous commit
Next Next commit
review comments
  • Loading branch information
eendebakpt committed Jun 1, 2025
commit d30ace8e7746d3f6c3ed3c8e3cf19999fab8ad03
2 changes: 2 additions & 0 deletions Lib/test/test_free_threading/test_threading_iter_locked.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import time
import unittest
from threading import Thread, Barrier, iter_locked
from test.support import threading_helper
Expand All @@ -15,6 +16,7 @@ def __iter__(self):

def __next__(self):
a = next(self.it)
time.sleep(0)
b = next(self.it)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add time.sleep(0) (or with small non-zero argument) or Event.wait() with a timeout to force or significantly increase the chance of concurrent access.

return a, b

Expand Down
9 changes: 7 additions & 2 deletions Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,7 @@ static PyType_Spec ThreadHandle_Type_spec = {
typedef struct {
PyObject_HEAD
PyObject *it;
PyMutex lock;
} iter_locked_object;

#define iter_locked_object_CAST(op) ((iter_locked_object *)(op))
Expand Down Expand Up @@ -774,6 +775,7 @@ _thread_iter_locked_impl(PyTypeObject *type, PyObject *iterable)
return NULL;
}
il->it = it;
il->lock = (PyMutex){0};

return (PyObject *)il;
}
Expand Down Expand Up @@ -804,14 +806,17 @@ iter_locked_next(PyObject *op)
iter_locked_object *lz = iter_locked_object_CAST(op);
PyObject *result = NULL;

Py_BEGIN_CRITICAL_SECTION(op); // lock on op or lz->it?
// we cannot use Py_BEGIN_CRITICAL_SECTION as it is not available in the normal build
PyMutex_Lock(&(lz->lock));

PyObject *it = lz->it;
result = PyIter_Next(it);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use PyIter_NextItem, PyIter_Next has a weird return value.

if (result == NULL) {
/* Note: StopIteration is already cleared by PyIter_Next() */
/* If PyErr_Occurred() we will also return NULL*/
}
Py_END_CRITICAL_SECTION();
PyMutex_Unlock(&(lz->lock));

return result;
}

Expand Down