From d2f43bdfd38c5901720858ef7a3e30144cf3891f Mon Sep 17 00:00:00 2001 From: alperyoney Date: Fri, 18 Jul 2025 08:48:54 -0700 Subject: [PATCH 1/2] gh-116738: Make syslog module thread-safe --- Lib/test/test_free_threading/test_syslog.py | 42 +++++++++++++++++++ ...-07-18-08-43-35.gh-issue-116738.i0HWtP.rst | 2 + Modules/syslogmodule.c | 8 +++- 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 Lib/test/test_free_threading/test_syslog.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-07-18-08-43-35.gh-issue-116738.i0HWtP.rst 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..2a995d617b4acf --- /dev/null +++ b/Lib/test/test_free_threading/test_syslog.py @@ -0,0 +1,42 @@ +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}") + 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)) + 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] From b8102af21b1984e57138572425ece2c715988325 Mon Sep 17 00:00:00 2001 From: alperyoney Date: Fri, 18 Jul 2025 13:29:58 -0700 Subject: [PATCH 2/2] gh-116738: Wrap with try/finally --- Lib/test/test_free_threading/test_syslog.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_free_threading/test_syslog.py b/Lib/test/test_free_threading/test_syslog.py index 2a995d617b4acf..b374a98b96e6de 100644 --- a/Lib/test/test_free_threading/test_syslog.py +++ b/Lib/test/test_free_threading/test_syslog.py @@ -22,14 +22,16 @@ def worker(): """ thread_id = threading.get_ident() syslog.openlog(f"thread-id: {thread_id}") - 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)) - syslog.closelog() + 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( 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