xref: /plan9/sys/src/cmd/aquarela/alarm.c (revision 4af5a9a1337b2226c3ce480af26cabb9dde39fa9)
1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <thread.h>
5 #include "netbios.h"
6 
7 static struct {
8 	int thread;
9 	int die;
10 	QLock;
11 	NbnsAlarm *head;
12 } alarmlist = { -1 };
13 
14 #define MaxLong ((1 << (sizeof(long) * 8 - 1)) - 1)
15 
16 void
alarmist(void *)17 alarmist(void *)
18 {
19 	for (;;) {
20 		vlong now;
21 		long snooze;
22 //print("running\n");
23 		qlock(&alarmlist);
24 		if (alarmlist.die) {
25 			qunlock(&alarmlist);
26 			break;
27 		}
28 		now = nsec() / 1000000;
29 		while (alarmlist.head && alarmlist.head->expirems <= now) {
30 //print("expiring because %lld > %lld\n", alarmlist.head->expirems, now);
31 			sendul(alarmlist.head->c, 1);
32 			alarmlist.head = alarmlist.head->next;
33 		}
34 		if (alarmlist.head) {
35 			vlong vsnooze = alarmlist.head->expirems - now;
36 			if (vsnooze > MaxLong)
37 				snooze = MaxLong;
38 			else
39 				snooze = vsnooze;
40 		}
41 		else
42 			snooze = 60 * 1000;
43 //print("snoozing for %ld\n", snooze);
44 		qunlock(&alarmlist);
45 		sleep(snooze);
46 	}
47 }
48 
49 NbnsAlarm *
nbnsalarmnew(void)50 nbnsalarmnew(void)
51 {
52 	NbnsAlarm *a;
53 	a = mallocz(sizeof(*a), 1);
54 	if (a == nil)
55 		return nil;
56 	a->c = chancreate(sizeof(ulong), 1);
57 	if (a->c == nil) {
58 		free(a);
59 		return nil;
60 	}
61 	return a;
62 }
63 
64 void
nbnsalarmcancel(NbnsAlarm * a)65 nbnsalarmcancel(NbnsAlarm *a)
66 {
67 	NbnsAlarm **ap;
68 	int rv;
69 	qlock(&alarmlist);
70 	for (ap = &alarmlist.head; *ap && *ap != a; ap = &(*ap)->next)
71 		;
72 	if (*ap) {
73 		*ap = a->next;
74 		if (ap == &alarmlist.head)
75 			threadint(alarmlist.thread);
76 	}
77 	qunlock(&alarmlist);
78 	do {
79 		ulong v;
80 		rv = nbrecv(a->c, &v);
81 	} while (rv != 0);
82 }
83 
84 void
nbnsalarmend(void)85 nbnsalarmend(void)
86 {
87 	qlock(&alarmlist);
88 	if (alarmlist.thread >= 0) {
89 		alarmlist.die = 1;
90 		threadint(alarmlist.thread);
91 	}
92 	qunlock(&alarmlist);
93 }
94 
95 void
nbnsalarmset(NbnsAlarm * a,ulong millisec)96 nbnsalarmset(NbnsAlarm *a, ulong millisec)
97 {
98 	NbnsAlarm **ap;
99 	nbnsalarmcancel(a);
100 	a->expirems = nsec() / 1000000 + millisec;
101 	qlock(&alarmlist);
102 	for (ap = &alarmlist.head; *ap; ap = &(*ap)->next)
103 		if (a->expirems < (*ap)->expirems)
104 			break;
105 	a->next = (*ap);
106 	*ap = a;
107 	if (alarmlist.thread < 0)
108 		alarmlist.thread = proccreate(alarmist, nil, 16384);
109 	else
110 		threadint(alarmlist.thread);
111 	qunlock(&alarmlist);
112 }
113 
114 void
nbnsalarmfree(NbnsAlarm ** ap)115 nbnsalarmfree(NbnsAlarm **ap)
116 {
117 	NbnsAlarm *a;
118 	a = *ap;
119 	if (a) {
120 		nbnsalarmcancel(a);
121 		chanfree(a->c);
122 		free(a);
123 		*ap = nil;
124 	}
125 }
126