timers: allow timers to re-use threads when restarted, simplify.

Throw an error if started twice.
fix-linux
John Benediktsson 2019-12-13 15:31:49 -08:00
parent 1959c68feb
commit cc15116323
2 changed files with 61 additions and 66 deletions

View File

@ -1,6 +1,6 @@
USING: timers timers.private calendar concurrency.count-downs USING: accessors calendar combinators concurrency.count-downs
concurrency.promises fry kernel math math.order sequences concurrency.promises fry kernel math math.order sequences
threads tools.test tools.time ; threads timers tools.test tools.time ;
{ } [ { } [
1 <count-down> 1 <count-down>
@ -74,3 +74,20 @@ threads tools.test tools.time ;
dup restart-timer drop dup restart-timer drop
700 milliseconds sleep 700 milliseconds sleep
] unit-test ] unit-test
{ { 1 } t t t t } [
{ 0 }
dup '[ 0 _ [ 1 + ] change-nth ] 300 milliseconds f <timer>
dup start-timer [ thread>> ] keep {
[ dup restart-timer thread>> eq? ]
[ dup restart-timer thread>> eq? ]
[ dup restart-timer thread>> eq? ]
[ dup restart-timer thread>> eq? ]
} 2cleave
700 milliseconds sleep
] unit-test
[
[ ] 1 seconds later start-timer
] [ timer-already-started? ] must-fail-with

View File

@ -1,17 +1,17 @@
! Copyright (C) 2005, 2008 Slava Pestov, Doug Coleman. ! Copyright (C) 2005, 2008 Slava Pestov, Doug Coleman.
! See http://factorcode.org/license.txt for BSD license. ! See http://factorcode.org/license.txt for BSD license.
USING: accessors calendar combinators.short-circuit fry kernel
math math.functions quotations system threads typed ; USING: accessors calendar fry kernel math quotations system
threads ;
IN: timers IN: timers
TUPLE: timer TUPLE: timer
{ quot callable initial: [ ] } { quot callable initial: [ ] }
start-nanos
delay-nanos delay-nanos
interval-nanos interval-nanos
iteration-start-nanos next-nanos
quotation-running? quotation-running?
restart?
thread ; thread ;
<PRIVATE <PRIVATE
@ -21,60 +21,42 @@ M: f >nanoseconds ;
M: real >nanoseconds >integer ; M: real >nanoseconds >integer ;
M: duration >nanoseconds duration>nanoseconds >integer ; M: duration >nanoseconds duration>nanoseconds >integer ;
TYPED: set-next-timer-time ( timer: timer -- timer ) : delay-nanos ( timer -- n )
! start + delay + ceiling((now - (start + delay)) / interval) * interval delay-nanos>> 0 or nano-count + ;
nano-count
over start-nanos>> -
over delay-nanos>> [ - ] when*
over interval-nanos>> / ceiling
over interval-nanos>> *
over start-nanos>> +
over delay-nanos>> [ + ] when*
>>iteration-start-nanos ;
TYPED: stop-timer? ( timer: timer -- ? ) : interval-nanos ( timer -- n/f )
{ [ thread>> self eq? not ] [ restart?>> ] } 1|| ; inline [ next-nanos>> nano-count over - ] [ interval-nanos>> ] bi
[ dupd [ mod ] [ swap - ] bi + + ] [ 2drop f ] if* ;
DEFER: call-timer-loop : next-nanos ( timer -- timer n/f )
dup thread>> self eq? [
dup next-nanos>> dup t eq? [
drop dup delay-nanos [ >>next-nanos ] keep
] when
] [ f ] if ;
TYPED: loop-timer ( timer: timer -- ) : run-timer ( timer -- timer )
nano-count over dup interval-nanos >>next-nanos
[ iteration-start-nanos>> - ] [ interval-nanos>> ] bi < t >>quotation-running?
[ set-next-timer-time ] dip dup quot>> call( -- )
[ dup iteration-start-nanos>> ] [ 0 ] if f >>quotation-running? ;
0 or sleep-until call-timer-loop ;
TYPED: maybe-loop-timer ( timer: timer -- ) : timer-loop ( timer -- )
dup { [ stop-timer? ] [ interval-nanos>> not ] } 1|| [ next-nanos ] [
[ drop ] [ loop-timer ] if ; dup nano-count <= [
drop run-timer yield
] [
sleep-until
] if
] while* dup thread>> self eq? [ f >>thread ] when drop ;
TYPED: call-timer-loop ( timer: timer -- ) : ?interrupt ( thread timer -- )
dup stop-timer? [ quotation-running?>> [ drop ] [ [ interrupt ] when* ] if ;
drop
] [
[
[ t >>quotation-running? drop ]
[ quot>> call( -- ) ]
[ f >>quotation-running? drop ] tri
] keep
maybe-loop-timer
] if ;
TYPED: sleep-delay ( timer: timer -- )
dup stop-timer? [
drop
] [
nano-count >>start-nanos
delay-nanos>> [ sleep ] when*
] if ;
TYPED: timer-loop ( timer: timer -- )
[ sleep-delay ]
[ nano-count >>iteration-start-nanos call-timer-loop ]
[ dup restart?>> [ f >>restart? timer-loop ] [ drop ] if ] tri ;
PRIVATE> PRIVATE>
ERROR: timer-already-started timer ;
: <timer> ( quot delay-duration/f interval-duration/f -- timer ) : <timer> ( quot delay-duration/f interval-duration/f -- timer )
timer new timer new
swap >nanoseconds >>interval-nanos swap >nanoseconds >>interval-nanos
@ -82,20 +64,19 @@ PRIVATE>
swap >>quot ; inline swap >>quot ; inline
: start-timer ( timer -- ) : start-timer ( timer -- )
[ dup thread>> [ timer-already-started ] when
'[ _ timer-loop ] "Timer execution" spawn t >>next-nanos
] keep thread<< ; dup '[ _ timer-loop ] "Timer" <thread>
[ >>thread drop ] [ (spawn) ] bi ;
: stop-timer ( timer -- ) : stop-timer ( timer -- )
dup quotation-running?>> [ [ f ] change-thread ?interrupt ;
dup thread>> [ interrupt ] when*
] unless f >>thread drop ;
: restart-timer ( timer -- ) : restart-timer ( timer -- )
dup quotation-running?>> [ dup thread>> [
t >>restart? drop t >>next-nanos [ thread>> ] [ ?interrupt ] bi
] [ ] [
dup thread>> [ interrupt ] when* start-timer start-timer
] if ; ] if ;
<PRIVATE <PRIVATE
@ -106,13 +87,10 @@ PRIVATE>
PRIVATE> PRIVATE>
: every ( quot interval-duration -- timer ) : every ( quot interval-duration -- timer )
[ f ] dip (start-timer) ; f swap (start-timer) ;
: later ( quot delay-duration -- timer ) : later ( quot delay-duration -- timer )
f (start-timer) ; f (start-timer) ;
: delayed-every ( quot duration -- timer ) : delayed-every ( quot duration -- timer )
dup (start-timer) ; dup (start-timer) ;
: nanos-since ( nano-count -- nanos )
[ nano-count ] dip - ;