From 5a119c748c423fa6b78b30d13d0425432074f0fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 5 Oct 2024 10:32:36 +0200 Subject: [PATCH 1/4] make global flags free-threaded friendly --- Modules/_cursesmodule.c | 179 ++++++++++++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 33 deletions(-) diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 61b65675375547..1d753991c0f61e 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -192,17 +192,118 @@ class _curses.window "PyCursesWindowObject *" "clinic_state()->window_type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ae6cb623018f2cbc]*/ -/* Tells whether setupterm() has been called to initialise terminfo. */ +/* + * Tells whether setupterm() has been called to initialise terminfo. + * + * Use curses_setupterm_{was,set}_called() for atomic reads and writes. + */ static int curses_setupterm_called = FALSE; -/* Tells whether initscr() has been called to initialise curses. */ +static inline int +curses_setupterm_was_called(void) +{ +#ifdef Py_GIL_DISABLED + return _Py_atomic_load_int(&curses_setupterm_called); +#else + return curses_setupterm_called; +#endif +} + +static inline void +curses_setupterm_set_called(void) +{ +#ifdef Py_GIL_DISABLED + _Py_atomic_store_int(&curses_setupterm_called, TRUE); +#else + curses_setupterm_called = TRUE; +#endif +} + +/* + * Tells whether initscr() has been called to initialise curses. + * + * Use curses_initscr_{was,set}_called() for atomic reads and writes. + */ static int curses_initscr_called = FALSE; -/* Tells whether start_color() has been called to initialise color usage. */ +static inline int +curses_initscr_was_called(void) +{ +#ifdef Py_GIL_DISABLED + return _Py_atomic_load_int(&curses_initscr_called); +#else + return curses_initscr_called; +#endif +} + +static inline void +curses_initscr_set_called(void) +{ +#ifdef Py_GIL_DISABLED + _Py_atomic_store_int(&curses_initscr_called, TRUE); +#else + curses_initscr_called = TRUE; +#endif +} + +/* + * Tells whether start_color() has been called to initialise color usage. + * + * Use curses_start_color_{was,set}_called() for atomic reads and writes. + */ static int curses_start_color_called = FALSE; +static inline int +curses_start_color_was_called(void) +{ +#ifdef Py_GIL_DISABLED + return _Py_atomic_load_int(&curses_start_color_called); +#else + return curses_start_color_called; +#endif +} + +static inline void +curses_start_color_set_called(void) +{ +#ifdef Py_GIL_DISABLED + _Py_atomic_store_int(&curses_start_color_called, TRUE); +#else + curses_start_color_called = TRUE; +#endif +} + +/* + * The curses screen encoding. + * + * Use curses_{get,set}_screen_encoding() to + * safely (atomically) access this variable. + */ static const char *curses_screen_encoding = NULL; +/* Atomically retrieve the current screen encoding. */ +static inline const char * +curses_get_screen_encoding(void) +{ +#ifdef Py_GIL_DISABLED + return (const char *)_Py_atomic_load_ptr(&curses_screen_encoding); +#else + return curses_screen_encoding; +#endif +} + +/* Atomically set the current screen encoding. */ +static inline void +curses_set_screen_encoding(const char *encoding) +{ + assert(encoding != NULL); +#ifdef Py_GIL_DISABLED + _Py_atomic_store_ptr(&curses_screen_encoding, (char *)encoding); +#else + curses_screen_encoding = encoding; +#endif +} + /* Utility Checking Procedures */ /* @@ -215,7 +316,7 @@ static const char *curses_screen_encoding = NULL; * type is directly taken from the global state for now. */ static inline int -_PyCursesCheckFunction(int called, const char *funcname) +_PyCursesStatelessCheckWasCalled(int called, const char *funcname) { if (called == TRUE) { return 1; @@ -232,7 +333,7 @@ _PyCursesCheckFunction(int called, const char *funcname) * The exception type is obtained from the 'module' state. */ static inline int -_PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcname) +_PyCursesCheckWasCalled(PyObject *module, int called, const char *funcname) { if (called == TRUE) { return 1; @@ -244,30 +345,24 @@ _PyCursesStatefulCheckFunction(PyObject *module, int called, const char *funcnam #define PyCursesStatefulSetupTermCalled(MODULE) \ do { \ - if (!_PyCursesStatefulCheckFunction(MODULE, \ - curses_setupterm_called, \ - "setupterm")) \ - { \ + int called = curses_setupterm_was_called(); \ + if (!_PyCursesCheckWasCalled(MODULE, called, "setupterm")) { \ return 0; \ } \ } while (0) #define PyCursesStatefulInitialised(MODULE) \ do { \ - if (!_PyCursesStatefulCheckFunction(MODULE, \ - curses_initscr_called, \ - "initscr")) \ - { \ + int called = curses_initscr_was_called(); \ + if (!_PyCursesCheckWasCalled(MODULE, called, "initscr")) { \ return 0; \ } \ } while (0) #define PyCursesStatefulInitialisedColor(MODULE) \ do { \ - if (!_PyCursesStatefulCheckFunction(MODULE, \ - curses_start_color_called, \ - "start_color")) \ - { \ + int called = curses_start_color_was_called(); \ + if (!_PyCursesCheckWasCalled(MODULE, called, "start_color")) { \ return 0; \ } \ } while (0) @@ -350,7 +445,7 @@ PyCurses_ConvertToChtype(PyCursesWindowObject *win, PyObject *obj, chtype *ch) if (win) encoding = win->encoding; else - encoding = curses_screen_encoding; + encoding = curses_get_screen_encoding(); bytes = PyUnicode_AsEncodedString(obj, encoding, NULL); if (bytes == NULL) return 0; @@ -3356,7 +3451,7 @@ _curses_initscr_impl(PyObject *module) { WINDOW *win; - if (curses_initscr_called) { + if (curses_initscr_was_called()) { wrefresh(stdscr); _cursesmodule_state *state = get_cursesmodule_state(module); return PyCursesWindow_New(state, stdscr, NULL); @@ -3370,7 +3465,8 @@ _curses_initscr_impl(PyObject *module) return NULL; } - curses_initscr_called = curses_setupterm_called = TRUE; + curses_initscr_set_called(); + curses_setupterm_set_called(); PyObject *module_dict = PyModule_GetDict(module); // borrowed if (module_dict == NULL) { @@ -3467,7 +3563,7 @@ _curses_initscr_impl(PyObject *module) if (winobj == NULL) { return NULL; } - curses_screen_encoding = ((PyCursesWindowObject *)winobj)->encoding; + curses_set_screen_encoding(((PyCursesWindowObject *)winobj)->encoding); return winobj; } @@ -3522,8 +3618,7 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) return NULL; } - curses_setupterm_called = TRUE; - + curses_setupterm_set_called(); Py_RETURN_NONE; } @@ -4332,7 +4427,7 @@ _curses_start_color_impl(PyObject *module) return NULL; } - curses_start_color_called = TRUE; + curses_start_color_set_called(); PyObject *module_dict = PyModule_GetDict(module); // borrowed if (module_dict == NULL) { @@ -4854,21 +4949,24 @@ static PyMethodDef PyCurses_methods[] = { initialised or not. */ static inline int -curses_capi_setupterm_called(void) +curses_capi_setupterm_was_called(void) { - return _PyCursesCheckFunction(curses_setupterm_called, "setupterm"); + int called = curses_setupterm_was_called(); + return _PyCursesStatelessCheckWasCalled(called, "setupterm"); } static inline int -curses_capi_initscr_called(void) +curses_capi_initscr_was_called(void) { - return _PyCursesCheckFunction(curses_initscr_called, "initscr"); + int called = curses_initscr_was_called(); + return _PyCursesStatelessCheckWasCalled(called, "initscr"); } static inline int -curses_capi_start_color_called(void) +curses_capi_start_color_was_called(void) { - return _PyCursesCheckFunction(curses_start_color_called, "start_color"); + int called = curses_start_color_was_called(); + return _PyCursesStatelessCheckWasCalled(called, "start_color"); } static void * @@ -4881,9 +4979,9 @@ curses_capi_new(_cursesmodule_state *state) return NULL; } capi[0] = (void *)Py_NewRef(state->window_type); - capi[1] = curses_capi_setupterm_called; - capi[2] = curses_capi_initscr_called; - capi[3] = curses_capi_start_color_called; + capi[1] = curses_capi_setupterm_was_called; + capi[2] = curses_capi_initscr_was_called; + capi[3] = curses_capi_start_color_was_called; return (void *)capi; } @@ -4944,9 +5042,24 @@ curses_capi_capsule_new(void *capi) /* Module initialization */ +/* Indicate whether the module has been loaded or not. */ +static int curses_module_loaded = 0; + static int cursesmodule_exec(PyObject *module) { + if (_Py_atomic_load_int(&curses_module_loaded)) { + PyErr_SetString(PyExc_ImportError, + "module 'curses' can only be loaded once per process"); + return -1; + } + +#ifdef Py_GIL_DISABLED + _Py_atomic_store_int(&curses_module_loaded, 1); +#else + curses_module_loaded = 1; +#endif + _cursesmodule_state *state = get_cursesmodule_state(module); /* Initialize object type */ state->window_type = (PyTypeObject *)PyType_FromModuleAndSpec( From 39652af3b181749e1ec669b014b825b939e22d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 5 Oct 2024 10:57:59 +0200 Subject: [PATCH 2/4] regen objects --- Programs/test_frozenmain.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 624d9c0b653ad7..661ce867c1ce00 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -12,26 +12,26 @@ unsigned char M_test_frozenmain[] = { 0,0,111,6,88,2,31,0,79,6,88,6,12,0,79,7, 88,5,88,6,2,0,0,0,12,0,47,4,49,1,0,0, 0,0,0,0,29,0,72,22,0,0,9,0,29,0,100,1, - 41,8,233,0,0,0,0,78,122,18,70,114,111,122,101,110, - 32,72,101,108,108,111,32,87,111,114,108,100,122,8,115,121, + 41,8,233,0,0,0,0,78,218,18,70,114,111,122,101,110, + 32,72,101,108,108,111,32,87,111,114,108,100,218,8,115,121, 115,46,97,114,103,118,218,6,99,111,110,102,105,103,41,5, 218,12,112,114,111,103,114,97,109,95,110,97,109,101,218,10, 101,120,101,99,117,116,97,98,108,101,218,15,117,115,101,95, 101,110,118,105,114,111,110,109,101,110,116,218,17,99,111,110, 102,105,103,117,114,101,95,99,95,115,116,100,105,111,218,14, - 98,117,102,102,101,114,101,100,95,115,116,100,105,111,122,7, - 99,111,110,102,105,103,32,122,2,58,32,41,7,218,3,115, + 98,117,102,102,101,114,101,100,95,115,116,100,105,111,218,7, + 99,111,110,102,105,103,32,218,2,58,32,41,7,218,3,115, 121,115,218,17,95,116,101,115,116,105,110,116,101,114,110,97, 108,99,97,112,105,218,5,112,114,105,110,116,218,4,97,114, 103,118,218,11,103,101,116,95,99,111,110,102,105,103,115,114, - 3,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, + 5,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, 218,18,116,101,115,116,95,102,114,111,122,101,110,109,97,105, - 110,46,112,121,218,8,60,109,111,100,117,108,101,62,114,18, + 110,46,112,121,218,8,60,109,111,100,117,108,101,62,114,22, 0,0,0,1,0,0,0,115,94,0,0,0,240,3,1,1, 1,243,8,0,1,11,219,0,24,225,0,5,208,6,26,212, 0,27,217,0,5,128,106,144,35,151,40,145,40,212,0,27, 216,9,26,215,9,38,210,9,38,211,9,40,168,24,209,9, 50,128,6,243,2,6,12,2,128,67,241,14,0,5,10,136, 71,144,67,144,53,152,2,152,54,160,35,153,59,152,45,208, - 10,40,214,4,41,242,15,6,12,2,114,16,0,0,0, + 10,40,214,4,41,242,15,6,12,2,114,20,0,0,0, }; From f6dc91bc0ad86d6a858f95b70a2d683a5562036e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 5 Oct 2024 11:05:12 +0200 Subject: [PATCH 3/4] regen objects???? --- Programs/test_frozenmain.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 661ce867c1ce00..624d9c0b653ad7 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -12,26 +12,26 @@ unsigned char M_test_frozenmain[] = { 0,0,111,6,88,2,31,0,79,6,88,6,12,0,79,7, 88,5,88,6,2,0,0,0,12,0,47,4,49,1,0,0, 0,0,0,0,29,0,72,22,0,0,9,0,29,0,100,1, - 41,8,233,0,0,0,0,78,218,18,70,114,111,122,101,110, - 32,72,101,108,108,111,32,87,111,114,108,100,218,8,115,121, + 41,8,233,0,0,0,0,78,122,18,70,114,111,122,101,110, + 32,72,101,108,108,111,32,87,111,114,108,100,122,8,115,121, 115,46,97,114,103,118,218,6,99,111,110,102,105,103,41,5, 218,12,112,114,111,103,114,97,109,95,110,97,109,101,218,10, 101,120,101,99,117,116,97,98,108,101,218,15,117,115,101,95, 101,110,118,105,114,111,110,109,101,110,116,218,17,99,111,110, 102,105,103,117,114,101,95,99,95,115,116,100,105,111,218,14, - 98,117,102,102,101,114,101,100,95,115,116,100,105,111,218,7, - 99,111,110,102,105,103,32,218,2,58,32,41,7,218,3,115, + 98,117,102,102,101,114,101,100,95,115,116,100,105,111,122,7, + 99,111,110,102,105,103,32,122,2,58,32,41,7,218,3,115, 121,115,218,17,95,116,101,115,116,105,110,116,101,114,110,97, 108,99,97,112,105,218,5,112,114,105,110,116,218,4,97,114, 103,118,218,11,103,101,116,95,99,111,110,102,105,103,115,114, - 5,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, + 3,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, 218,18,116,101,115,116,95,102,114,111,122,101,110,109,97,105, - 110,46,112,121,218,8,60,109,111,100,117,108,101,62,114,22, + 110,46,112,121,218,8,60,109,111,100,117,108,101,62,114,18, 0,0,0,1,0,0,0,115,94,0,0,0,240,3,1,1, 1,243,8,0,1,11,219,0,24,225,0,5,208,6,26,212, 0,27,217,0,5,128,106,144,35,151,40,145,40,212,0,27, 216,9,26,215,9,38,210,9,38,211,9,40,168,24,209,9, 50,128,6,243,2,6,12,2,128,67,241,14,0,5,10,136, 71,144,67,144,53,152,2,152,54,160,35,153,59,152,45,208, - 10,40,214,4,41,242,15,6,12,2,114,20,0,0,0, + 10,40,214,4,41,242,15,6,12,2,114,16,0,0,0, }; From c876ae61b5b2a34004425fc299e3ec7c00e0562d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sat, 5 Oct 2024 11:40:00 +0200 Subject: [PATCH 4/4] update globals --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index a0be2a0a203f8c..687811b8c55e0a 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -358,7 +358,6 @@ Modules/_testclinic.c - TestClass - ##----------------------- ## static types -Modules/_cursesmodule.c - PyCursesWindow_Type - Modules/_datetimemodule.c - PyDateTime_DateTimeType - Modules/_datetimemodule.c - PyDateTime_DateType - Modules/_datetimemodule.c - PyDateTime_DeltaType - @@ -383,7 +382,6 @@ Modules/_tkinter.c - Tktt_Type - Modules/xxlimited_35.c - Xxo_Type - ## exception types -Modules/_cursesmodule.c - PyCursesError - Modules/_tkinter.c - Tkinter_TclError - Modules/xxlimited_35.c - ErrorObject - Modules/xxmodule.c - ErrorObject - @@ -413,6 +411,7 @@ Modules/_cursesmodule.c - curses_initscr_called - Modules/_cursesmodule.c - curses_setupterm_called - Modules/_cursesmodule.c - curses_start_color_called - Modules/_cursesmodule.c - curses_screen_encoding - +Modules/_cursesmodule.c - curses_module_loaded - Modules/_elementtree.c - expat_capi - Modules/readline.c - libedit_append_replace_history_offset - Modules/readline.c - using_libedit_emulation -