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