https://github.com/python/cpython/commit/c2fedeaa6d30e25a5dce90bdf112954637988c29 commit: c2fedeaa6d30e25a5dce90bdf112954637988c29 branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-06-26T18:01:09+03:00 summary:
[3.14] gh-139145: Fix tkinter event loop in interactive mode (GH-152257) (GH-152292) When a Tcl command running its own event loop (such as vwait or wait_variable) was active and the user typed input on stdin, the event loop kept spinning at 100% CPU. The stdin file handler is now removed as soon as input becomes available. Also fix gh-139816: an exception raised in a callback no longer stops the event loop to wait for Enter on a Python built without readline; pending callbacks keep running until input is actually available on stdin. (cherry picked from commit 3ffda34f5cd3809a8755c9596948e4e477661d5f) Co-authored-by: Serhiy Storchaka <[email protected]> Co-authored-by: mdehoon <[email protected]> Co-authored-by: Christopher Chavez <[email protected]> Co-authored-by: Claude Opus 4.8 <[email protected]> files: A Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst A Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst M Modules/_tkinter.c diff --git a/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst b/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst new file mode 100644 index 00000000000000..3fa639c5f727ba --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-14-32-42.gh-issue-139145.kT9rmP.rst @@ -0,0 +1,5 @@ +Fix a busy loop in :mod:`tkinter` on interactive Python. When a Tcl command +running its own event loop (such as ``vwait`` or :meth:`!wait_variable`) was +active and input arrived on stdin, the event loop kept spinning at 100% CPU. +The stdin file handler is now removed as soon as input is available. Based on +a patch by Michiel de Hoon. diff --git a/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst b/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst new file mode 100644 index 00000000000000..b180dee686caf8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-25-14-32-43.gh-issue-139816.Lq2vXa.rst @@ -0,0 +1,4 @@ +Fix a hang in :mod:`tkinter` on interactive Python built without +:mod:`readline`. An exception raised in a callback no longer causes the +event loop to stop and wait for the user to press Enter; pending callbacks +now keep running until input is actually available on stdin. diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 365398fa2389fc..7e7a3ad144346b 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -3392,7 +3392,13 @@ static int stdin_ready = 0; static void MyFileProc(void *clientData, int mask) { + int tfile = (int)(Py_intptr_t)clientData; stdin_ready = 1; + /* Stop watching stdin now that input is available. Doing it here rather + than after the loop below ensures that a nested event loop (e.g. the one + started by wait_variable) does not keep waking up on the same unread + input, spinning at 100% CPU. */ + Tcl_DeleteFileHandler(tfile); } #endif @@ -3409,9 +3415,10 @@ EventHook(void) errorInCmd = 0; #ifndef MS_WINDOWS tfile = fileno(stdin); - Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, NULL); + Tcl_CreateFileHandler(tfile, TCL_READABLE, MyFileProc, + (void *)(Py_intptr_t)tfile); #endif - while (!errorInCmd && !stdin_ready) { + while (!stdin_ready) { int result; #ifdef MS_WINDOWS if (_kbhit()) { @@ -3431,18 +3438,23 @@ EventHook(void) Sleep(Tkinter_busywaitinterval); Py_END_ALLOW_THREADS + /* Report an exception raised in a callback, but keep pumping events + instead of returning to the prompt: without readline there is no + input waiting on stdin yet, so returning here would block in fgets + until the user hits enter, freezing later callbacks. */ + if (errorInCmd) { + errorInCmd = 0; + PyErr_SetRaisedException(excInCmd); + excInCmd = NULL; + PyErr_Print(); + } if (result < 0) break; } #ifndef MS_WINDOWS - Tcl_DeleteFileHandler(tfile); + if (!stdin_ready) + Tcl_DeleteFileHandler(tfile); #endif - if (errorInCmd) { - errorInCmd = 0; - PyErr_SetRaisedException(excInCmd); - excInCmd = NULL; - PyErr_Print(); - } PyEval_SaveThread(); return 0; } _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
