diff options
Diffstat (limited to 'src/cmd/fossil/periodic.c')
-rw-r--r-- | src/cmd/fossil/periodic.c | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/cmd/fossil/periodic.c b/src/cmd/fossil/periodic.c new file mode 100644 index 00000000..8a0c2084 --- /dev/null +++ b/src/cmd/fossil/periodic.c @@ -0,0 +1,84 @@ +#include "stdinc.h" +#include "dat.h" +#include "fns.h" +#include "error.h" + +struct Periodic { + VtLock *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 = vtMemAllocZ(sizeof(Periodic)); + p->lk = vtLockAlloc(); + p->f = f; + p->a = a; + p->msec = msec; + if(p->msec < 10) + p->msec = 10; + + vtThread(periodicThread, p); + return p; +} + +void +periodicKill(Periodic *p) +{ + if(p == nil) + return; + vtLock(p->lk); + p->die = 1; + vtUnlock(p->lk); +} + +static void +periodicFree(Periodic *p) +{ + vtLockFree(p->lk); + vtMemFree(p); +} + +static void +periodicThread(void *a) +{ + Periodic *p = a; + vlong t, ct, ts; /* times in ms. */ + + vtThreadSetName("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 */ + + vtLock(p->lk); + if(p->die){ + vtUnlock(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; + } + vtUnlock(p->lk); + } + periodicFree(p); +} + |