| #include "stdinc.h" |
| #include "dat.h" |
| #include "fns.h" |
| #include "error.h" |
| |
| struct Periodic { |
| QLock lk; |
| int die; /* flag: quit if set */ |
| void (*f)(void*); /* call this each period */ |
| void *a; /* argument to f */ |
| int msec; /* period */ |
| }; |
| |
| static void periodicThread(void *a); |
| |
| Periodic * |
| periodicAlloc(void (*f)(void*), void *a, int msec) |
| { |
| Periodic *p; |
| |
| p = vtmallocz(sizeof(Periodic)); |
| p->f = f; |
| p->a = a; |
| p->msec = msec; |
| if(p->msec < 10) |
| p->msec = 10; |
| |
| proccreate(periodicThread, p, STACK); |
| return p; |
| } |
| |
| void |
| periodicKill(Periodic *p) |
| { |
| if(p == nil) |
| return; |
| qlock(&p->lk); |
| p->die = 1; |
| qunlock(&p->lk); |
| } |
| |
| static void |
| periodicFree(Periodic *p) |
| { |
| vtfree(p); |
| } |
| |
| static void |
| periodicThread(void *a) |
| { |
| Periodic *p = a; |
| vlong t, ct, ts; /* times in ms. */ |
| |
| threadsetname("periodic"); |
| |
| ct = nsec() / 1000000; |
| t = ct + p->msec; /* call p->f at or after this time */ |
| |
| for(;;){ |
| ts = t - ct; /* ms. to next cycle's start */ |
| if(ts > 1000) |
| ts = 1000; /* bound sleep duration */ |
| if(ts > 0) |
| sleep(ts); /* wait for cycle's start */ |
| |
| qlock(&p->lk); |
| if(p->die){ |
| qunlock(&p->lk); |
| break; |
| } |
| ct = nsec() / 1000000; |
| if(t <= ct){ /* due to call p->f? */ |
| p->f(p->a); |
| ct = nsec() / 1000000; |
| while(t <= ct) /* advance t to future cycle start */ |
| t += p->msec; |
| } |
| qunlock(&p->lk); |
| } |
| periodicFree(p); |
| } |
| |