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