TIP #302: FIX "AFTER"'S SENSITIVITY TO ADJUSTMENTS OF SYSTEM CLOCK ==================================================================== Version: $Revision: 1.3 $ Author: Alexandre Ferrieux Kevin Kenny State: Draft Type: Project Tcl-Version: 8.7 Vote: Pending Created: Wednesday, 13 December 2006 URL: https://tip.tcl-lang.org302.html Post-History: ------------------------------------------------------------------------- ABSTRACT ========== Currently, *after* tasks can be drastically delayed or sped up simply by adjusting the system clock. This is due to the implementation's use of an /absolute/ target date based on the system clock. The idea of this TIP is to use another timebase for this purpose: the count of ticks from boot, which is not affected by system time adjustments. BACKGROUND ============ The basis of the implementation of *after* is, on each call to *vwait*, to compute the /timeout/ argument to select() by difference between the stored target date of the earliest event and the current system date (/gettimeofday()/). This is perfect while the system date ticks regularly. But if, say, the clock is set back by 5 minutes, then an after handler scheduled 1 second ago which was just about to fire, will have 5 minutes yet to wait before its (unmodified) target date is reached. So, if this handler was part of a 1-Hz periodic task, there will be a huge gap of 5:01 between two ticks at that point. If some other component is expecting some kind of regularity, even with a conservative timeout of 10 times the expected period, it /will/ time out, decide the periodic task is dead, and possibly take drastic action. PROPOSED CHANGE ================= This TIP proposes to use other timebases instead of gettimeofday() in the vwait/after code: *times()* in unix, *GetTickCount()* in Windows. These clocks suffer /no/ sysadmin tinkering. POTENTIAL BREAK OF COMPATIBILITY ================================== It has been objected that /some/ applications today may be using *after* with an /absolute/ spirit; IOW such apps are supposed to /rely/ on the fact that the after handler will fire when the system clock equals the target date computed once for all when *after* was called. A prototype example would be a crontab-like task, which would itself compute the offset by difference between the target date and the current *clock seconds*. ARGUMENTS FOR BREAKING IT ANYWAY ---------------------------------- 1. This /absolute/ interpretation is far from being natural, because *after*'s argument is an /offset/. 2. This technique is not usable for a longer range than 25 days (MAXINT milliseconds), so not applicable e.g. for a personal schedule. 3. The *overwhelming* majority of uses of *after* takes the /relative/ interpretation (periodic tasks, timeouts) and /cannot/ work correctly today. 4. If this TIP were implemented incompatibly (i.e. without a specific flag to *after*), those /absolute-minded/ apps could simply be adapted /and/ improved in both robustness and range by using a periodic task which polls *clock seconds*. 5. There is little evidence that the total number of /absolute-minded/ apps exceeds *one* (see discussion on "[after] fooled by shifting date") SYNTAX FOR NOT BREAKING IT IF DEEMED USEFUL ============================================= Of course, if this supposed singleton is in fact many, or has enough weight to preclude an improvement of the rest of Tcl timers, we can do: *after -robust* /millisecs/ or any other colorful option name. But in this case there is a high risk that: /either/ *after -robust* becomes the dominant use, thus cluttering the code in many places, /or/ people remain largely unaware of the problem, stick to the default *after*, and space shuttles fall by dozens. ESCALATION TO THE TCT ======================= I'll leave it to the TCT to arbitrate, and decide whether /fixing/ a widely used core primitive can outweigh breaking a rare and clumsy use. REFERENCE IMPLEMENTATION ========================== I have not yet written a reference implementation; I assume somebody with a more fluent practice of the core will do so more efficiently. However, gentle arm twisting, etc. COPYRIGHT =========== This document has been placed in the public domain. COMMENTS ========== The /times/ function in Unix is /not/ an appropriate time base. It reports the user and system time (CPU time, in other words) of the currently executing process and its children. As far as I have been able to determine, Unix assumes that the system time reported by /gettimeofday/ is the sole time base for absolute timing; if multiple timers are required in a single process, /gettimeofday/ appears to be the only reference that is available. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows