1*37da2899SCharles.Forsythimplement Timers; 2*37da2899SCharles.Forsyth 3*37da2899SCharles.Forsythinclude "sys.m"; 4*37da2899SCharles.Forsyth sys: Sys; 5*37da2899SCharles.Forsyth 6*37da2899SCharles.Forsythinclude "timers.m"; 7*37da2899SCharles.Forsyth 8*37da2899SCharles.Forsythtimerin: chan of ref Timer; 9*37da2899SCharles.Forsyth 10*37da2899SCharles.Forsythinit(minms: int): int 11*37da2899SCharles.Forsyth{ 12*37da2899SCharles.Forsyth sys = load Sys Sys->PATH; 13*37da2899SCharles.Forsyth timerin = chan[20] of ref Timer; 14*37da2899SCharles.Forsyth if(minms <= 0) 15*37da2899SCharles.Forsyth minms = 1; 16*37da2899SCharles.Forsyth pid := chan of int; 17*37da2899SCharles.Forsyth spawn timeproc(timerin, minms, pid); 18*37da2899SCharles.Forsyth return <-pid; 19*37da2899SCharles.Forsyth} 20*37da2899SCharles.Forsyth 21*37da2899SCharles.Forsythshutdown() 22*37da2899SCharles.Forsyth{ 23*37da2899SCharles.Forsyth if(timerin != nil) 24*37da2899SCharles.Forsyth timerin <-= nil; 25*37da2899SCharles.Forsyth} 26*37da2899SCharles.Forsyth 27*37da2899SCharles.ForsythTimer.start(dt: int): ref Timer 28*37da2899SCharles.Forsyth{ 29*37da2899SCharles.Forsyth t := ref Timer(dt, chan[1] of int); 30*37da2899SCharles.Forsyth timerin <-= t; 31*37da2899SCharles.Forsyth return t; 32*37da2899SCharles.Forsyth} 33*37da2899SCharles.Forsyth 34*37da2899SCharles.ForsythTimer.stop(t: self ref Timer) 35*37da2899SCharles.Forsyth{ 36*37da2899SCharles.Forsyth # this is safe, because only Timer.stop sets t.timeout and timeproc only fetches it 37*37da2899SCharles.Forsyth t.timeout = nil; 38*37da2899SCharles.Forsyth} 39*37da2899SCharles.Forsyth 40*37da2899SCharles.Forsythtimeproc(req: chan of ref Timer, msec: int, pid: chan of int) 41*37da2899SCharles.Forsyth{ 42*37da2899SCharles.Forsyth pending: list of ref Timer; 43*37da2899SCharles.Forsyth 44*37da2899SCharles.Forsyth pid <-= sys->pctl(Sys->NEWFD|Sys->NEWNS|Sys->NEWENV, nil); # same pgrp 45*37da2899SCharles.Forsyth old := sys->millisec(); 46*37da2899SCharles.ForsythWork: 47*37da2899SCharles.Forsyth for(;;){ 48*37da2899SCharles.Forsyth if(pending == nil){ 49*37da2899SCharles.Forsyth if((t := <-req) == nil) 50*37da2899SCharles.Forsyth break Work; 51*37da2899SCharles.Forsyth pending = t :: pending; 52*37da2899SCharles.Forsyth old = sys->millisec(); 53*37da2899SCharles.Forsyth }else{ 54*37da2899SCharles.Forsyth # check quickly for new requests 55*37da2899SCharles.Forsyth Check: 56*37da2899SCharles.Forsyth for(;;) alt{ 57*37da2899SCharles.Forsyth t := <-req => 58*37da2899SCharles.Forsyth if(t == nil) 59*37da2899SCharles.Forsyth break Work; 60*37da2899SCharles.Forsyth pending = t :: pending; 61*37da2899SCharles.Forsyth * => 62*37da2899SCharles.Forsyth break Check; 63*37da2899SCharles.Forsyth } 64*37da2899SCharles.Forsyth } 65*37da2899SCharles.Forsyth sys->sleep(msec); 66*37da2899SCharles.Forsyth new := sys->millisec(); 67*37da2899SCharles.Forsyth dt := new-old; 68*37da2899SCharles.Forsyth old = new; 69*37da2899SCharles.Forsyth if(dt < 0) 70*37da2899SCharles.Forsyth continue; # millisec counter wrapped 71*37da2899SCharles.Forsyth ticked := 0; 72*37da2899SCharles.Forsyth for(l := pending; l != nil; l = tl l) 73*37da2899SCharles.Forsyth if(((hd l).dt -= dt) <= 0) 74*37da2899SCharles.Forsyth ticked = 1; 75*37da2899SCharles.Forsyth if(ticked){ 76*37da2899SCharles.Forsyth l = pending; 77*37da2899SCharles.Forsyth pending = nil; 78*37da2899SCharles.Forsyth for(; l != nil; l = tl l){ 79*37da2899SCharles.Forsyth t := hd l; 80*37da2899SCharles.Forsyth if(t.dt > 0 || !notify(t)) 81*37da2899SCharles.Forsyth pending = t :: pending; 82*37da2899SCharles.Forsyth } 83*37da2899SCharles.Forsyth } 84*37da2899SCharles.Forsyth } 85*37da2899SCharles.Forsyth # shut down: attempt to clear pending requests 86*37da2899SCharles.Forsyth for(; pending != nil; pending = tl pending) 87*37da2899SCharles.Forsyth notify(hd pending); 88*37da2899SCharles.Forsyth} 89*37da2899SCharles.Forsyth 90*37da2899SCharles.Forsythnotify(t: ref Timer): int 91*37da2899SCharles.Forsyth{ 92*37da2899SCharles.Forsyth # copy to c to avoid race with Timer.stop 93*37da2899SCharles.Forsyth if((c := t.timeout) == nil) 94*37da2899SCharles.Forsyth return 1; # cancelled; consider it done 95*37da2899SCharles.Forsyth alt{ 96*37da2899SCharles.Forsyth c <-= 1 => return 1; 97*37da2899SCharles.Forsyth * => return 0; 98*37da2899SCharles.Forsyth } 99*37da2899SCharles.Forsyth} 100