]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-123471: Make `itertools.zip_longest` safe in the FT build (#146033)
authorPieter Eendebak <pieter.eendebak@gmail.com>
Fri, 27 Mar 2026 14:01:49 +0000 (15:01 +0100)
committerGitHub <noreply@github.com>
Fri, 27 Mar 2026 14:01:49 +0000 (19:31 +0530)
Lib/test/test_free_threading/test_itertools.py
Misc/NEWS.d/next/Library/2026-03-17-19-51-05.gh-issue-123471.oY4UR5.rst [new file with mode: 0644]
Modules/itertoolsmodule.c

index 20135dd3165acf8edeba78d974b3db699bee6faf..670d4ca8835e0d22e4cf1f80beef227df119f69c 100644 (file)
@@ -1,5 +1,5 @@
 import unittest
-from itertools import accumulate, batched, chain, combinations_with_replacement, cycle, permutations
+from itertools import accumulate, batched, chain, combinations_with_replacement, cycle, permutations, zip_longest
 from test.support import threading_helper
 
 
@@ -62,6 +62,13 @@ class ItertoolsThreading(unittest.TestCase):
             it = permutations(tuple(range(4)), 2)
             threading_helper.run_concurrently(work_iterator, nthreads=6, args=[it])
 
+    @threading_helper.reap_threads
+    def test_zip_longest(self):
+        number_of_iterations = 10
+        for _ in range(number_of_iterations):
+            it = zip_longest(list(range(4)), list(range(8)), fillvalue=0)
+            threading_helper.run_concurrently(work_iterator, nthreads=10, args=[it])
+
 
 if __name__ == "__main__":
     unittest.main()
diff --git a/Misc/NEWS.d/next/Library/2026-03-17-19-51-05.gh-issue-123471.oY4UR5.rst b/Misc/NEWS.d/next/Library/2026-03-17-19-51-05.gh-issue-123471.oY4UR5.rst
new file mode 100644 (file)
index 0000000..8d2e1b9
--- /dev/null
@@ -0,0 +1 @@
+Make concurrent iteration over :class:`itertools.zip_longest` safe under free-threading.
index 48f1d1c7fde17bd615081bc4b6966e3b5c6ecb23..cf49724b8861c25fcf6bd3cf4a360b8adc8ade0e 100644 (file)
@@ -3876,7 +3876,7 @@ zip_longest_traverse(PyObject *op, visitproc visit, void *arg)
 }
 
 static PyObject *
-zip_longest_next(PyObject *op)
+zip_longest_next_lock_held(PyObject *op)
 {
     ziplongestobject *lz = ziplongestobject_CAST(op);
     Py_ssize_t i;
@@ -3947,6 +3947,16 @@ zip_longest_next(PyObject *op)
     return result;
 }
 
+static PyObject *
+zip_longest_next(PyObject *op)
+{
+    PyObject *result;
+    Py_BEGIN_CRITICAL_SECTION(op);
+    result = zip_longest_next_lock_held(op);
+    Py_END_CRITICAL_SECTION()
+    return result;
+}
+
 PyDoc_STRVAR(zip_longest_doc,
 "zip_longest(*iterables, fillvalue=None)\n\
 --\n\