xref: /plan9-contrib/sys/src/cmd/fossil/periodic.c (revision 13ab33fbec1dce6058a37685859b28e104de23a6)
1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 #include "error.h"
5 
6 struct Periodic {
7 	QLock 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 = vtmallocz(sizeof(Periodic));
22 	p->f = f;
23 	p->a = a;
24 	p->msec = msec;
25 	if(p->msec < 10)
26 		p->msec = 10;
27 
28 	proccreate(periodicThread, p, STACK);
29 	return p;
30 }
31 
32 void
periodicKill(Periodic * p)33 periodicKill(Periodic *p)
34 {
35 	if(p == nil)
36 		return;
37 	qlock(&p->lk);
38 	p->die = 1;
39 	qunlock(&p->lk);
40 }
41 
42 static void
periodicFree(Periodic * p)43 periodicFree(Periodic *p)
44 {
45 	vtfree(p);
46 }
47 
48 static void
periodicThread(void * a)49 periodicThread(void *a)
50 {
51 	Periodic *p = a;
52 	vlong t, ct, ts;		/* times in ms. */
53 
54 	threadsetname("periodic");
55 
56 	ct = nsec() / 1000000;
57 	t = ct + p->msec;		/* call p->f at or after this time */
58 
59 	for(;;){
60 		if(t - ct > p->msec)	/* time went backwards? */
61 			t = ct + p->msec;
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 		qlock(&p->lk);
69 		if(p->die){
70 			qunlock(&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 		qunlock(&p->lk);
81 	}
82 	periodicFree(p);
83 }
84 
85