time.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       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