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 +` 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] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy