Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

system-clock-safe timers without time()?

by edan (Curate)
on Apr 13, 2003 at 12:54 UTC ( [id://250130]=perlquestion: print w/replies, xml ) Need Help??

edan has asked for the wisdom of the Perl Monks concerning the following question:

Monks,

I have a daemon that runs in a loop which is driven by a poll on several sockets, and a bunch of timers that go off on various intervals. I have implemented a simple timer mechanism by keeping a hash of timers, where each timer is represented by a code-ref for the function that should be called when the timer goes off, and the next time when the counter should go off. This is calculated by adding the timer's interval to the current time as returned by time(). This works great, except when someone changes the system clock... then all my timers are hopelessly out of whack!

So, I want to keep my current code as unchanged as possible, but insulate myself from system-clock changes. What suggestions do my fellow monks have for getting a tick every second without calling time()? I banged out the following code as a first shot:

my $counter; init_timer(); while(1) { select(undef, undef, undef, 0.5); print "$counter " . scalar(localtime) . "\n"; } sub init_timer { $counter = 0; $SIG{ALRM} = \&tick; alarm(1); } sub tick { alarm(1); $counter++; }

This seems to work, but I don't know if it is a good/safe way to do it... is it okay to set a new alarm from within the SIGALRM signal handler? Are there any other gotchas (besides not being able to intermix any sleep() calls in my program, which I don't do anyway)? Will it pretty reliably give me a tick every second (I don't need anything terribly HiRes at this point... if I ever do, I suppose it wouldn't be too hard to retrofit it with Time::HiRes...)

TIA

--
3dan

Replies are listed 'Best First'.
Re: system-clock-safe timers without time()?
by tachyon (Chancellor) on Apr 13, 2003 at 13:12 UTC

    Why not just teach your server admin(s) to sync their clocks using NTP? Then you don't have a problem.....

    As to the approach I would probably run a demon that just did:

    #!/usr/bin/perl my $start = time(); my $sleep = 600; my $how_much = 5; my $offset_file = '/tmp/offset.txt'; my $offset = 0; print_to_file( $offset ); while ( 1 ) { sleep($sleep); my $now = time(); if ( abs ( $start + $sleep - $now ) > $how_much ) { $offset = $start + $sleep - $now; print_to_file( $offset ); } $start = time(); } sub print_to_file { my $offset = shift; `echo $offset > $offset_file`; }

    In this approach we allow use 5 seconds of change in 10 minutes as our significance level. If the time has changed by more than this then someone has probably changed the clock so we write the offset to the offset file.... This is the general approach used by time limited software for instance that gets upset if you change the clock.

    Just check the offset file as needed. This should be less load and is not dependent on sleep(1) being exactly 1,000 msec. If it is not your clock will drift considerably over time.

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      You should be very wary of the first second of any sleep() call - as per the POSIX spec, this is allowed, and frequently is, somewhere between 0 and 1 seconds (being based on when the computers clock counds the end of a second. So whether your clock currently says 12:00:00.01 or 12:00:00.99, if you ask it to sleep 5, it will finish at 12:00:05.00 This is obviously less of a problem if you're asking it to sleep to just delay between two actions, but if you're using it to issue metronome clicks, then you get strange issues depending on how long it takes to do the processing between the sections.

      Getting back to the main question, I read the issue as being more about changing to summertime, rather than clock corrections. (probably because the clocks only changed recently) But either way it sounds like your sysadmin needs educating - for time correcting, use NTP as suggested. For summertime, the system clock itself shouldn't be changed, but users can have their timezones changed to match their requirements. Meanwhile, your script can set its timezone to something fixed ($ENV{'TZ'} = 'UTC' is my preference) and then it won't be bothered by daylight saving.

      the hatter

Re: system-clock-safe timers without time()?
by rob_au (Abbot) on Apr 14, 2003 at 02:45 UTC
    While not a solution, I would note that this issue is currently being discussed on the POE mailing list with reference to alarm and signal states within the POE kernel - It may be worth following this discussion over the next few weeks to see what the outcome there will be.

     

    perl -le 'print+unpack("N",pack("B32","00000000000000000000001001001001"))'

Re: system-clock-safe timers without time()?
by fizbin (Chaplain) on Apr 14, 2003 at 14:11 UTC

    This looks like a job for POSIX::times() - among other things, this call gives you the number of clock ticks since some time that is guaranteed to change only on system reboot. (Usually, this is the number of clock ticks since system reboot, but in theory it could use some different base time)

    This allows you to write something like this:

    use POSIX; sub mytime { my ($clock_ticks) = POSIX::sysconf(&POSIX::_SC_CLK_TCK); return ((POSIX::times())[0] / $clock_ticks); }

    which gives you the number of seconds since that base time. Rewriting it so that POSIX::sysconf is called only once is left as an exercise for the reader.

      fizbin++

      Great stuff - just what I was looking for - didn't know it existed until now - nice to have in my Bag O' Tricks.

      Thanks a bunch!!

      --
      3dan

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://250130]
Approved by tachyon
Front-paged by thelenm
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-16 22:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found