xref: /inferno-os/appl/lib/timers.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
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