TIP: 302 Title: Fix "after"'s Sensitivity To Adjustments Of System Clock Version: $Revision: 1.3 $ Author: Alexandre Ferrieux Author: Kevin Kenny State: Draft Type: Project Vote: Pending Created: 13-Dec-2006 Post-History: Keywords: Tcl,time changes Tcl-Version: 8.7 ~ 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 news:comp.lang.tcl "[[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.