diff --git a/Misc/NEWS.d/next/Library/2026-07-13-10-37-32.gh-issue-153020.eventTs.rst b/Misc/NEWS.d/next/Library/2026-07-13-10-37-32.gh-issue-153020.eventTs.rst new file mode 100644 index 00000000000000..1dd8485ade4620 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-13-10-37-32.gh-issue-153020.eventTs.rst @@ -0,0 +1,2 @@ +Fix a data race in :mod:`!_tkinter` input event handling in free-threaded +builds. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index f5fb1841f0d594..a5f8b2754a6216 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -31,6 +31,7 @@ Copyright (C) 1994 Steen Lumholt. #endif #include "pycore_long.h" // _PyLong_IsNegative() +#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_PTR, FT_ATOMIC_STORE_PTR #include "pycore_unicodeobject.h" // _PyUnicode_AsUTF8String #ifdef MS_WINDOWS @@ -3655,7 +3656,7 @@ EventHook(void) int tfile; stdin_ready = 0; #endif - PyEval_RestoreThread(event_tstate); + PyEval_RestoreThread(FT_ATOMIC_LOAD_PTR(event_tstate)); errorInCmd = 0; #ifdef MS_WINDOWS hStdin = GetStdHandle(STD_INPUT_HANDLE); @@ -3687,7 +3688,7 @@ EventHook(void) #endif Py_BEGIN_ALLOW_THREADS if(tcl_lock)PyThread_acquire_lock(tcl_lock, 1); - tcl_tstate = event_tstate; + tcl_tstate = FT_ATOMIC_LOAD_PTR(event_tstate); result = Tcl_DoOneEvent(TCL_DONT_WAIT); @@ -3725,7 +3726,7 @@ EnableEventHook(void) { #ifdef WAIT_FOR_STDIN if (PyOS_InputHook == NULL) { - event_tstate = PyThreadState_Get(); + FT_ATOMIC_STORE_PTR(event_tstate, PyThreadState_Get()); PyOS_InputHook = EventHook; } #endif @@ -3737,6 +3738,7 @@ DisableEventHook(void) #ifdef WAIT_FOR_STDIN if (Tk_GetNumMainWindows() == 0 && PyOS_InputHook == EventHook) { PyOS_InputHook = NULL; + FT_ATOMIC_STORE_PTR(event_tstate, NULL); } #endif }