xref: /plan9/sys/src/cmd/rio/time.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier #include <u.h>
2*7dd7cddfSDavid du Colombier #include <libc.h>
3*7dd7cddfSDavid du Colombier #include <draw.h>
4*7dd7cddfSDavid du Colombier #include <thread.h>
5*7dd7cddfSDavid du Colombier #include <cursor.h>
6*7dd7cddfSDavid du Colombier #include <mouse.h>
7*7dd7cddfSDavid du Colombier #include <keyboard.h>
8*7dd7cddfSDavid du Colombier #include <frame.h>
9*7dd7cddfSDavid du Colombier #include <auth.h>
10*7dd7cddfSDavid du Colombier #include <fcall.h>
11*7dd7cddfSDavid du Colombier #include "dat.h"
12*7dd7cddfSDavid du Colombier #include "fns.h"
13*7dd7cddfSDavid du Colombier 
14*7dd7cddfSDavid du Colombier static Channel*	ctimer;	/* chan(Timer*)[100] */
15*7dd7cddfSDavid du Colombier static Timer *timer;
16*7dd7cddfSDavid du Colombier 
17*7dd7cddfSDavid du Colombier static
18*7dd7cddfSDavid du Colombier uint
19*7dd7cddfSDavid du Colombier msec(void)
20*7dd7cddfSDavid du Colombier {
21*7dd7cddfSDavid du Colombier 	return nsec()/1000000;
22*7dd7cddfSDavid du Colombier }
23*7dd7cddfSDavid du Colombier 
24*7dd7cddfSDavid du Colombier void
25*7dd7cddfSDavid du Colombier timerstop(Timer *t)
26*7dd7cddfSDavid du Colombier {
27*7dd7cddfSDavid du Colombier 	t->next = timer;
28*7dd7cddfSDavid du Colombier 	timer = t;
29*7dd7cddfSDavid du Colombier }
30*7dd7cddfSDavid du Colombier 
31*7dd7cddfSDavid du Colombier void
32*7dd7cddfSDavid du Colombier timercancel(Timer *t)
33*7dd7cddfSDavid du Colombier {
34*7dd7cddfSDavid du Colombier 	t->cancel = TRUE;
35*7dd7cddfSDavid du Colombier }
36*7dd7cddfSDavid du Colombier 
37*7dd7cddfSDavid du Colombier static
38*7dd7cddfSDavid du Colombier void
39*7dd7cddfSDavid du Colombier timerproc(void*)
40*7dd7cddfSDavid du Colombier {
41*7dd7cddfSDavid du Colombier 	int i, nt, na, dt, del;
42*7dd7cddfSDavid du Colombier 	Timer **t, *x;
43*7dd7cddfSDavid du Colombier 	uint old, new;
44*7dd7cddfSDavid du Colombier 
45*7dd7cddfSDavid du Colombier 	rfork(RFFDG);
46*7dd7cddfSDavid du Colombier 	threadsetname("TIMERPROC");
47*7dd7cddfSDavid du Colombier 	t = nil;
48*7dd7cddfSDavid du Colombier 	na = 0;
49*7dd7cddfSDavid du Colombier 	nt = 0;
50*7dd7cddfSDavid du Colombier 	old = msec();
51*7dd7cddfSDavid du Colombier 	for(;;){
52*7dd7cddfSDavid du Colombier 		sleep(1);	/* will sleep minimum incr */
53*7dd7cddfSDavid du Colombier 		new = msec();
54*7dd7cddfSDavid du Colombier 		dt = new-old;
55*7dd7cddfSDavid du Colombier 		old = new;
56*7dd7cddfSDavid du Colombier 		if(dt < 0)	/* timer wrapped; go around, losing a tick */
57*7dd7cddfSDavid du Colombier 			continue;
58*7dd7cddfSDavid du Colombier 		for(i=0; i<nt; i++){
59*7dd7cddfSDavid du Colombier 			x = t[i];
60*7dd7cddfSDavid du Colombier 			x->dt -= dt;
61*7dd7cddfSDavid du Colombier 			del = 0;
62*7dd7cddfSDavid du Colombier 			if(x->cancel){
63*7dd7cddfSDavid du Colombier 				timerstop(x);
64*7dd7cddfSDavid du Colombier 				del = 1;
65*7dd7cddfSDavid du Colombier 			}else if(x->dt <= 0){
66*7dd7cddfSDavid du Colombier 				/*
67*7dd7cddfSDavid du Colombier 				 * avoid possible deadlock if client is
68*7dd7cddfSDavid du Colombier 				 * now sending on ctimer
69*7dd7cddfSDavid du Colombier 				 */
70*7dd7cddfSDavid du Colombier 				if(nbsendul(x->c, 0) > 0)
71*7dd7cddfSDavid du Colombier 					del = 1;
72*7dd7cddfSDavid du Colombier 			}
73*7dd7cddfSDavid du Colombier 			if(del){
74*7dd7cddfSDavid du Colombier 				memmove(&t[i], &t[i+1], (nt-i-1)*sizeof t[0]);
75*7dd7cddfSDavid du Colombier 				--nt;
76*7dd7cddfSDavid du Colombier 				--i;
77*7dd7cddfSDavid du Colombier 			}
78*7dd7cddfSDavid du Colombier 		}
79*7dd7cddfSDavid du Colombier 		if(nt == 0){
80*7dd7cddfSDavid du Colombier 			x = recvp(ctimer);
81*7dd7cddfSDavid du Colombier 	gotit:
82*7dd7cddfSDavid du Colombier 			if(nt == na){
83*7dd7cddfSDavid du Colombier 				na += 10;
84*7dd7cddfSDavid du Colombier 				t = realloc(t, na*sizeof(Timer*));
85*7dd7cddfSDavid du Colombier 				if(t == nil)
86*7dd7cddfSDavid du Colombier 					abort();
87*7dd7cddfSDavid du Colombier 			}
88*7dd7cddfSDavid du Colombier 			t[nt++] = x;
89*7dd7cddfSDavid du Colombier 			old = msec();
90*7dd7cddfSDavid du Colombier 		}
91*7dd7cddfSDavid du Colombier 		if(nbrecv(ctimer, &x) > 0)
92*7dd7cddfSDavid du Colombier 			goto gotit;
93*7dd7cddfSDavid du Colombier 	}
94*7dd7cddfSDavid du Colombier }
95*7dd7cddfSDavid du Colombier 
96*7dd7cddfSDavid du Colombier void
97*7dd7cddfSDavid du Colombier timerinit(void)
98*7dd7cddfSDavid du Colombier {
99*7dd7cddfSDavid du Colombier 	ctimer = chancreate(sizeof(Timer*), 100);
100*7dd7cddfSDavid du Colombier 	proccreate(timerproc, nil, STACK);
101*7dd7cddfSDavid du Colombier }
102*7dd7cddfSDavid du Colombier 
103*7dd7cddfSDavid du Colombier /*
104*7dd7cddfSDavid du Colombier  * timeralloc() and timerfree() don't lock, so can only be
105*7dd7cddfSDavid du Colombier  * called from the main proc.
106*7dd7cddfSDavid du Colombier  */
107*7dd7cddfSDavid du Colombier 
108*7dd7cddfSDavid du Colombier Timer*
109*7dd7cddfSDavid du Colombier timerstart(int dt)
110*7dd7cddfSDavid du Colombier {
111*7dd7cddfSDavid du Colombier 	Timer *t;
112*7dd7cddfSDavid du Colombier 
113*7dd7cddfSDavid du Colombier 	t = timer;
114*7dd7cddfSDavid du Colombier 	if(t)
115*7dd7cddfSDavid du Colombier 		timer = timer->next;
116*7dd7cddfSDavid du Colombier 	else{
117*7dd7cddfSDavid du Colombier 		t = emalloc(sizeof(Timer));
118*7dd7cddfSDavid du Colombier 		t->c = chancreate(sizeof(int), 0);
119*7dd7cddfSDavid du Colombier 	}
120*7dd7cddfSDavid du Colombier 	t->next = nil;
121*7dd7cddfSDavid du Colombier 	t->dt = dt;
122*7dd7cddfSDavid du Colombier 	t->cancel = FALSE;
123*7dd7cddfSDavid du Colombier 	sendp(ctimer, t);
124*7dd7cddfSDavid du Colombier 	return t;
125*7dd7cddfSDavid du Colombier }
126