summaryrefslogtreecommitdiff
path: root/appl/acme/time.b
blob: b5edda74a1852556bc90a426c51bcf9c68af1bf0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
implement Timerm;

include "common.m";

sys : Sys;
acme : Acme;
utils : Utils;
dat : Dat;

millisec : import sys;
Timer : import dat;

init(mods : ref Dat->Mods)
{
	sys = mods.sys;
	acme = mods.acme;
	utils = mods.utils;
	dat = mods.dat;
}

ctimer : chan of ref Timer;

timeproc()
{
	i, nt, na, dt : int;
	x : ref Timer;
	t : array of ref Timer;
	old, new : int;

	acme->timerpid = sys->pctl(0, nil);
	sys->pctl(Sys->FORKFD, nil);
	t = array[10] of ref Timer;
	na = 10;
	nt = 0;
	old = millisec();
	for(;;){
		if (nt == 0) {	# don't waste cpu time
			x = <-ctimer;
			t[nt++] = x;
			old = millisec();
		}
		sys->sleep(1);	# will sleep minimum incr 
		new = millisec();
		dt = new-old;
		old = new;
		if(dt < 0)	# timer wrapped; go around, losing a tick 
			continue;
		for(i=0; i<nt; i++){
			x = t[i];
			x.dt -= dt;
			if(x.dt <= 0){
				#
				# avoid possible deadlock if client is
				# now sending on ctimer
				#
				 
				alt {
					x.c <-= 0 =>
						t[i:] = t[i+1:nt];
						t[nt-1] = nil;
						nt--;
						i--;
					* =>
						;
				}
			}
		}
		gotone := 1;
		while (gotone) {
			alt {
				x = <-ctimer =>
					if (nt == na) {
						ot := t;
						t = array[na+10] of ref Timer;
						t[0:] = ot[0:na];
						ot = nil;
						na += 10;
					}
					t[nt++] = x;
					old = millisec();
				* =>
					gotone = 0;
			}
		}
	}
}

timerinit()
{
	ctimer = chan of ref Timer;
	spawn timeproc();
}

#
# timeralloc() and timerfree() don't lock, so can only be
# called from the main proc.
#
 

timer : ref Timer;

timerstart(dt : int) : ref Timer
{
	t : ref Timer;

	t = timer;
	if(t != nil)
		timer = timer.next;
	else{
		t = ref Timer;
		t.c = chan of int;
	}
	t.next = nil;
	t.dt = dt;
	ctimer <-= t;
	return t;
}

timerstop(t : ref Timer)
{
	t.next = timer;
	timer = t;
}

timerwaittask(timer : ref Timer)
{
	<-(timer.c);
	timerstop(timer);
}