#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);
}
|