]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-116738: Make _suggestions module thread-safe (gh-140321)
authorAlper <alperyoney@fb.com>
Wed, 22 Oct 2025 00:14:48 +0000 (17:14 -0700)
committerGitHub <noreply@github.com>
Wed, 22 Oct 2025 00:14:48 +0000 (09:14 +0900)
Lib/test/test_free_threading/test_suggestions.py [new file with mode: 0755]
Misc/NEWS.d/next/Core_and_Builtins/2025-10-18-19-52-20.gh-issue-116738.NLJW0L.rst [new file with mode: 0644]
Modules/_suggestions.c
Modules/clinic/_suggestions.c.h

diff --git a/Lib/test/test_free_threading/test_suggestions.py b/Lib/test/test_free_threading/test_suggestions.py
new file mode 100755 (executable)
index 0000000..2c10a51
--- /dev/null
@@ -0,0 +1,24 @@
+import unittest
+
+from test.support import import_helper, threading_helper
+from test.support.threading_helper import run_concurrently
+
+suggestions = import_helper.import_module("_suggestions")
+
+NTHREADS = 10
+
+
+@threading_helper.requires_working_threading()
+class SuggestionsTests(unittest.TestCase):
+    def test_generate_suggestions(self):
+        candidates = [str(i) for i in range(100)]
+
+        def worker():
+            _ = suggestions._generate_suggestions(candidates, "42")
+            candidates.clear()
+
+        run_concurrently(worker_func=worker, nthreads=NTHREADS)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-10-18-19-52-20.gh-issue-116738.NLJW0L.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-10-18-19-52-20.gh-issue-116738.NLJW0L.rst
new file mode 100644 (file)
index 0000000..bf323b8
--- /dev/null
@@ -0,0 +1,2 @@
+Make _suggestions module thread-safe on the :term:`free threaded <free
+threading>` build.
index b8bc6db24772811fd1926ed5150a26def8872caf..fb588de78085fe3ec1b6898ca98be3d49c0bcc25 100644 (file)
@@ -8,6 +8,7 @@ module _suggestions
 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=e58d81fafad5637b]*/
 
 /*[clinic input]
+@critical_section candidates
 _suggestions._generate_suggestions
     candidates: object
     item: unicode
@@ -18,7 +19,7 @@ Returns the candidate in candidates that's closest to item
 static PyObject *
 _suggestions__generate_suggestions_impl(PyObject *module,
                                         PyObject *candidates, PyObject *item)
-/*[clinic end generated code: output=79be7b653ae5e7ca input=ba2a8dddc654e33a]*/
+/*[clinic end generated code: output=79be7b653ae5e7ca input=92861a6c9bd8f667]*/
 {
    // Check if dir is a list
     if (!PyList_CheckExact(candidates)) {
@@ -29,7 +30,7 @@ _suggestions__generate_suggestions_impl(PyObject *module,
     // Check if all elements in the list are Unicode
     Py_ssize_t size = PyList_Size(candidates);
     for (Py_ssize_t i = 0; i < size; ++i) {
-        PyObject *elem = PyList_GetItem(candidates, i);
+        PyObject *elem = PyList_GET_ITEM(candidates, i);
         if (!PyUnicode_Check(elem)) {
             PyErr_SetString(PyExc_TypeError, "all elements in 'candidates' must be strings");
             return NULL;
index 51484b13d5af89cf0457b7ad491cb0451d12f154..3b3ed5056ac8d025e4e6f8baf921ed0b2069c925 100644 (file)
@@ -2,6 +2,7 @@
 preserve
 [clinic start generated code]*/
 
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
 #include "pycore_modsupport.h"    // _PyArg_CheckPositional()
 
 PyDoc_STRVAR(_suggestions__generate_suggestions__doc__,
@@ -33,9 +34,11 @@ _suggestions__generate_suggestions(PyObject *module, PyObject *const *args, Py_s
         goto exit;
     }
     item = args[1];
+    Py_BEGIN_CRITICAL_SECTION(candidates);
     return_value = _suggestions__generate_suggestions_impl(module, candidates, item);
+    Py_END_CRITICAL_SECTION();
 
 exit:
     return return_value;
 }
-/*[clinic end generated code: output=1d8e963cdae30b13 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=1690dd15a464d19c input=a9049054013a1b77]*/