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