xref: /plan9/sys/src/cmd/fossil/periodic.c (revision 7fd2696ac38c1e0929802fd9633fa59b7bcc7c21)
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)17 periodicAlloc(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)34 periodicKill(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)44 periodicFree(Periodic *p)
45 {
46 	vtLockFree(p->lk);
47 	vtMemFree(p);
48 }
49 
50 static void
periodicThread(void * a)51 periodicThread(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