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