aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/fossil/periodic.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/fossil/periodic.c')
-rw-r--r--src/cmd/fossil/periodic.c84
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);
+}
+