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