Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "ureg.h"
8
#include "../port/error.h"
9
 
10
enum {
11
	Maxtimerloops = 20*1000,
12
};
13
 
14
struct Timers
15
{
16
	Lock;
17
	Timer	*head;
18
};
19
 
20
static Timers timers[MAXMACH];
21
static int timersinited;
22
 
23
ulong intrcount[MAXMACH];
24
ulong fcallcount[MAXMACH];
25
 
26
static vlong
27
tadd(Timers *tt, Timer *nt)
28
{
29
	Timer *t, **last;
30
 
31
	/* Called with tt locked */
32
	assert(nt->tt == nil);
33
	switch(nt->tmode){
34
	default:
35
		panic("timer");
36
		break;
37
	case Trelative:
38
		if(nt->tns <= 0)
39
			nt->tns = 1;
40
		nt->twhen = fastticks(nil) + ns2fastticks(nt->tns);
41
		break;
42
	case Tperiodic:
43
		assert(nt->tns >= 100000);	/* At least 100 µs period */
44
		if(nt->twhen == 0){
45
			/* look for another timer at same frequency for combining */
46
			for(t = tt->head; t; t = t->tnext){
47
				if(t->tmode == Tperiodic && t->tns == nt->tns)
48
					break;
49
			}
50
			if (t)
51
				nt->twhen = t->twhen;
52
			else
53
				nt->twhen = fastticks(nil);
54
		}
55
		nt->twhen += ns2fastticks(nt->tns);
56
		break;
57
	}
58
 
59
	for(last = &tt->head; t = *last; last = &t->tnext){
60
		if(t->twhen > nt->twhen)
61
			break;
62
	}
63
	nt->tnext = *last;
64
	*last = nt;
65
	nt->tt = tt;
66
	if(last == &tt->head)
67
		return nt->twhen;
68
	return 0;
69
}
70
 
71
static uvlong
72
tdel(Timer *dt)
73
{
74
 
75
	Timer *t, **last;
76
	Timers *tt;
77
 
78
	tt = dt->tt;
79
	if (tt == nil)
80
		return 0;
81
	for(last = &tt->head; t = *last; last = &t->tnext){
82
		if(t == dt){
83
			assert(dt->tt);
84
			dt->tt = nil;
85
			*last = t->tnext;
86
			break;
87
		}
88
	}
89
	if(last == &tt->head && tt->head)
90
		return tt->head->twhen;
91
	return 0;
92
}
93
 
94
/* add or modify a timer */
95
void
96
timeradd(Timer *nt)
97
{
98
	Timers *tt;
99
	vlong when;
100
 
101
	/* Must lock Timer struct before Timers struct */
102
	ilock(nt);
103
	if(tt = nt->tt){
104
		ilock(tt);
105
		tdel(nt);
106
		iunlock(tt);
107
	}
108
	tt = &timers[m->machno];
109
	ilock(tt);
110
	when = tadd(tt, nt);
111
	if(when)
112
		timerset(when);
113
	iunlock(tt);
114
	iunlock(nt);
115
}
116
 
117
 
118
void
119
timerdel(Timer *dt)
120
{
121
	Timers *tt;
122
	uvlong when;
123
 
124
	ilock(dt);
125
	if(tt = dt->tt){
126
		ilock(tt);
127
		when = tdel(dt);
128
		if(when && tt == &timers[m->machno])
129
			timerset(tt->head->twhen);
130
		iunlock(tt);
131
	}
132
	iunlock(dt);
133
}
134
 
135
void
136
hzclock(Ureg *ur)
137
{
138
	m->ticks++;
139
	if(m->proc)
140
		m->proc->pc = ur->pc;
141
 
142
	if(m->flushmmu){
143
		if(up)
144
			flushmmu();
145
		m->flushmmu = 0;
146
	}
147
 
148
	accounttime();
149
	kmapinval();
150
 
151
	if(kproftimer != nil)
152
		kproftimer(ur->pc);
153
 
154
	if((active.machs&(1<<m->machno)) == 0)
155
		return;
156
 
157
	if(active.exiting) {
158
		print("someone's exiting\n");
159
		exit(0);
160
	}
161
 
162
	checkalarms();
163
 
164
	if(up && up->state == Running)
165
		hzsched();	/* in proc.c */
166
}
167
 
