Mega Search
23.2 Million


Sign Up

Make a donation  
"after" timer script is never called if the system time is s  
News Group: comp.lang.tcl

Hello,

I develop an embedded system featuring some Tcl applications.

To update a clock view, I use a simple "label" widget and an "after 500"
script to update that widget's contents to the latest time. That works well
for the common use case. In the system, there is a second application
(modified tclhttpd) which I use to change the system clock (via the "date"
command). This works well, too.

However, whenever I change the system time *backwards*, the clock view
stalls. When I change back to the future time, it immediately restarts
updating the view.

I assume there is a problem with the "after" command I use. Is there a way
to solve this issue?

Kind regards

        Jan



Vote for best question.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 12:13 AM EST
From: Jan Kandziora
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
Alexandre Ferrieux schrieb:
> 
> What's wrong with times(2), which I mentioned in the TIP, and which
> needs no extra resource allocation, and just returns a tick count
> since some arbitrary point in the past ?
> 
Now that I read more about it, nothing. On first view, I had the impression
one could only get sys and user time, not real time by timer(). Wrong. A
lot of Posix calls have confusing semantics.


>> Have you already thought more deeply into TIP 302?
> 
> In fact, so far I've hoped that Kevin (the god of Time in Tcl
> scriptures) would kick in at some point and implement it between lunch
> and coffee. My experience with  the Tcl notifier nears zero *and* I'm
> lazy beyond what you can imagine :-)
> 
Well, ok.

Kind regards

        Jan

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 8:31 PM EST
From: Jan Kandziora
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
On Jan 18, 12:42 pm, Jan Kandziora  wrote:
> Alexandre Ferrieux schrieb:
>
> > This is a known problem in current timer implementation. See TIP 302:
>
> >      http://www.tcl.tk/cgi-bin/tct/tip/302.html
>
> Hmm. A have now read a bit about POSIX' timer_create(), which allows to
> create a CLOCK_MONOTONIC per process. If this works on at least a handful
> of systems, it could be a nearly *drop-in replacement* for gettimeofday().

What's wrong with times(2), which I mentioned in the TIP, and which
needs no extra resource allocation, and just returns a tick count
since some arbitrary point in the past ?

> Have you already thought more deeply into TIP 302?

In fact, so far I've hoped that Kevin (the god of Time in Tcl
scriptures) would kick in at some point and implement it between lunch
and coffee. My experience with  the Tcl notifier nears zero *and* I'm
lazy beyond what you can imagine :-)

-Alex

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 8:55 AM EST
From: Alexandre Ferrieux
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
On Jan 18, 2:59 am, Jan Kandziora  wrote:
> I came up with the following code snippet during the
> last few hours, which allows restarting of timers with approximated remaining
> times:

OK. The problem is that it works only when there is cooperation
between the app itself and the time-shifting operation. In my case it
never happens. Instead I just have a dozen of Tcl daemons with a 10-
sec self-reposting timer, and some idiot crontab job does ntpdate (or
worse, some user changes the date to one year before to investigate an
issue with an expired software license)...

-Alex


Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 8:47 AM EST
From: Alexandre Ferrieux
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
Alexandre Ferrieux schrieb:
> 
> This is a known problem in current timer implementation. See TIP 302:
> 
>      http://www.tcl.tk/cgi-bin/tct/tip/302.html
> 
Hmm. A have now read a bit about POSIX' timer_create(), which allows to
create a CLOCK_MONOTONIC per process. If this works on at least a handful
of systems, it could be a nearly *drop-in replacement* for gettimeofday().

Have you already thought more deeply into TIP 302?

Kind regards

        Jan

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 12:42 PM EST
From: Jan Kandziora
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
Andreas Leitgeb schrieb:

> Jan Kandziora  wrote:
>> In the system, there is a second application
>> (modified tclhttpd) which I use to change the system clock (via the
>> "date" command). This works well, too.
> 
> Is this just for daylight saving time, or do you really have a need
> to turn the clock ?
> 
I really have to turn the clock. This is an embedded system were the clock
is turned (though rarely) by an ordinary user, not a rugged sysadmin who
may be aware of problems.

Or say, the customers expect the computer clock to work like an ordinary
alarm clock, with timers etc. unaffected...

Kind regards

        Jan




Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 12:20 PM EST
From: Jan Kandziora
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
Jan Kandziora  wrote:
> In the system, there is a second application
> (modified tclhttpd) which I use to change the system clock (via the "date"
> command). This works well, too.

Is this just for daylight saving time, or do you really have a need
to turn the clock ?

If DST is the thing, then just use a UTC-based clock, instead.
If the clock really needs to be manipulated, then the other
two followups apply (shell-sleep and the TIP).


Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 10:35 AM EST
From: Andreas Leitgeb
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
Alexandre Ferrieux schrieb:
> 
> This is a known problem in current timer implementation. See TIP 302:
> 
>      http://www.tcl.tk/cgi-bin/tct/tip/302.html
> 
> you can even manifest your interest on the Tcl-core mailing list ;-)
>
I will do, even if I'm just a me-too'er then... >_<;


