Skip to content

Commit d2f43bd

Browse files
committed
gh-116738: Make syslog module thread-safe
1 parent 28937d3 commit d2f43bd

3 files changed

Lines changed: 51 additions & 1 deletion

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import unittest
2+
import threading
3+
4+
from test.support import import_helper, threading_helper
5+
from test.support.threading_helper import run_concurrently
6+
7+
syslog = import_helper.import_module("syslog")
8+
9+
NTHREADS = 32
10+
11+
# Similar to Lib/test/test_syslog.py, this test's purpose is to verify that
12+
# the code neither crashes nor leaks.
13+
14+
15+
@threading_helper.requires_working_threading()
16+
class TestSyslog(unittest.TestCase):
17+
def test_racing_syslog(self):
18+
def worker():
19+
"""
20+
The syslog module provides the following functions:
21+
openlog(), syslog(), closelog(), and setlogmask().
22+
"""
23+
thread_id = threading.get_ident()
24+
syslog.openlog(f"thread-id: {thread_id}")
25+
for _ in range(5):
26+
syslog.syslog("logline")
27+
syslog.setlogmask(syslog.LOG_MASK(syslog.LOG_INFO))
28+
syslog.syslog(syslog.LOG_INFO, "logline LOG_INFO")
29+
syslog.setlogmask(syslog.LOG_MASK(syslog.LOG_ERR))
30+
syslog.syslog(syslog.LOG_ERR, "logline LOG_ERR")
31+
syslog.setlogmask(syslog.LOG_UPTO(syslog.LOG_DEBUG))
32+
syslog.closelog()
33+
34+
# Run the worker concurrently to exercise all these syslog functions
35+
run_concurrently(
36+
worker_func=worker,
37+
nthreads=NTHREADS,
38+
)
39+
40+
41+
if __name__ == "__main__":
42+
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Make functions in :mod:`syslog` thread-safe on the :term:`free threaded
2+
<free threading>` build.

Modules/syslogmodule.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,13 @@ syslog_setlogmask_impl(PyObject *module, long maskpri)
298298
return -1;
299299
}
300300

301-
return setlogmask(maskpri);
301+
static PyMutex setlogmask_mutex = {0};
302+
PyMutex_Lock(&setlogmask_mutex);
303+
// Linux man page (3): setlogmask() is MT-Unsafe race:LogMask.
304+
long previous_mask = setlogmask(maskpri);
305+
PyMutex_Unlock(&setlogmask_mutex);
306+
307+
return previous_mask;
302308
}
303309

304310
/*[clinic input]

0 commit comments

Comments
 (0)