Ticket UUID: | 0221b993a19fd8d1b72db4e79286c0861e7eb83c | |||
Title: | Tcl command [update idletasks] doesn't skip main loop in Tcl_DoOneEvent | |||
Type: | Bug | Version: | 8.6.11 | |
Submitter: | erikleunissen | Created on: | 2021-03-15 19:09:33 | |
Subsystem: | 02. Event Loops | Assigned To: | jan.nijtmans | |
Priority: | 5 Medium | Severity: | Important | |
Status: | Closed | Last Modified: | 2021-06-04 20:28:02 | |
Resolution: | Fixed | Closed By: | dgp | |
Closed on: | 2021-06-04 20:28:02 | |||
Description: |
Nonwithstanding the intention in the comment, the following code snippet from Tcl_DoOneEvent(): /* * If idle events are the only things to service, skip the main part * of the loop and go directly to handle idle events (i.e. don't wait * even if TCL_DONT_WAIT isn't set). */ if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) { flags = flags | TCL_DONT_WAIT; goto idleEvents; } is bypassed for [update idletasks] because of the presence of the TCL_WINDOW_EVENTS bit in the flags argument, which Tcl_DoOneEvent() receives from Tcl_UpdateObjCmd(): switch ((enum updateOptions) optionIndex) { case OPT_IDLETASKS: flags = TCL_WINDOW_EVENTS|TCL_IDLE_EVENTS|TCL_DONT_WAIT; <=== *** break; default: Tcl_Panic("Tcl_UpdateObjCmd: bad option index to UpdateOptions"); } I find the presence of TCL_WINDOW_EVENTS in that flags variable suspect. What window events anyway? Especially when comparing with the Tk counterpart Tk_UpdateObjCmd(). In Tk, windows do play a role, but even here the TCL_WINDOW_EVENTS bit is not passed when "update idletasks" is invoked: if (objc == 1) { flags = TCL_DONT_WAIT; } else if (objc == 2) { if (Tcl_GetIndexFromObj(interp, objv[1], updateOptions, "option", 0, &index) != TCL_OK) { return TCL_ERROR; } flags = TCL_IDLE_EVENTS; <=== *** } else { Tcl_WrongNumArgs(interp, 1, objv, "?idletasks?"); return TCL_ERROR; } | |||
User Comments: |
dgp added on 2021-06-04 20:28:02:
Should tcl.h continue to define TCL_WINDOW_EVENTS ? Should there continue to be a testing subcommand [testfilehandler windowevent] ? jan.nijtmans added on 2021-03-19 15:01:33: Merged to core-8-branch and trunk jan.nijtmans added on 2021-03-18 13:21:29: Proposal now committed to the "bug-0221b993a1" branch jan.nijtmans added on 2021-03-17 08:30:23: Since TCL_WINDOW_EVENTS are really Tk events, I see no harm in removing TCL_WINDOW_EVENTS, as @erikleunissen suggests. Still, to prevent any risk (maybe other extensions could register TCL_WINDOW_EVENTS ...) I suggest to make this change only in Tcl 8.7+. Any objections? erikleunissen added on 2021-03-16 18:15:36: Corroborating the misbehaviour: I've put a printf() inside the crucial code snippet in Tcl_DoOneEvent(), like: if ((flags & TCL_ALL_EVENTS) == TCL_IDLE_EVENTS) { printf("***\n"); flags = TCL_IDLE_EVENTS | TCL_DONT_WAIT; goto idleEvents; } This printf() is skipped by [update idletasks] in a tclsh, but after loading Tk (which has a different implementation of the "update" command), the printf() statement is executed. This confirms my suspicion, that [update idletasks], called from tclsh (no Tk loaded) doesn't skip what it should skip inside Tcl_DoOneEVent(). The consequences are probably not as severe as that it services timer and file events, but it does carry out a bunch of useless work (harmful work not excluded), like checking inappropriate event sources. The remedy is simple (stripping the offending TCL_WINDOW_EVENTS inside Tcl_UpdateObjCmd() ). A patch (against tcl8.6.11) is provided anyway to prevent any ambiguity. erikleunissen added on 2021-03-15 19:34:41: > Therefore, upgrading priority to important. Uhmm, I mean: severity erikleunissen added on 2021-03-15 19:33:44: If I am right, the consequence is that all along [update idletasks] has been servicing events from sources that it should ignore: timer events and file events. Therefore, upgrading priority to important. |
Attachments:
- idletasks-bug.patch [download] added by erikleunissen on 2021-03-16 18:16:17. [details]