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