Version 1 of Tcl event loop

Updated 2001-10-11 13:26:35

PURPOSE: Describe the operation of the Tcl event loop.


Tcl/Tk's event model is essentially single threaded. There is a main event loop (Tcl_DoOneEvent) that checks for work to do and handles that work by making callbacks. These callbacks are registered with the event loop by the after, fileevent and bind commands, by -command, -xscrollcommand, and similar options on widgets, and by various things within C code.

    Main
    Event ----+----> Callback from Tcl_DoWhenIdle (after idle)
    Loop      |
              +----> Callback from Tcl_CreateTimerHandler (after N)
              |
              +----> Callback from Tcl_CreateChannelHandler (fileevent)
              |
              +----> Callback from Tk_CreateEventHandler
              |      (bind, -command, etc)
              |
              +----> Other callbacks (Tk_CreateGenericHandler,
                     Tk_CreateErrorHandler, Tcl_EventuallyFree,
                     etc.)

The natural flow of the event loop is something like:

     Start
       |
       |<----------------------------------------------------------+
       v                                                           ^
   Do I have    No[*]  Calculate how            Sleep for at       |
   work to do?  -----> long I may sleep  -----> most that much --->|
       |                                        time               |
       | Yes                                                       |
       |                                                           |
       v                                                           |
   Do one callback                                                 |
       |                                                           |
       +-----------------------------------------------------------+

    [*] This may cause a return from the event loop if it was
        invoked recursively (see below)

multithreading because they cause more events to be processed. It is just an Commands like update, tkwait, and vwait give the illusion of multithreading because they cause more events to be processed. It is just an illusion.'' What they really do is to invoke the event loop recursively:

   event ---> Callback ---> update ---> event ---> callbacks
   Main                                 Main       More

   loop                                 loop       as needed
update
Enters the event loop and services both queues in the normal manner until all events remaining in the main queue are scheduled in the future and the idle queue is empty.
  • [update] simply does the calls until there are no more to do.
  • [update idletasks] does only [after idle] and [Tcl_DoWhenIdle] callbacks.
  • [vwait] runs the event loop, including going to sleep, until some code breaks it by assigning to the specified variable.
  • [tkwait] has various more complex termination conditions.

You need to be careful with these calls, or you can get bizarre results because your recursive call into the event loop has resulted in having the event loop make a recursive call to you. If you get into this kind of trouble, consider avoiding the four calls above and structuring your code to be callback-driven. This restructuring can be a tremendous cleaning of the stables; it's much better to structure callback-driven code from the very beginning. See Update considered harmful for some pointers on ways to do this.