how does timer: deal with real-time clock changes?
Matthias Lang
matthias@REDACTED
Thu Mar 14 14:15:30 CET 2002
Ulf Wiger writes:
> The following code in timer.erl seems to define this behaviour:
> timer_timeout([{Time, BRef, {repeat, Interv, To}, MFA} | Ts],
> SysTime) ->
> do_apply(MFA),
> Ts0 = insert_sort({Time + Interv, BRef, %% <<==== here!
> {repeat, Interv, To}, MFA}, Ts),
> timer_timeout(Ts0, SysTime).
>
> Since it adds Interv (in your case, 1000 ms) to the calculated
> trigger time, instead of the actual trigger time, you will end up
> with an interval timer that acts like you describe....
>
> ...assuming that erlang:now() jumps around when the system clock
> is altered!
>
> I thought that erlang:now() had been adjusted on all platforms to
> adjust smoothly to changes to the system clock. This is the case
> on Solaris, at least. I do not see how the described behaviour
> could happen given a well-behaved erlang:now().
Your description of what's going on is perfect.
The problem is with the code which smoothes out time changes. There are
two versions in erl_time_sup.c, and the one used for Linux systems
starts like this
static void get_tolerant_timeofday(SysTimeval *tvp)
{
clock_t current_ct;
SysTimeval current_tv;
Milli ct_diff;
Milli tv_diff;
Milli current_correction;
long act_correction; /* Never more than a long (?) */
Milli max_adjust;
Milli is a typedef for a 64-bit integer. The comment points to the
root of the problem. In my case, huge adjustments (say, 2 months)
caused timers to fail, and smaller ones did not. And indeed, 2 months
of milliseconds (5184000000) does not fit in a 32 bit integer.
Changing act_correction's type to Milli fixes the problem. Any reason
why this shouldn't be put in to R8B-1?
Aside: it is fundamentally wrong to combine wall time with the base
used for time interval measurements if you cannot guarantee that wall
time is continuous. No system that allows manual time adjustment can
guarantee that. Smoothing out now() is a hack which we're probably
stuck with because of existing code which relies on now() being
continuous, including the timer() module.
A quick look at time.c suggests that the BIF timers
(e.g. erlang:send_after) are not related to now(). Does anyone
know if 'receive' timeouts are?
Matthias
More information about the erlang-questions
mailing list