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
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
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
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
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
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
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
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
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
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