# # timers # forsyth@caldo.demon.co.uk implement Timers; include "sys.m"; sys: Sys; include "timers.m"; timerin: chan of (int, ref Timer); Start, Stop, Finish: con iota; Timer.new(): ref Timer { return ref Timer(0, chan of int); } Timer.start(t: self ref Timer, dt: int) { t.dt = dt/Sec + 1; timerin <-= (Start, t); } Timer.stop(t: self ref Timer) { alt { timerin <-= (Stop, t)=> ; <-t.timeout => # lost race, but timer now stopped ; } } timeproc(req: chan of (int, ref Timer), ticks, acks: chan of int) { pending: list of ref Timer; Work: for(;;) alt{ (op, t) := <-req => case op { Start=> pending = t :: pending; Stop=> l := pending; pending = nil; for(; l != nil; l = tl l) if((hd l) != t) pending = (hd l) :: pending; Finish=> break Work; } <-ticks => acks <-= 1; l := pending; pending = nil; for(; l != nil; l = tl l){ t := hd l; t.dt--; if(t.dt <= 0) t.timeout <-= 1; else pending = t :: pending; } } for(; pending != nil; pending = tl pending) (hd pending).timeout <-= 1; <-ticks; # could killpid if the 1 second wait matters acks <-= 0; } # tickproc doesn't compensate for clock drift, # but it's adequate in my application tickproc(ticks, acks: chan of int) { do{ sys->sleep(Sec); ticks <-= 1; }while(<-acks); } init() { sys = load Sys Sys->PATH; timerin = chan of (int, ref Timer); ticks := chan of int; acks := chan of int; spawn timeproc(timerin, ticks, acks); spawn tickproc(ticks, acks); } shutdown() { timerin <-= (Finish, nil); }