From ced41bc32973a58e920d53aebc7f4ca054f8b04d Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 5 Nov 2022 22:26:38 +0900 Subject: [PATCH 01/23] gh-99127: Port syslog module to use module state. --- ...2-11-05-22-26-35.gh-issue-99127.Btk7ih.rst | 1 + Modules/syslogmodule.c | 65 +++++++++++++++---- 2 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst new file mode 100644 index 00000000000000..0eab0cac402fd0 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst @@ -0,0 +1 @@ +Port :mod:`syslog` to use module state. Patch by Dong-hee Na. diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 5137d01c6887c6..a2a216e784d5c5 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -61,10 +61,18 @@ module syslog #include "clinic/syslogmodule.c.h" -/* only one instance, only one syslog, so globals should be ok */ -static PyObject *S_ident_o = NULL; /* identifier, held by openlog() */ -static char S_log_open = 0; +typedef struct { + PyObject *S_ident_o; /* identifier, held by openlog() */ + char S_log_open; +} _syslog_state; +static inline _syslog_state* +get_syslog_state(PyObject *module) +{ + void *state = PyModule_GetState(module); + assert(state != NULL); + return (_syslog_state *)state; +} static PyObject * syslog_get_argv(void) @@ -162,8 +170,9 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, } openlog(ident_str, logopt, facility); - S_log_open = 1; - Py_XSETREF(S_ident_o, ident); + _syslog_state *state = get_syslog_state(module); + state->S_log_open = 1; + Py_XSETREF(state->S_ident_o, ident); Py_RETURN_NONE; } @@ -193,8 +202,9 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, return NULL; } + _syslog_state *state = get_syslog_state(module); /* if log is not opened, open it now */ - if (!S_log_open) { + if (!state->S_log_open) { PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); if (openlog_ret == NULL) { return NULL; @@ -205,7 +215,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, /* Incref ident, because it can be decrefed if syslog.openlog() is * called when the GIL is released. */ - PyObject *ident = S_ident_o; + PyObject *ident = state->S_ident_o; Py_XINCREF(ident); #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe @@ -233,10 +243,12 @@ syslog_closelog_impl(PyObject *module) if (PySys_Audit("syslog.closelog", NULL) < 0) { return NULL; } - if (S_log_open) { + + _syslog_state *state = get_syslog_state(module); + if (state->S_log_open) { closelog(); - Py_CLEAR(S_ident_o); - S_log_open = 0; + Py_CLEAR(state->S_ident_o); + state->S_log_open = 0; } Py_RETURN_NONE; } @@ -315,6 +327,11 @@ syslog_exec(PyObject *module) return -1; \ } \ } while (0) + + _syslog_state *state = get_syslog_state(module); + state->S_ident_o = NULL; + state->S_log_open = 0; + /* Priorities */ ADD_INT_MACRO(module, LOG_EMERG); ADD_INT_MACRO(module, LOG_ALERT); @@ -380,6 +397,29 @@ syslog_exec(PyObject *module) return 0; } +static int +_syslog_traverse(PyObject *module, visitproc visit, void *arg) +{ + _syslog_state *state = get_syslog_state(module); + Py_VISIT(state->S_ident_o); + return 0; +} + +static int +_syslog_clear(PyObject *module) +{ + _syslog_state *state = get_syslog_state(module); + Py_CLEAR(state->S_ident_o); + state->S_log_open = 0; + return 0; +} + +static void +_syslog_free(void *module) +{ + _syslog_clear((PyObject *)module); +} + static PyModuleDef_Slot syslog_slots[] = { {Py_mod_exec, syslog_exec}, {0, NULL} @@ -390,9 +430,12 @@ static PyModuleDef_Slot syslog_slots[] = { static struct PyModuleDef syslogmodule = { PyModuleDef_HEAD_INIT, .m_name = "syslog", - .m_size = 0, + .m_size = sizeof(_syslog_state), .m_methods = syslog_methods, .m_slots = syslog_slots, + .m_traverse = _syslog_traverse, + .m_clear = _syslog_clear, + .m_free = _syslog_free, }; PyMODINIT_FUNC From 8beb461586fd6cd0e96bccb05368a8ede5ae9f47 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 5 Nov 2022 23:01:29 +0900 Subject: [PATCH 02/23] Address code review --- Modules/syslogmodule.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index a2a216e784d5c5..cd3632d79cf053 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -409,8 +409,11 @@ static int _syslog_clear(PyObject *module) { _syslog_state *state = get_syslog_state(module); - Py_CLEAR(state->S_ident_o); - state->S_log_open = 0; + if (state->S_log_open) { + closelog(); + Py_CLEAR(state->S_ident_o); + state->S_log_open = 0; + } return 0; } From d8acc8bde967f2aa9d1dbff17c809684d082bbd9 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 5 Nov 2022 23:41:50 +0900 Subject: [PATCH 03/23] Remove logic to check the openlog status while calling syslog.syslog --- Modules/syslogmodule.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index cd3632d79cf053..ea4dd9ee997445 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -203,14 +203,11 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, } _syslog_state *state = get_syslog_state(module); - /* if log is not opened, open it now */ - if (!state->S_log_open) { - PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); - if (openlog_ret == NULL) { - return NULL; - } - Py_DECREF(openlog_ret); + PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); + if (openlog_ret == NULL) { + return NULL; } + Py_DECREF(openlog_ret); /* Incref ident, because it can be decrefed if syslog.openlog() is * called when the GIL is released. From 11d9228f67a0f10b5ee43571f8cf98f8a6574612 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 6 Nov 2022 00:17:33 +0900 Subject: [PATCH 04/23] Do not call openlog while calling syslog --- Modules/syslogmodule.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index ea4dd9ee997445..1c13b6cce7a18e 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -203,17 +203,6 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, } _syslog_state *state = get_syslog_state(module); - PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); - if (openlog_ret == NULL) { - return NULL; - } - Py_DECREF(openlog_ret); - - /* Incref ident, because it can be decrefed if syslog.openlog() is - * called when the GIL is released. - */ - PyObject *ident = state->S_ident_o; - Py_XINCREF(ident); #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe syslog(priority, "%s", message); @@ -222,7 +211,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, syslog(priority, "%s", message); Py_END_ALLOW_THREADS; #endif - Py_XDECREF(ident); + state->S_log_open = 1; Py_RETURN_NONE; } From e7408a874ecb5a3a986f3ff9a10128e9bf064593 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 6 Nov 2022 00:36:33 +0900 Subject: [PATCH 05/23] Fix test_audit --- Lib/test/test_audit.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 50f78f2a6b8a46..b9c401cc12a81d 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -216,7 +216,6 @@ def test_syslog(self): ('syslog.setlogmask', ' ', f'{syslog.LOG_DEBUG}'), ('syslog.closelog', '', ''), ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test2'), - ('syslog.openlog', ' ', f'audit-tests.py 0 {syslog.LOG_USER}'), ('syslog.openlog', ' ', f'audit-tests.py {syslog.LOG_NDELAY} {syslog.LOG_LOCAL0}'), ('syslog.openlog', ' ', f'None 0 {syslog.LOG_USER}'), ('syslog.closelog', '', '')] From 69ac18a8e583c1874b389228c51c857a3ad0c318 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sun, 6 Nov 2022 12:26:54 +0900 Subject: [PATCH 06/23] nit --- Modules/syslogmodule.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 1c13b6cce7a18e..fbb9fac44b4aca 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -233,9 +233,12 @@ syslog_closelog_impl(PyObject *module) _syslog_state *state = get_syslog_state(module); if (state->S_log_open) { closelog(); - Py_CLEAR(state->S_ident_o); state->S_log_open = 0; } + + if (state->S_ident_o != NULL) { + Py_CLEAR(state->S_ident_o); + } Py_RETURN_NONE; } @@ -397,9 +400,12 @@ _syslog_clear(PyObject *module) _syslog_state *state = get_syslog_state(module); if (state->S_log_open) { closelog(); - Py_CLEAR(state->S_ident_o); state->S_log_open = 0; } + + if (state->S_ident_o != NULL) { + Py_CLEAR(state->S_ident_o); + } return 0; } From 3a784f64838aaadb61ed3ae46908a41649d71910 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 7 Nov 2022 00:18:12 +0900 Subject: [PATCH 07/23] Address code review --- Modules/syslogmodule.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index fbb9fac44b4aca..8e9ccd24114357 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -236,9 +236,7 @@ syslog_closelog_impl(PyObject *module) state->S_log_open = 0; } - if (state->S_ident_o != NULL) { - Py_CLEAR(state->S_ident_o); - } + Py_CLEAR(state->S_ident_o); Py_RETURN_NONE; } @@ -403,9 +401,7 @@ _syslog_clear(PyObject *module) state->S_log_open = 0; } - if (state->S_ident_o != NULL) { - Py_CLEAR(state->S_ident_o); - } + Py_CLEAR(state->S_ident_o); return 0; } From f5cf63a22fb8f8753dab28c1f2da5489c320aabb Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 7 Nov 2022 01:02:23 +0900 Subject: [PATCH 08/23] nit --- Modules/syslogmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 8e9ccd24114357..abefdfd7375cc6 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -408,7 +408,7 @@ _syslog_clear(PyObject *module) static void _syslog_free(void *module) { - _syslog_clear((PyObject *)module); + (void)_syslog_clear((PyObject *)module); } static PyModuleDef_Slot syslog_slots[] = { From fc8582720bba5b3e865fa783939efc7e242fcd76 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 11 Nov 2022 15:33:27 +0900 Subject: [PATCH 09/23] Address code review --- Modules/syslogmodule.c | 54 +++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index abefdfd7375cc6..e7f73934603568 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -62,10 +62,22 @@ module syslog #include "clinic/syslogmodule.c.h" typedef struct { - PyObject *S_ident_o; /* identifier, held by openlog() */ - char S_log_open; + PyObject *ident_o; /* identifier, held by openlog() */ + char log_open; /* flag for checking whether the openlog() is already called. */ } _syslog_state; + +static inline int is_main_interpreter() +{ + PyInterpreterState *main_interp = PyInterpreterState_Main(); + PyThreadState *tstate = PyThreadState_GET(); + PyInterpreterState *current_interp = PyThreadState_GetInterpreter(tstate); + if (current_interp == main_interp) { + return 0; + } + return -1; +} + static inline _syslog_state* get_syslog_state(PyObject *module) { @@ -143,6 +155,11 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, long facility) /*[clinic end generated code: output=5476c12829b6eb75 input=8a987a96a586eee7]*/ { + if (is_main_interpreter() < 0) { + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); + return NULL; + } + const char *ident_str = NULL; if (ident) { @@ -171,8 +188,8 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, openlog(ident_str, logopt, facility); _syslog_state *state = get_syslog_state(module); - state->S_log_open = 1; - Py_XSETREF(state->S_ident_o, ident); + state->log_open = 1; + Py_XSETREF(state->ident_o, ident); Py_RETURN_NONE; } @@ -203,6 +220,10 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, } _syslog_state *state = get_syslog_state(module); + if (state->log_open != 1 && is_main_interpreter() < 0) { + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter."); + return NULL; + } #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe syslog(priority, "%s", message); @@ -211,7 +232,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, syslog(priority, "%s", message); Py_END_ALLOW_THREADS; #endif - state->S_log_open = 1; + state->log_open = 1; Py_RETURN_NONE; } @@ -226,17 +247,22 @@ static PyObject * syslog_closelog_impl(PyObject *module) /*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/ { + if (is_main_interpreter() < 0) { + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); + return NULL; + } + if (PySys_Audit("syslog.closelog", NULL) < 0) { return NULL; } _syslog_state *state = get_syslog_state(module); - if (state->S_log_open) { + if (state->log_open) { closelog(); - state->S_log_open = 0; + state->log_open = 0; } - Py_CLEAR(state->S_ident_o); + Py_CLEAR(state->ident_o); Py_RETURN_NONE; } @@ -316,8 +342,8 @@ syslog_exec(PyObject *module) } while (0) _syslog_state *state = get_syslog_state(module); - state->S_ident_o = NULL; - state->S_log_open = 0; + state->ident_o = NULL; + state->log_open = 0; /* Priorities */ ADD_INT_MACRO(module, LOG_EMERG); @@ -388,7 +414,7 @@ static int _syslog_traverse(PyObject *module, visitproc visit, void *arg) { _syslog_state *state = get_syslog_state(module); - Py_VISIT(state->S_ident_o); + Py_VISIT(state->ident_o); return 0; } @@ -396,12 +422,12 @@ static int _syslog_clear(PyObject *module) { _syslog_state *state = get_syslog_state(module); - if (state->S_log_open) { + if (state->log_open) { closelog(); - state->S_log_open = 0; + state->log_open = 0; } - Py_CLEAR(state->S_ident_o); + Py_CLEAR(state->ident_o); return 0; } From f40d953dc658fa4c909a3f73d38734f6c19e969d Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 11 Nov 2022 15:47:29 +0900 Subject: [PATCH 10/23] Add test --- Lib/test/test_syslog.py | 47 +++++++++++++++++++++++++++++++++++++++++ Modules/syslogmodule.c | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index 2125ec58d87e03..746434c48b6725 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -5,6 +5,7 @@ import threading import time import unittest +from textwrap import dedent # XXX(nnorwitz): This test sucks. I don't know of a platform independent way # to verify that the messages were really logged. @@ -78,6 +79,52 @@ def logger(): finally: sys.setswitchinterval(orig_si) + def test_subinterpreter_syslog(self): + code = dedent(''' + import syslog + catch_error = False + try: + syslog.syslog('foo') + except RuntimeError: + catch_error = True + + assert(catch_error == True) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + + def test_subinterpreter_openlog(self): + code = dedent(''' + import syslog + catch_error = False + try: + syslog.openlog() + except RuntimeError: + catch_error = True + + assert(catch_error == True) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + + def test_subinterpreter_closelog(self): + syslog.openlog('python') + code = dedent(''' + import syslog + catch_error = False + try: + syslog.closelog() + except RuntimeError: + catch_error = True + + assert(catch_error == True) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + syslog.closelog() + + + if __name__ == "__main__": unittest.main() diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index e7f73934603568..ec339ea3f33438 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -248,7 +248,7 @@ syslog_closelog_impl(PyObject *module) /*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/ { if (is_main_interpreter() < 0) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.closelog at non-main interpreter."); return NULL; } From 35bbac240ca7d5f90fd1f57b557e5bcef49b9696 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 11 Nov 2022 15:48:52 +0900 Subject: [PATCH 11/23] nit --- Modules/syslogmodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index ec339ea3f33438..7bcdd454f429be 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -67,7 +67,8 @@ typedef struct { } _syslog_state; -static inline int is_main_interpreter() +static inline int +is_main_interpreter() { PyInterpreterState *main_interp = PyInterpreterState_Main(); PyThreadState *tstate = PyThreadState_GET(); From 525a32b55ed03af6d191f2a0cd638b9d79c16b7b Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:00:32 +0900 Subject: [PATCH 12/23] Address code review --- Lib/test/test_audit.py | 1 + Lib/test/test_syslog.py | 48 ++++++++++++--------- Modules/syslogmodule.c | 93 +++++++++++++---------------------------- 3 files changed, 59 insertions(+), 83 deletions(-) diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index b9c401cc12a81d..50f78f2a6b8a46 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -216,6 +216,7 @@ def test_syslog(self): ('syslog.setlogmask', ' ', f'{syslog.LOG_DEBUG}'), ('syslog.closelog', '', ''), ('syslog.syslog', ' ', f'{syslog.LOG_INFO} test2'), + ('syslog.openlog', ' ', f'audit-tests.py 0 {syslog.LOG_USER}'), ('syslog.openlog', ' ', f'audit-tests.py {syslog.LOG_NDELAY} {syslog.LOG_LOCAL0}'), ('syslog.openlog', ' ', f'None 0 {syslog.LOG_USER}'), ('syslog.closelog', '', '')] diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index 746434c48b6725..73c89a7c6fb299 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -80,29 +80,41 @@ def logger(): sys.setswitchinterval(orig_si) def test_subinterpreter_syslog(self): - code = dedent(''' - import syslog - catch_error = False - try: - syslog.syslog('foo') - except RuntimeError: - catch_error = True + # syslog.syslog() is not allowed in subinterpreters, but only if + # syslog.openlog() hasn't been called in the main interpreter yet. + with self.subTest('before openlog()'): + code = dedent(''' + import syslog + caught_error = False + try: + syslog.syslog('foo') + except RuntimeError: + caught_error = True + assert(caught_error) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) - assert(catch_error == True) - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) + syslog.openlog() + with self.subTest('after openlog()'): + code = dedent(''' + import syslog + syslog.syslog('foo') + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + syslog.closelog() def test_subinterpreter_openlog(self): code = dedent(''' import syslog - catch_error = False + caught_error = False try: syslog.openlog() except RuntimeError: - catch_error = True + caught_error = True - assert(catch_error == True) + assert(caught_error) ''') res = support.run_in_subinterp(code) self.assertEqual(res, 0) @@ -111,20 +123,18 @@ def test_subinterpreter_closelog(self): syslog.openlog('python') code = dedent(''' import syslog - catch_error = False + caught_error = False try: syslog.closelog() except RuntimeError: - catch_error = True + caught_error = True - assert(catch_error == True) + assert(caught_error) ''') res = support.run_in_subinterp(code) self.assertEqual(res, 0) syslog.closelog() - - if __name__ == "__main__": unittest.main() diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 7bcdd454f429be..86107e730bb2e9 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -61,11 +61,10 @@ module syslog #include "clinic/syslogmodule.c.h" -typedef struct { - PyObject *ident_o; /* identifier, held by openlog() */ - char log_open; /* flag for checking whether the openlog() is already called. */ -} _syslog_state; - +/* only one instance, only one syslog, so globals should be ok, + * these fields are writable from the main interpreter only. */ +static PyObject *S_ident_o = NULL; // identifier, held by openlog() +static char S_log_open = 0; static inline int is_main_interpreter() @@ -74,17 +73,9 @@ is_main_interpreter() PyThreadState *tstate = PyThreadState_GET(); PyInterpreterState *current_interp = PyThreadState_GetInterpreter(tstate); if (current_interp == main_interp) { - return 0; + return 1; } - return -1; -} - -static inline _syslog_state* -get_syslog_state(PyObject *module) -{ - void *state = PyModule_GetState(module); - assert(state != NULL); - return (_syslog_state *)state; + return 0; } static PyObject * @@ -156,7 +147,9 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, long facility) /*[clinic end generated code: output=5476c12829b6eb75 input=8a987a96a586eee7]*/ { - if (is_main_interpreter() < 0) { + // Since the sys.openlog changes the process level state of syslog library, + // this operation is only allowed for the main interpreter. + if (!is_main_interpreter()) { PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); return NULL; } @@ -188,9 +181,8 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, } openlog(ident_str, logopt, facility); - _syslog_state *state = get_syslog_state(module); - state->log_open = 1; - Py_XSETREF(state->ident_o, ident); + S_log_open = 1; + Py_XSETREF(S_ident_o, ident); Py_RETURN_NONE; } @@ -220,10 +212,16 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, return NULL; } - _syslog_state *state = get_syslog_state(module); - if (state->log_open != 1 && is_main_interpreter() < 0) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter."); - return NULL; + if (!S_log_open) { + if (!is_main_interpreter()) { + PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter for the first time."); + return NULL; + } + PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); + if (openlog_ret == NULL) { + return NULL; + } + Py_DECREF(openlog_ret); } #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe @@ -233,7 +231,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, syslog(priority, "%s", message); Py_END_ALLOW_THREADS; #endif - state->log_open = 1; + S_log_open = 1; Py_RETURN_NONE; } @@ -248,7 +246,9 @@ static PyObject * syslog_closelog_impl(PyObject *module) /*[clinic end generated code: output=97890a80a24b1b84 input=fb77a54d447acf07]*/ { - if (is_main_interpreter() < 0) { + // Since the sys.closelog changes the process level state of syslog library, + // this operation is only allowed for the main interpreter. + if (!is_main_interpreter()) { PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.closelog at non-main interpreter."); return NULL; } @@ -257,13 +257,12 @@ syslog_closelog_impl(PyObject *module) return NULL; } - _syslog_state *state = get_syslog_state(module); - if (state->log_open) { + if (S_log_open) { closelog(); - state->log_open = 0; + S_log_open = 0; + Py_CLEAR(S_ident_o); } - Py_CLEAR(state->ident_o); Py_RETURN_NONE; } @@ -342,10 +341,6 @@ syslog_exec(PyObject *module) } \ } while (0) - _syslog_state *state = get_syslog_state(module); - state->ident_o = NULL; - state->log_open = 0; - /* Priorities */ ADD_INT_MACRO(module, LOG_EMERG); ADD_INT_MACRO(module, LOG_ALERT); @@ -411,33 +406,6 @@ syslog_exec(PyObject *module) return 0; } -static int -_syslog_traverse(PyObject *module, visitproc visit, void *arg) -{ - _syslog_state *state = get_syslog_state(module); - Py_VISIT(state->ident_o); - return 0; -} - -static int -_syslog_clear(PyObject *module) -{ - _syslog_state *state = get_syslog_state(module); - if (state->log_open) { - closelog(); - state->log_open = 0; - } - - Py_CLEAR(state->ident_o); - return 0; -} - -static void -_syslog_free(void *module) -{ - (void)_syslog_clear((PyObject *)module); -} - static PyModuleDef_Slot syslog_slots[] = { {Py_mod_exec, syslog_exec}, {0, NULL} @@ -448,12 +416,9 @@ static PyModuleDef_Slot syslog_slots[] = { static struct PyModuleDef syslogmodule = { PyModuleDef_HEAD_INIT, .m_name = "syslog", - .m_size = sizeof(_syslog_state), + .m_size = 0, .m_methods = syslog_methods, .m_slots = syslog_slots, - .m_traverse = _syslog_traverse, - .m_clear = _syslog_clear, - .m_free = _syslog_free, }; PyMODINIT_FUNC From 741baf05f8eed8e6a21997d930768a3e7508e0d1 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:02:58 +0900 Subject: [PATCH 13/23] Update NEWS.d --- .../2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst index 0eab0cac402fd0..e93ae4e7b127d1 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-05-22-26-35.gh-issue-99127.Btk7ih.rst @@ -1 +1 @@ -Port :mod:`syslog` to use module state. Patch by Dong-hee Na. +Allow some features of :mod:`syslog` to the main interpreter only. Patch by Dong-hee Na. From 779a3d22e2990f23fa694f7b0dc8dabe4b4a932b Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:04:24 +0900 Subject: [PATCH 14/23] nit --- Modules/syslogmodule.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 86107e730bb2e9..60d220fcf35b36 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -340,7 +340,6 @@ syslog_exec(PyObject *module) return -1; \ } \ } while (0) - /* Priorities */ ADD_INT_MACRO(module, LOG_EMERG); ADD_INT_MACRO(module, LOG_ALERT); From 557578f85b2082256b13dbf6499d98cb8f3f45d1 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:07:48 +0900 Subject: [PATCH 15/23] Revert some logic --- Modules/syslogmodule.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 60d220fcf35b36..e26a2b44551276 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -223,6 +223,12 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, } Py_DECREF(openlog_ret); } + + /* Incref ident, because it can be decrefed if syslog.openlog() is + * called when the GIL is released. + */ + PyObject *ident = S_ident_o; + Py_XINCREF(ident); #ifdef __APPLE__ // gh-98178: On macOS, libc syslog() is not thread-safe syslog(priority, "%s", message); @@ -231,7 +237,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, syslog(priority, "%s", message); Py_END_ALLOW_THREADS; #endif - S_log_open = 1; + Py_XDECREF(ident); Py_RETURN_NONE; } From 01334e8e962d80ecf45a425aabae88d36d1a8519 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Sat, 12 Nov 2022 20:09:19 +0900 Subject: [PATCH 16/23] nit --- Modules/syslogmodule.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index e26a2b44551276..da0752d515b2e7 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -212,6 +212,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, return NULL; } + /* if log is not opened, open it now */ if (!S_log_open) { if (!is_main_interpreter()) { PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter for the first time."); @@ -262,13 +263,11 @@ syslog_closelog_impl(PyObject *module) if (PySys_Audit("syslog.closelog", NULL) < 0) { return NULL; } - if (S_log_open) { closelog(); - S_log_open = 0; Py_CLEAR(S_ident_o); + S_log_open = 0; } - Py_RETURN_NONE; } From 4ad2b8f173259a73ae42e1e321d9e2e49118a3ed Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Mon, 14 Nov 2022 20:49:07 +0900 Subject: [PATCH 17/23] Address code review --- Modules/syslogmodule.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index da0752d515b2e7..85c2827b375aa7 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -67,7 +67,7 @@ static PyObject *S_ident_o = NULL; // identifier, held by openlog() static char S_log_open = 0; static inline int -is_main_interpreter() +is_main_interpreter(void) { PyInterpreterState *main_interp = PyInterpreterState_Main(); PyThreadState *tstate = PyThreadState_GET(); @@ -150,7 +150,7 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, // Since the sys.openlog changes the process level state of syslog library, // this operation is only allowed for the main interpreter. if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.openlog at non-main interpreter."); + PyErr_SetString(PyExc_RuntimeError, "subinterpreter can not use syslog.openlog"); return NULL; } @@ -215,7 +215,8 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, /* if log is not opened, open it now */ if (!S_log_open) { if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.syslog at non-main interpreter for the first time."); + PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog " + "until the syslog is opened by the main interpreter"); return NULL; } PyObject *openlog_ret = syslog_openlog_impl(module, NULL, 0, LOG_USER); @@ -256,7 +257,7 @@ syslog_closelog_impl(PyObject *module) // Since the sys.closelog changes the process level state of syslog library, // this operation is only allowed for the main interpreter. if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "unable to use syslog.closelog at non-main interpreter."); + PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can not use syslog.closelog"); return NULL; } From 696196d8e138d28a4440767f10b934fc3fa56387 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 16 Nov 2022 12:59:21 +0900 Subject: [PATCH 18/23] Update Lib/test/test_syslog.py Co-authored-by: Eric Snow --- Lib/test/test_syslog.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index 73c89a7c6fb299..4beeed4c58f6ac 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -96,14 +96,16 @@ def test_subinterpreter_syslog(self): self.assertEqual(res, 0) syslog.openlog() - with self.subTest('after openlog()'): - code = dedent(''' - import syslog - syslog.syslog('foo') - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) - syslog.closelog() + try: + with self.subTest('after openlog()'): + code = dedent(''' + import syslog + syslog.syslog('foo') + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + finally: + syslog.closelog() def test_subinterpreter_openlog(self): code = dedent(''' From 5eeade569d87628f65fc8c5dfc9bfe6ee0ed555e Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Wed, 16 Nov 2022 13:05:09 +0900 Subject: [PATCH 19/23] Address code review --- Lib/test/test_syslog.py | 55 ++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/Lib/test/test_syslog.py b/Lib/test/test_syslog.py index 4beeed4c58f6ac..54db80fa9df1af 100644 --- a/Lib/test/test_syslog.py +++ b/Lib/test/test_syslog.py @@ -108,34 +108,39 @@ def test_subinterpreter_syslog(self): syslog.closelog() def test_subinterpreter_openlog(self): - code = dedent(''' - import syslog - caught_error = False - try: - syslog.openlog() - except RuntimeError: - caught_error = True - - assert(caught_error) - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) + try: + code = dedent(''' + import syslog + caught_error = False + try: + syslog.openlog() + except RuntimeError: + caught_error = True + + assert(caught_error) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + finally: + syslog.closelog() def test_subinterpreter_closelog(self): syslog.openlog('python') - code = dedent(''' - import syslog - caught_error = False - try: - syslog.closelog() - except RuntimeError: - caught_error = True - - assert(caught_error) - ''') - res = support.run_in_subinterp(code) - self.assertEqual(res, 0) - syslog.closelog() + try: + code = dedent(''' + import syslog + caught_error = False + try: + syslog.closelog() + except RuntimeError: + caught_error = True + + assert(caught_error) + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + finally: + syslog.closelog() if __name__ == "__main__": From fb81c1eb81f2a2de720285ee5c90d92ec5d94963 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 17 Nov 2022 10:15:23 +0900 Subject: [PATCH 20/23] Address code review --- Modules/syslogmodule.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index 85c2827b375aa7..97f761d253d4f7 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -69,13 +69,7 @@ static char S_log_open = 0; static inline int is_main_interpreter(void) { - PyInterpreterState *main_interp = PyInterpreterState_Main(); - PyThreadState *tstate = PyThreadState_GET(); - PyInterpreterState *current_interp = PyThreadState_GetInterpreter(tstate); - if (current_interp == main_interp) { - return 1; - } - return 0; + return (PyInterpreterState_Get() == PyInterpreterState_Main()); } static PyObject * @@ -150,7 +144,7 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, // Since the sys.openlog changes the process level state of syslog library, // this operation is only allowed for the main interpreter. if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "subinterpreter can not use syslog.openlog"); + PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.openlog()"); return NULL; } @@ -215,7 +209,7 @@ syslog_syslog_impl(PyObject *module, int group_left_1, int priority, /* if log is not opened, open it now */ if (!S_log_open) { if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog " + PyErr_SetString(PyExc_RuntimeError, "subinterpreter can't use syslog.syslog() " "until the syslog is opened by the main interpreter"); return NULL; } @@ -257,7 +251,7 @@ syslog_closelog_impl(PyObject *module) // Since the sys.closelog changes the process level state of syslog library, // this operation is only allowed for the main interpreter. if (!is_main_interpreter()) { - PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can not use syslog.closelog"); + PyErr_SetString(PyExc_RuntimeError, "sunbinterpreter can't use syslog.closelog()"); return NULL; } From 140366b1861aef326d5162ecfbc69193b83a6c15 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 17 Nov 2022 21:41:54 +0900 Subject: [PATCH 21/23] Update documentations --- Doc/library/syslog.rst | 12 ++++++++++++ Doc/whatsnew/3.12.rst | 7 +++++++ 2 files changed, 19 insertions(+) diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst index 766ff57cc66d69..e8440aeb72ec99 100644 --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -40,6 +40,10 @@ The module defines the following functions: it wasn't called prior to the call to :func:`syslog`, deferring to the syslog implementation to call ``openlog()``. + .. versionchanged:: 3.12 + Subinterpreters are allowed to call only if the main interpreter already called :func:`openlog`. + If not, it will raise :exc:`RuntimeError`. + .. function:: openlog([ident[, logoption[, facility]]]) @@ -60,6 +64,10 @@ The module defines the following functions: In previous versions, keyword arguments were not allowed, and *ident* was required. + .. versionchanged:: 3.12 + Only the main interpreter is allowed to call. It will raise :exc:`RuntimeError` + if subinterpreters call :func:`openlog`. + .. function:: closelog() @@ -72,6 +80,10 @@ The module defines the following functions: .. audit-event:: syslog.closelog "" syslog.closelog + .. versionchanged:: 3.12 + Only the main interpreter is allowed to call. It will raise :exc:`RuntimeError` + if subinterpreters call :func:`closelog`. + .. function:: setlogmask(maskpri) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index ead2a9e718a9e2..861d044404a279 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -295,6 +295,13 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) +syslog +------ + +* :func:`syslog.openlog` and :func:`syslog.closelog` are only available from the main interpreter not subinterpreter. + :func:`syslog.syslog` is only available to subinterpreters if :func:`syslog.openlog` was already called from the main interpreter. + (Contributed by Dong-hee Na in :gh:`99127`.) + Optimizations ============= From c961709f5b780ab1b0014eead1b3f02d59f44235 Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Thu, 17 Nov 2022 23:30:29 +0900 Subject: [PATCH 22/23] Address code review --- Doc/whatsnew/3.12.rst | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 861d044404a279..bc08ccf52ac830 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -295,13 +295,6 @@ sys with contributions from Gregory P. Smith [Google] and Mark Shannon in :gh:`96123`.) -syslog ------- - -* :func:`syslog.openlog` and :func:`syslog.closelog` are only available from the main interpreter not subinterpreter. - :func:`syslog.syslog` is only available to subinterpreters if :func:`syslog.openlog` was already called from the main interpreter. - (Contributed by Dong-hee Na in :gh:`99127`.) - Optimizations ============= @@ -656,6 +649,10 @@ Changes in the Python API :class:`bytes` type is accepted for bytes strings. (Contributed by Victor Stinner in :gh:`98393`.) +* :func:`syslog.openlog` and :func:`syslog.closelog` are only available from the main interpreter not subinterpreter. + :func:`syslog.syslog` is only available to subinterpreters if :func:`syslog.openlog` was already called from the main interpreter. + (Contributed by Dong-hee Na in :gh:`99127`.) + Build Changes ============= From e8dce888766f52834b1d6fc5b943a58bdf7482af Mon Sep 17 00:00:00 2001 From: Dong-hee Na Date: Fri, 18 Nov 2022 13:58:33 +0900 Subject: [PATCH 23/23] Apply suggestions from code review Co-authored-by: Eric Snow --- Doc/library/syslog.rst | 21 +++++++++++++++------ Doc/whatsnew/3.12.rst | 9 +++++++-- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Doc/library/syslog.rst b/Doc/library/syslog.rst index e8440aeb72ec99..f29ef03267b1ba 100644 --- a/Doc/library/syslog.rst +++ b/Doc/library/syslog.rst @@ -41,8 +41,11 @@ The module defines the following functions: implementation to call ``openlog()``. .. versionchanged:: 3.12 - Subinterpreters are allowed to call only if the main interpreter already called :func:`openlog`. - If not, it will raise :exc:`RuntimeError`. + This function is restricted in subinterpreters. + (Only code that runs in multiple interpreters is affected and + the restriction is not relevant for most users.) + :func:`openlog` must be called in the main interpreter before :func:`syslog` may be used + in a subinterpreter. Otherwise it will raise :exc:`RuntimeError`. .. function:: openlog([ident[, logoption[, facility]]]) @@ -65,8 +68,11 @@ The module defines the following functions: required. .. versionchanged:: 3.12 - Only the main interpreter is allowed to call. It will raise :exc:`RuntimeError` - if subinterpreters call :func:`openlog`. + This function is restricted in subinterpreters. + (Only code that runs in multiple interpreters is affected and + the restriction is not relevant for most users.) + This may only be called in the main interpreter. + It will raise :exc:`RuntimeError` if called in a subinterpreter. .. function:: closelog() @@ -81,8 +87,11 @@ The module defines the following functions: .. audit-event:: syslog.closelog "" syslog.closelog .. versionchanged:: 3.12 - Only the main interpreter is allowed to call. It will raise :exc:`RuntimeError` - if subinterpreters call :func:`closelog`. + This function is restricted in subinterpreters. + (Only code that runs in multiple interpreters is affected and + the restriction is not relevant for most users.) + This may only be called in the main interpreter. + It will raise :exc:`RuntimeError` if called in a subinterpreter. .. function:: setlogmask(maskpri) diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index bc08ccf52ac830..b3916956158b40 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -649,8 +649,13 @@ Changes in the Python API :class:`bytes` type is accepted for bytes strings. (Contributed by Victor Stinner in :gh:`98393`.) -* :func:`syslog.openlog` and :func:`syslog.closelog` are only available from the main interpreter not subinterpreter. - :func:`syslog.syslog` is only available to subinterpreters if :func:`syslog.openlog` was already called from the main interpreter. +* :func:`syslog.openlog` and :func:`syslog.closelog` now fail if used in subinterpreters. + :func:`syslog.syslog` may still be used in subinterpreters, + but now only if :func:`syslog.openlog` has already been called in the main interpreter. + These new restrictions do not apply to the main interpreter, + so only a very small set of users might be affected. + This change helps with interpreter isolation. Furthermore, :mod:`syslog` is a wrapper + around process-global resources, which are best managed from the main interpreter. (Contributed by Dong-hee Na in :gh:`99127`.)