]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/portclock.c
alarm: run checkalarms() only on cpu0 (from eriks alarm-once patch)
[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                 print("someone's exiting\n");
153                 exit(0);
154         }
155
156         if(m->machno == 0)
157                 checkalarms();
158
159         if(up && up->state == Running)
160                 hzsched();      /* in proc.c */
161 }
162
163 void
164 timerintr(Ureg *u, Tval)
165 {
166         Timer *t;
167         Timers *tt;
168         uvlong when, now;
169         int callhzclock;
170         static int sofar;
171
172         intrcount[m->machno]++;
173         callhzclock = 0;
174         tt = &timers[m->machno];
175         now = fastticks(nil);
176         ilock(tt);
177         while(t = tt->head){
178                 /*
179                  * No need to ilock t here: any manipulation of t
180                  * requires tdel(t) and this must be done with a
181                  * lock to tt held.  We have tt, so the tdel will
182                  * wait until we're done
183                  */
184                 when = t->twhen;
185                 if(when > now){
186                         timerset(when);
187                         iunlock(tt);
188                         if(callhzclock)
189                                 hzclock(u);
190                         return;
191                 }
192                 tt->head = t->tnext;
193                 assert(t->tt == tt);
194                 t->tt = nil;
195                 fcallcount[m->machno]++;
196                 iunlock(tt);
197                 if(t->tf)
198                         (*t->tf)(u, t);
199                 else
200                         callhzclock++;
201                 ilock(tt);
202                 if(t->tmode == Tperiodic)
203                         tadd(tt, t);
204         }
205         iunlock(tt);
206 }
207
208 void
209 timersinit(void)
210 {
211         Timer *t;
212
213         /*
214          * T->tf == nil means the HZ clock for this processor.
215          */
216         todinit();
217         t = malloc(sizeof(*t));
218         if(t == nil)
219                 panic("timersinit: no memory for Timer");
220         t->tmode = Tperiodic;
221         t->tt = nil;
222         t->tns = 1000000000/HZ;
223         t->tf = nil;
224         timeradd(t);
225 }
226
227 Timer*
228 addclock0link(void (*f)(void), int ms)
229 {
230         Timer *nt;
231         uvlong when;
232
233         /* Synchronize to hztimer if ms is 0 */
234         nt = malloc(sizeof(Timer));
235         if(nt == nil)
236                 panic("addclock0link: no memory for Timer");
237         if(ms == 0)
238                 ms = 1000/HZ;
239         nt->tns = (vlong)ms*1000000LL;
240         nt->tmode = Tperiodic;
241         nt->tt = nil;
242         nt->tf = (void (*)(Ureg*, Timer*))f;
243
244         ilock(&timers[0]);
245         when = tadd(&timers[0], nt);
246         if(when)
247                 timerset(when);
248         iunlock(&timers[0]);
249         return nt;
250 }
251
252 /*
253  *  This tk2ms avoids overflows that the macro version is prone to.
254  *  It is a LOT slower so shouldn't be used if you're just converting
255  *  a delta.
256  */
257 ulong
258 tk2ms(ulong ticks)
259 {
260         uvlong t, hz;
261
262         t = ticks;
263         hz = HZ;
264         t *= 1000L;
265         t = t/hz;
266         ticks = t;
267         return ticks;
268 }
269
270 ulong
271 ms2tk(ulong ms)
272 {
273         /* avoid overflows at the cost of precision */
274         if(ms >= 1000000000/HZ)
275                 return (ms/1000)*HZ;
276         return (ms*HZ+500)/1000;
277 }