> 
> As to workarounds, my favourite is to use an external program not
> crippled by this problem.
> In unix, "sleep" (binary or sh built-in) may serve this purpose since
> it is based on relative timers, not recomputed through a slippery
> gettimeofday(). So just spawn an sh pipe, and tell it to sleep and
> echo in a loop (Sorry but you won't get faster than 1 Hz. A bit slow
> for a clock.):
> 
>            set ff [open {|sh -c {while :;do echo blip;sleep 1;done}
> 2>@ stderr} r]
>            fileevent $ff readable gotblip
>            proc gotblip {} {
>              if {[gets $::ff line]<0} {fatal "Unexpected EOF from sh"}
>              # do your stuff
>            }
> 
Hm. That should work. I came up with the following code snippet during the
last few hours, which allows restarting of timers with approximated remaining
times:


rename after tcl_after
proc after {command args} {
  switch -exact -- $command {
    cancel - idle - info { eval tcl_after "$command" $args }
    restart { eval ::after_restart::restart $args }
    default { eval ::after_restart::after "$command" $args }
  }
}

namespace eval after_restart {
  set timer_unique 0
  array set timers {}

  proc after {ms args} {
    variable timer_unique
    variable timers

    set after_id [ ::tcl_after $ms ::after_restart::trigger $timer_unique $args ]
    set timers($timer_unique) [ list $after_id [ expr [ clock seconds ] + $ms/1000 ] ]
    incr timer_unique

    return $after_id
  }

  proc trigger {unique args} {
    variable timers

    uplevel #0 $args
    unset -nocomplain timers($unique)
  }

  proc restart {adjust_time} {
    variable timers

    foreach {unique timer_data} [ array get timers ] {
      set old_after_id [ lindex $timer_data 0 ]
      set old_trigger_time [ lindex $timer_data 1 ]

      set remaining_time [ expr $old_trigger_time - $adjust_time ]
      if { $remaining_time < 0 } { set remaining_time 0 }

      set timer_script [ lindex [ ::tcl_after info $old_after_id ] 0 ]
      ::tcl_after cancel $old_after_id
      set new_after_id [ eval ::tcl_after [ expr $remaining_time*1000 ] $timer_script ]

      set timers($unique) [ list $new_after_id [ expr [ clock seconds ] + $remaining_time ] ]
    }
  }
}


With this extension, the "after" command works as before, but has a new "restart" subcommand.
It should be used as follows:


after 100000 puts "Done!"
....
set now [ clock seconds ]
exec date -s ...
after restart $now


Then the timers are restarted appropiately for the new timeline. Something for the wiki?

Kind regards

        Jan




Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 2:59 AM EST
From: Jan Kandziora
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
On Jan 18, 12:13 am, Jan Kandziora  wrote:
>
> However, whenever I change the system time *backwards*, the clock view
> stalls. When I change back to the future time, it immediately restarts
> updating the view.

This is a known problem in current timer implementation. See TIP 302:

     http://www.tcl.tk/cgi-bin/tct/tip/302.html

you can even manifest your interest on the Tcl-core mailing list ;-)

As to workarounds, my favourite is to use an external program not
crippled by this problem.
In unix, "sleep" (binary or sh built-in) may serve this purpose since
it is based on relative timers, not recomputed through a slippery
gettimeofday(). So just spawn an sh pipe, and tell it to sleep and
echo in a loop (Sorry but you won't get faster than 1 Hz. A bit slow
for a clock.):

           set ff [open {|sh -c {while :;do echo blip;sleep 1;done}
2>@ stderr} r]
           fileevent $ff readable gotblip
           proc gotblip {} {
             if {[gets $::ff line]<0} {fatal "Unexpected EOF from sh"}
             # do your stuff
           }

-Alex

Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 17-Jan-2008, at 4:31 PM EST
From: Alexandre Ferrieux
 
Re: "after" timer script is never called if the system time  
News Group: comp.lang.tcl
Dennis LaBelle schrieb:
> 
> In this case, you should cancel the after event (see the [after cancel]
> syntax in the documentation) and reissue the [after] command right after
> completing the clock "date" change.
> 
That was my first idea, but it opens a new problem, because the time is
changed in *another* application. Ok, sending a signal with kill from one
application too another should work.

I suspect there is no way finding out when the clock was changed? To make it
more complicated, there are more timers in other applications. They will
stall too, right? Then I have to work out a wrapper for "after" which keeps
track of timers and eventually restarts them on demand...


Too bad "after info " only reports type and script, not the issuing and
estimated firing time of a timer. That way, a long duration timer could be
restarted with a time period shortened to the approximated new firing time.
Ok, I could handle all this in the wrapper, but that at least the firing
time is stored anyway.


Is there a wiki page for proposals of new useful functions in Tcl?


Kind regards

        Jan


Vote for best answer.
Score: 0  # Vote:  0
Date Posted: 18-Jan-2008, at 12:58 AM EST
From: Jan Kandziora