]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/portclock.c
kernel: replace ulong with uintptr in ucallocb() and fix unneeded parentheses
[plan9front.git] / sys / src / 9 / port / portclock.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "ureg.h"
8
9 struct Timers
10 {
11         Lock;
12         Timer   *head;
13 };
14
15 static Timers timers[MAXMACH];
16
17 ulong intrcount[MAXMACH];
18 ulong fcallcount[MAXMACH];
19
20 static vlong
21 tadd(Timers *tt, Timer *nt)
22 {
23         Timer *t, **last;
24
25         /* Called with tt locked */
26         assert(nt->tt == nil);
27         switch(nt->tmode){
28         default:
29                 panic("timer");
30                 break;
31         case Trelative:
32                 if(nt->tns <= 0)
33                         nt->tns = 1;
34                 nt->twhen = fastticks(nil) + ns2fastticks(nt->tns);
35                 break;
36         case Tperiodic:
37                 assert(nt->tns >= 100000);      /* At least 100 µs period */
38                 if(nt->twhen == 0){
39                         /* look for another timer at same frequency for combining */
40                         for(t = tt->head; t; t = t->tnext){
41                                 if(t->tmode == Tperiodic && t->tns == nt->tns)
42                                         break;
43                         }
44                         if (t)
45                                 nt->twhen = t->twhen;
46                         else
47                                 nt->twhen = fastticks(nil);
48                 }
49                 nt->twhen += ns2fastticks(nt->tns);
50                 break;
51         }
52
53         for(last = &tt->head; t = *last; last = &t->tnext){
54                 if(t->twhen > nt->twhen)
55                         break;
56         }
57         nt->tnext = *last;
58         *last = nt;
59         nt->tt = tt;
60         if(last == &tt->head)
61                 return nt->twhen;
62         return 0;
63 }
64
65 static uvlong
66 tdel(Timer *dt)
67 {
68
69         Timer *t, **last;
70         Timers *tt;
71
72         tt = dt->tt;
73         if (tt == nil)
74                 return 0;
75         for(last = &tt->head; t = *last; last = &t->tnext){
76                 if(t == dt){
77                         assert(dt->tt);
78                         dt->tt = nil;
79                         *last = t->tnext;
80                         break;
81                 }
82         }
83         if(last == &tt->head && tt->head)
84                 return tt->head->twhen;
85         return 0;
86 }
87
88 /* add or modify a timer */
89 void
90 timeradd(Timer *nt)
91 {
92         Timers *tt;
93         vlong when;
94
95         /* Must lock Timer struct before Timers struct */
96         ilock(nt);
97         if(tt = nt->tt){
98                 ilock(tt);
99                 tdel(nt);
100                 iunlock(tt);
101         }
102         tt = &timers[m->machno];
103         ilock(tt);
104         when = tadd(tt, nt);
105         if(when)
106                 timerset(when);
107         iunlock(tt);
108         iunlock(nt);
109 }
110
111
112 void
113 timerdel(Timer *dt)
114 {
115         Timers *tt;
116         uvlong when;
117
118         ilock(dt);
119         if(tt = dt->tt){
120                 ilock(tt);
121                 when = tdel(dt);
122                 if(when && tt == &timers[m->machno])
123                         timerset(tt->head->twhen);
124                 iunlock(tt);
125         }
126         iunlock(dt);
127 }
128
129 void
130 hzclock(Ureg *ur)
131 {
132         m->ticks++;
133         if(m->proc)
134                 m->proc->pc = ur->pc;
135
136         if(m->flushmmu){
137                 if(up)
138                         flushmmu();
139                 m->flushmmu = 0;
140         }
141
142         accounttime();
143         kmapinval();
144
145         if(kproftimer != nil)
146                 kproftimer(ur->pc);
147
148         if((active.machs&(1<<m->machno)) == 0)
149                 return;
150
151         if(active.exiting)
152                 exit(0);
153
154         if(m->machno == 0)
155                 checkalarms();
156
157         if(up && up->state == Running)
158                 hzsched();      /* in proc.c */
159 }
160
161 void
162 timerintr(Ureg *u, Tval)
163 {
164         Timer *t;
165         Timers *tt;
166         uvlong when, now;
167         int callhzclock;
168         static int sofar;
169
170         intrcount[m->machno]++;
171         callhzclock = 0;
172         tt = &timers[m->machno];
173         now = fastticks(nil);
174         ilock(tt);
175         while(t = tt->head){
176                 /*
177                  * No need to ilock t here: any manipulation of t
178                  * requires tdel(t) and this must be done with a
179                  * lock to tt held.  We have tt, so the tdel will
180                  * wait until we're done
181                  */
182                 when = t->twhen;
183                 if(when > now){
184                         timerset(when);
185                         iunlock(tt);
186                         if(callhzclock)
187                                 hzclock(u);
188                         return;
189                 }
190                 tt->head = t->tnext;
191                 assert(t->tt == tt);
192                 t->tt = nil;
193                 fcallcount[m->machno]++;
194                 iunlock(tt);
195                 if(t->tf)
196                         (*t->tf)(u, t);
197                 else
198                         callhzclock++;
199                 ilock(tt);
200                 if(t->tmode == Tperiodic)
201                         tadd(tt, t);
202         }
203         iunlock(tt);
204 }
205
206 void
207 timersinit(void)
208 {
209         Timer *t;
210
211         /*
212          * T->tf == nil means the HZ clock for this processor.
213          */
214         todinit();
215         t = malloc(sizeof(*t));
216         if(t == nil)
217                 panic("timersinit: no memory for Timer");
218         t->tmode = Tperiodic;
219         t->tt = nil;
220         t->tns = 1000000000/HZ;
221         t->tf = nil;
222         timeradd(t);
223 }
224
225 Timer*
226 addclock0link(void (*f)(void), int ms)
227 {
228         Timer *nt;
229         uvlong when;
230
231         /* Synchronize to hztimer if ms is 0 */
232         nt = malloc(sizeof(Timer));
233         if(nt == nil)
234                 panic("addclock0link: no memory for Timer");
235         if(ms == 0)
236                 ms = 1000/HZ;
237         nt->tns = (vlong)ms*1000000LL;
238         nt->tmode = Tperiodic;
239         nt->tt = nil;
240         nt->tf = (void (*)(Ureg*, Timer*))f;
241
242         ilock(&timers[0]);
243         when = tadd(&timers[0], nt);
244         if(when)
245                 timerset(when);
246         iunlock(&timers[0]);
247         return nt;
248 }
249
250 /*
251  *  This tk2ms avoids overflows that the macro version is prone to.
252  *  It is a LOT slower so shouldn't be used if you're just converting
253  *  a delta.
254  */
255 ulong
256 tk2ms(ulong ticks)
257 {
258         uvlong t, hz;
259
260         t = ticks;
261         hz = HZ;
262         t *= 1000L;
263         t = t/hz;
264         ticks = t;
265         return ticks;
266 }
267
268 ulong
269 ms2tk(ulong ms)
270 {
271         /* avoid overflows at the cost of precision */
272         if(ms >= 1000000000/HZ)
273                 return (ms/1000)*HZ;
274         return (ms*HZ+500)/1000;
275 }