https://github.com/python/cpython/commit/65893c6f9c69562526d24fe8265119feeea54cbf
commit: 65893c6f9c69562526d24fe8265119feeea54cbf
branch: main
author: Alper <alperyo...@fb.com>
committer: mpage <mp...@cs.stanford.edu>
date: 2025-07-21T09:24:42-07:00
summary:

gh-116738: Make syslog module thread-safe (#136760)

Make the setlogmask() function in the syslog module thread-safe. These changes 
are relevant for scenarios where the GIL is disabled or when using 
subinterpreters.

files:
A Lib/test/test_free_threading/test_syslog.py
A 
Misc/NEWS.d/next/Core_and_Builtins/2025-07-18-08-43-35.gh-issue-116738.i0HWtP.rst
M Modules/syslogmodule.c

diff --git a/Lib/test/test_free_threading/test_syslog.py 
b/Lib/test/test_free_threading/test_syslog.py
new file mode 100644
index 00000000000000..b374a98b96e6de
--- /dev/null
+++ b/Lib/test/test_free_threading/test_syslog.py
@@ -0,0 +1,44 @@
+import unittest
+import threading
+
+from test.support import import_helper, threading_helper
+from test.support.threading_helper import run_concurrently
+
+syslog = import_helper.import_module("syslog")
+
+NTHREADS = 32
+
+# Similar to Lib/test/test_syslog.py, this test's purpose is to verify that
+# the code neither crashes nor leaks.
+
+
+@threading_helper.requires_working_threading()
+class TestSyslog(unittest.TestCase):
+    def test_racing_syslog(self):
+        def worker():
+            """
+            The syslog module provides the following functions:
+            openlog(), syslog(), closelog(), and setlogmask().
+            """
+            thread_id = threading.get_ident()
+            syslog.openlog(f"thread-id: {thread_id}")
+            try:
+                for _ in range(5):
+                    syslog.syslog("logline")
+                    syslog.setlogmask(syslog.LOG_MASK(syslog.LOG_INFO))
+                    syslog.syslog(syslog.LOG_INFO, "logline LOG_INFO")
+                    syslog.setlogmask(syslog.LOG_MASK(syslog.LOG_ERR))
+                    syslog.syslog(syslog.LOG_ERR, "logline LOG_ERR")
+                    syslog.setlogmask(syslog.LOG_UPTO(syslog.LOG_DEBUG))
+            finally:
+                syslog.closelog()
+
+        # Run the worker concurrently to exercise all these syslog functions
+        run_concurrently(
+            worker_func=worker,
+            nthreads=NTHREADS,
+        )
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-18-08-43-35.gh-issue-116738.i0HWtP.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-18-08-43-35.gh-issue-116738.i0HWtP.rst
new file mode 100644
index 00000000000000..77dca4074b742f
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-18-08-43-35.gh-issue-116738.i0HWtP.rst
@@ -0,0 +1,2 @@
+Make functions in :mod:`syslog` thread-safe on the :term:`free threaded
+<free threading>` build.
diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c
index ab20fff1509dfe..5d7fd20c4e0999 100644
--- a/Modules/syslogmodule.c
+++ b/Modules/syslogmodule.c
@@ -298,7 +298,13 @@ syslog_setlogmask_impl(PyObject *module, long maskpri)
         return -1;
     }
 
-    return setlogmask(maskpri);
+    static PyMutex setlogmask_mutex = {0};
+    PyMutex_Lock(&setlogmask_mutex);
+    // Linux man page (3): setlogmask() is MT-Unsafe race:LogMask.
+    long previous_mask = setlogmask(maskpri);
+    PyMutex_Unlock(&setlogmask_mutex);
+
+    return previous_mask;
 }
 
 /*[clinic input]

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to