1 #include "stdinc.h" 2 #include "dat.h" 3 #include "fns.h" 4 #include "error.h" 5 6 struct Periodic { 7 VtLock *lk; 8 int die; /* flag: quit if set */ 9 void (*f)(void*); /* call this each period */ 10 void *a; /* argument to f */ 11 int msec; /* period */ 12 }; 13 14 static void periodicThread(void *a); 15 16 Periodic * periodicAlloc(void (* f)(void *),void * a,int msec)17periodicAlloc(void (*f)(void*), void *a, int msec) 18 { 19 Periodic *p; 20 21 p = vtMemAllocZ(sizeof(Periodic)); 22 p->lk = vtLockAlloc(); 23 p->f = f; 24 p->a = a; 25 p->msec = msec; 26 if(p->msec < 10) 27 p->msec = 10; 28 29 vtThread(periodicThread, p); 30 return p; 31 } 32 33 void periodicKill(Periodic * p)34periodicKill(Periodic *p) 35 { 36 if(p == nil) 37 return; 38 vtLock(p->lk); 39 p->die = 1; 40 vtUnlock(p->lk); 41 } 42 43 static void periodicFree(Periodic * p)44periodicFree(Periodic *p) 45 { 46 vtLockFree(p->lk); 47 vtMemFree(p); 48 } 49 50 static void periodicThread(void * a)51periodicThread(void *a) 52 { 53 Periodic *p = a; 54 vlong t, ct, ts; /* times in ms. */ 55 56 vtThreadSetName("periodic"); 57 58 ct = nsec() / 1000000; 59 t = ct + p->msec; /* call p->f at or after this time */ 60 61 for(;;){ 62 ts = t - ct; /* ms. to next cycle's start */ 63 if(ts > 1000) 64 ts = 1000; /* bound sleep duration */ 65 if(ts > 0) 66 sleep(ts); /* wait for cycle's start */ 67 68 vtLock(p->lk); 69 if(p->die){ 70 vtUnlock(p->lk); 71 break; 72 } 73 ct = nsec() / 1000000; 74 if(t <= ct){ /* due to call p->f? */ 75 p->f(p->a); 76 ct = nsec() / 1000000; 77 while(t <= ct) /* advance t to future cycle start */ 78 t += p->msec; 79 } 80 vtUnlock(p->lk); 81 } 82 periodicFree(p); 83 } 84 85