168
void
169
timerintr(Ureg *u, Tval)
170
{
171
	Timer *t;
172
	Timers *tt;
173
	uvlong when, now;
174
	int count, callhzclock;
175
 
176
	intrcount[m->machno]++;
177
	callhzclock = 0;
178
	tt = &timers[m->machno];
179
	now = fastticks(nil);
180
	if(now == 0)
181
		panic("timerintr: zero fastticks()");
182
	ilock(tt);
183
	count = Maxtimerloops;
184
	while((t = tt->head) != nil){
185
		/*
186
		 * No need to ilock t here: any manipulation of t
187
		 * requires tdel(t) and this must be done with a
188
		 * lock to tt held.  We have tt, so the tdel will
189
		 * wait until we're done
190
		 */
191
		when = t->twhen;
192
		if(when > now){
193
			timerset(when);
194
			iunlock(tt);
195
			if(callhzclock)
196
				hzclock(u);
197
			return;
198
		}
199
		tt->head = t->tnext;
200
		assert(t->tt == tt);
201
		t->tt = nil;
202
		fcallcount[m->machno]++;
203
		iunlock(tt);
204
		if(t->tf)
205
			(*t->tf)(u, t);
206
		else
207
			callhzclock++;
208
		ilock(tt);
209
		if(t->tmode == Tperiodic)
210
			tadd(tt, t);
211
		if (--count <= 0) {
212
			count = Maxtimerloops;
213
			iprint("timerintr: probably stuck in while loop; "
214
				"scrutinise clock.c or use faster cycle "
215
				"counter\n");
216
		}
217
	}
218
	iunlock(tt);
219
}
220
 
221
void
222
timersinit(void)
223
{
224
	Timer *t;
225
 
226
	/*
227
	 * T->tf == nil means the HZ clock for this processor.
228
	 */
229
	timersinited = 1;
230
	todinit();
231
	t = malloc(sizeof(*t));
232
	if(t == nil)
233
		error(Enomem);
234
	t->tmode = Tperiodic;
235
	t->tt = nil;
236
	t->tns = 1000000000/HZ;
237
	t->tf = nil;
238
	timeradd(t);
239
}
240
 
241
Timer*
242
addclock0link(void (*f)(void), int ms)
243
{
244
	Timer *nt;
245
	uvlong when;
246
 
247
	if(!timersinited)
248
		panic("addclock0link: timersinit not called yet");
249
	/* Synchronize to hztimer if ms is 0 */
250
	nt = malloc(sizeof(Timer));
251
	if(nt == nil)
252
		error(Enomem);
253
	if(ms == 0)
254
		ms = 1000/HZ;
255
	nt->tns = (vlong)ms*1000000LL;
256
	nt->tmode = Tperiodic;
257
	nt->tt = nil;
258
	nt->tf = (void (*)(Ureg*, Timer*))f;
259
 
260
	ilock(&timers[0]);
261
	when = tadd(&timers[0], nt);
262
	if(when)
263
		timerset(when);
264
	iunlock(&timers[0]);
265
	return nt;
266
}
267
 
268
/*
269
 *  This tk2ms avoids overflows that the macro version is prone to.
270
 *  It is a LOT slower so shouldn't be used if you're just converting
271
 *  a delta.
272
 */
273
ulong
274
tk2ms(ulong ticks)
275
{
276
	uvlong t, hz;
277
 
278
	t = ticks;
279
	hz = HZ;
280
	t *= 1000L;
281
	t = t/hz;
282
	ticks = t;
283
	return ticks;
284
}
285
 
286
ulong
287
ms2tk(ulong ms)
288
{
289
	/* avoid overflows at the cost of precision */
290
	if(ms >= 1000000000/HZ)
291
		return (ms/1000)*HZ;
292
	return (ms*HZ+500)/1000;
293
}