time.c (6541B)
1 /* 2 * Plan 9 VX timers. 3 * 4 * In Plan 9 VX, "ticks" are milliseconds, 5 * and "fast ticks" are nanoseconds. 6 * This makes the conversions trivial. 7 */ 8 9 #include "u.h" 10 #include <pthread.h> 11 #include <signal.h> 12 #include "lib.h" 13 #include "mem.h" 14 #include "dat.h" 15 #include "fns.h" 16 #include "error.h" 17 #include "ureg.h" 18 19 #define nsec() fastticks(nil) 20 #define ns2fastticks(x) (x) 21 22 struct Timers 23 { 24 Lock lk; 25 Timer *head; 26 }; 27 28 static vlong start; 29 static Timers timers; 30 static void kicktimerproc(void); 31 32 static vlong 33 tadd(Timers *tt, Timer *nt) 34 { 35 Timer *t, **last; 36 37 /* Called with tt locked */ 38 assert(nt->tt == nil); 39 switch(nt->tmode){ 40 default: 41 panic("timer"); 42 break; 43 case Trelative: 44 if(nt->tns <= 0) 45 nt->tns = 1; 46 nt->twhen = fastticks(nil) + ns2fastticks(nt->tns); 47 break; 48 case Tperiodic: 49 assert(nt->tns >= 100000); /* At least 100 µs period */ 50 if(nt->twhen == 0){ 51 /* look for another timer at same frequency for combining */ 52 for(t = tt->head; t; t = t->tnext){ 53 if(t->tmode == Tperiodic && t->tns == nt->tns) 54 break; 55 } 56 if (t) 57 nt->twhen = t->twhen; 58 else 59 nt->twhen = fastticks(nil); 60 } 61 nt->twhen += ns2fastticks(nt->tns); 62 break; 63 } 64 65 for(last = &tt->head; (t = *last); last = &t->tnext){ 66 if(t->twhen > nt->twhen) 67 break; 68 } 69 nt->tnext = *last; 70 *last = nt; 71 nt->tt = tt; 72 if(last == &tt->head) 73 return nt->twhen; 74 return 0; 75 } 76 77 static uvlong 78 tdel(Timer *dt) 79 { 80 Timer *t, **last; 81 Timers *tt; 82 83 tt = dt->tt; 84 if (tt == nil) 85 return 0; 86 for(last = &tt->head; (t = *last); last = &t->tnext){ 87 if(t == dt){ 88 assert(dt->tt); 89 dt->tt = nil; 90 *last = t->tnext; 91 break; 92 } 93 } 94 if(last == &tt->head && tt->head) 95 return tt->head->twhen; 96 return 0; 97 } 98 99 /* add or modify a timer */ 100 void 101 timeradd(Timer *nt) 102 { 103 Timers *tt; 104 vlong when; 105 106 /* Must lock Timer struct before Timers struct */ 107 ilock(&nt->lk); 108 if((tt = nt->tt)){ 109 ilock(&tt->lk); 110 tdel(nt); 111 iunlock(&tt->lk); 112 } 113 tt = &timers; 114 ilock(&tt->lk); 115 when = tadd(tt, nt); 116 if(when) 117 kicktimerproc(); 118 iunlock(&tt->lk); 119 iunlock(&nt->lk); 120 } 121 122 void 123 timerdel(Timer *dt) 124 { 125 Timers *tt; 126 uvlong when; 127 128 ilock(&dt->lk); 129 if((tt = dt->tt)){ 130 ilock(&tt->lk); 131 when = tdel(dt); 132 if(when && tt == &timers) 133 kicktimerproc(); 134 iunlock(&tt->lk); 135 } 136 iunlock(&dt->lk); 137 } 138 139 /* 140 * The timer proc sleeps until the next timer is going 141 * to go off, and then runs any timers that need running. 142 * If a new timer is inserted while it is asleep, the proc 143 * that adds the new timer will send the timer proc a SIGURG 144 * to wake it up early. SIGURG is blocked in all procs by default, 145 * so the timer is guaranteed to get the signal. 146 */ 147 static pthread_t timer_pid; 148 void 149 timerkproc(void *v) 150 { 151 sigset_t sigs; 152 Timers *tt; 153 Timer *t; 154 uvlong when, now; 155 struct timespec ts; 156 Ureg u; 157 int signo; 158 159 memset(&u, 0, sizeof u); 160 timer_pid = pthread_self(); 161 162 tt = &timers; 163 ilock(&tt->lk); 164 for(;;){ 165 if((t = tt->head) == nil){ 166 iunlock(&tt->lk); 167 sigemptyset(&sigs); 168 sigaddset(&sigs, SIGURG); 169 sigwait(&sigs, &signo); 170 ilock(&tt->lk); 171 continue; 172 } 173 /* 174 * No need to ilock t here: any manipulation of t 175 * requires tdel(t) and this must be done with a 176 * lock to tt held. We have tt, so the tdel will 177 * wait until we're done 178 */ 179 now = fastticks(nil); 180 when = t->twhen; 181 if(when > now){ 182 iunlock(&tt->lk); 183 when -= now; 184 ts.tv_sec = when/1000000000; 185 ts.tv_nsec = when%1000000000; 186 pthread_sigmask(SIG_SETMASK, nil, &sigs); 187 sigdelset(&sigs, SIGURG); 188 pselect(0, nil, nil, nil, &ts, &sigs); 189 ilock(&tt->lk); 190 continue; 191 } 192 193 tt->head = t->tnext; 194 assert(t->tt == tt); 195 t->tt = nil; 196 iunlock(&tt->lk); 197 (*t->tf)(&u, t); 198 ilock(&tt->lk); 199 if(t->tmode == Tperiodic) 200 tadd(tt, t); 201 } 202 } 203 204 static void 205 kicktimerproc(void) 206 { 207 if(timer_pid != 0) 208 pthread_kill(timer_pid, SIGURG); 209 } 210 211 void 212 timersinit(void) 213 { 214 kproc("*timer*", timerkproc, nil); 215 } 216 217 static Alarms alarms; 218 static Timer alarmtimer; 219 220 static void setalarm(void); 221 222 static void 223 soundalarms(Ureg *u, Timer *t) 224 { 225 ulong now; 226 Proc *rp; 227 228 now = msec(); 229 qlock(&alarms.lk); 230 while((rp = alarms.head) && rp->alarm <= now){ 231 if(rp->alarm != 0){ 232 if(!canqlock(&rp->debug)) 233 break; 234 if(!waserror()){ 235 postnote(rp, 0, "alarm", NUser); 236 poperror(); 237 } 238 qunlock(&rp->debug); 239 rp->alarm = 0; 240 } 241 alarms.head = rp->palarm; 242 } 243 setalarm(); 244 qunlock(&alarms.lk); 245 } 246 247 static void 248 setalarm(void) 249 { 250 Proc *p; 251 ulong now; 252 253 now = msec(); 254 if(alarmtimer.tt) 255 timerdel(&alarmtimer); 256 while((p = alarms.head) && p->alarm == 0) 257 alarms.head = p->palarm; 258 if(p == nil) 259 return; 260 alarmtimer.tf = soundalarms; 261 alarmtimer.tmode = Trelative; 262 alarmtimer.tns = (p->alarm - now)*1000000LL; 263 timeradd(&alarmtimer); 264 } 265 266 ulong 267 procalarm(ulong time) 268 { 269 Proc **l, *f; 270 ulong when, old, now; 271 272 now = msec(); 273 if(up->alarm) 274 old = up->alarm - now; 275 else 276 old = 0; 277 if(time == 0) { 278 up->alarm = 0; 279 return old; 280 } 281 when = time+now; 282 283 qlock(&alarms.lk); 284 l = &alarms.head; 285 for(f = *l; f; f = f->palarm) { 286 if(up == f){ 287 *l = f->palarm; 288 break; 289 } 290 l = &f->palarm; 291 } 292 293 up->palarm = 0; 294 if(alarms.head) { 295 l = &alarms.head; 296 for(f = *l; f; f = f->palarm) { 297 if(f->alarm > when) { 298 up->palarm = f; 299 *l = up; 300 goto done; 301 } 302 l = &f->palarm; 303 } 304 *l = up; 305 } 306 else 307 alarms.head = up; 308 done: 309 up->alarm = when; 310 setalarm(); 311 qunlock(&alarms.lk); 312 313 return old; 314 } 315 316 ulong 317 perfticks(void) 318 { 319 return msec(); 320 } 321 322 // Only gets used by the profiler. 323 // Not going to bother for now. 324 Timer* 325 addclock0link(void (*x)(void), int y) 326 { 327 return 0; 328 } 329 330 uvlong 331 fastticks(uvlong *hz) 332 { 333 struct timeval tv; 334 uvlong t; 335 336 gettimeofday(&tv, 0); 337 t = tv.tv_sec * 1000000000LL + tv.tv_usec*1000LL; 338 if(hz) 339 *hz = 1000000000LL; 340 return t; 341 } 342 343 ulong 344 msec(void) 345 { 346 struct timeval tv; 347 348 gettimeofday(&tv, 0); 349 return tv.tv_sec * 1000 + tv.tv_usec/1000; 350 } 351 352 ulong 353 tk2ms(ulong x) 354 { 355 return x; 356 } 357 358 ulong 359 ms2tk(ulong x) 360 { 361 return x; 362 } 363 364 long 365 seconds(void) 366 { 367 return time(0); 368 } 369 370 void 371 todinit(void) 372 { 373 start = todget(nil); 374 } 375 376 void 377 pcycles(uvlong *t) 378 { 379 *t = fastticks(nil); 380 } 381 382 void (*cycles)(uvlong*) = pcycles; 383 384 void 385 microdelay(int x) 386 { 387 struct timeval tv; 388 389 tv.tv_sec = x/1000000; 390 tv.tv_usec = x%1000000; 391 select(0, nil, nil, nil, &tv); 392 } 393 394 /* 395 * Time of day 396 */ 397 vlong 398 todget(vlong *ticksp) 399 { 400 struct timeval tv; 401 vlong t; 402 gettimeofday(&tv, NULL); 403 t = tv.tv_sec*1000000000LL + tv.tv_usec*1000LL; 404 if(ticksp) 405 *ticksp = t - start; 406 return t; 407 } 408 409 void 410 todset(vlong a, vlong b, int c) 411 { 412 USED(a); 413 USED(b); 414 USED(c); 415 } 416 417 void 418 todsetfreq(vlong a) 419 { 420 USED(a); 421 } 422