Skip to content

Commit 946ee51

Browse files
committed
use recursive lock
1 parent bb98c52 commit 946ee51

File tree

2 files changed

+34
-5
lines changed

2 files changed

+34
-5
lines changed

Lib/test/test_threading.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,5 +2457,35 @@ def test_iter_locked(self):
24572457
for arg in [1, None, True, sys]:
24582458
self.assertRaises(TypeError, threading.iter_locked, arg)
24592459

2460+
def test_iter_locked_recursive_generator(self):
2461+
def g():
2462+
yield next(it)
2463+
2464+
it = threading.iter_locked(g())
2465+
with self.assertRaises(ValueError):
2466+
next(it)
2467+
2468+
def test_iter_locked_recursive_iterator(self):
2469+
class evil_it:
2470+
def __init__(self):
2471+
self.it = iter(range(100))
2472+
self.it2 = None
2473+
2474+
def __iter__(self):
2475+
return self
2476+
2477+
def __next__(self):
2478+
if self.it2 is not None:
2479+
it2, self.it2 = self.it2, None
2480+
return next(it2), next(it2)
2481+
return next(self.it)
2482+
2483+
a = evil_it()
2484+
il = threading.iter_locked(a)
2485+
assert next(il) == 0
2486+
a.it2 = il
2487+
assert next(il) == (1, 2)
2488+
2489+
24602490
if __name__ == "__main__":
24612491
unittest.main()

Modules/_threadmodule.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ static PyType_Spec ThreadHandle_Type_spec = {
759759
typedef struct {
760760
PyObject_HEAD
761761
PyObject *it;
762-
PyMutex lock;
762+
_PyRecursiveMutex lock;
763763
} iter_locked_object;
764764

765765
#define iter_locked_object_CAST(op) ((iter_locked_object *)(op))
@@ -787,7 +787,7 @@ _thread_iter_locked_impl(PyTypeObject *type, PyObject *iterable)
787787
return NULL;
788788
}
789789
il->it = it;
790-
il->lock = (PyMutex){0};
790+
il->lock = (_PyRecursiveMutex){0};
791791

792792
return (PyObject *)il;
793793
}
@@ -818,15 +818,14 @@ iter_locked_next(PyObject *op)
818818
iter_locked_object *lz = iter_locked_object_CAST(op);
819819
PyObject *result = NULL;
820820

821-
// we cannot use Py_BEGIN_CRITICAL_SECTION as it is not available in the normal build
822-
PyMutex_Lock(&(lz->lock));
821+
_PyRecursiveMutex_Lock(&(lz->lock));
823822

824823
int v = PyIter_NextItem(lz->it, &result);
825824
if (v == -1) {
826825
/* Note: StopIteration is already cleared by PyIter_Next() */
827826
/* If PyErr_Occurred() we will also return NULL*/
828827
}
829-
PyMutex_Unlock(&(lz->lock));
828+
_PyRecursiveMutex_Unlock(&(lz->lock));
830829

831830
return result;
832831
}

0 commit comments

Comments
 (0)