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