1 | /*
2 | * Layer Two Tunnelling Protocol Daemon
3 | * Copyright (C) 1998 Adtran, Inc.
4 | *
5 | * Mark Spencer
6 | *
7 | * This software is distributed under the terms
8 | * of the GPL, which you should have received
9 | * along with this source.
10 | *
11 | * Scheduler code for time based functionality
12 | *
13 | */
14 |
15 | #include <stdlib.h>
16 | #include <signal.h>
17 | #include <string.h>
18 | #include "l2tp.h"
19 | #include "scheduler.h"
20 |
21 | struct schedule_entry *events;
22 | static struct timeval zero;
23 | static sigset_t alarm;
24 |
25 | void init_scheduler (void)
26 | {
27 | struct sigaction act;
28 | act.sa_handler = alarm_handler;
29 | #ifdef LINUX
30 | act.sa_restorer = NULL;
31 | #endif
32 | act.sa_flags = 0;
33 | sigemptyset (&act.sa_mask);
34 | sigaddset (&act.sa_mask, SIGALRM);
35 | sigaction (SIGALRM, &act, NULL);
36 | events = NULL;
37 | zero.tv_usec = 0;
38 | zero.tv_sec = 0;
39 | sigemptyset (&alarm);
40 | sigaddset (&alarm, SIGALRM);
41 | }
42 |
43 | void alarm_handler (int signal)
44 | {
45 | /* Check queue for events which should be
46 | executed right now. Execute them, then
47 | see how long we should set the next timer
48 | */
49 | struct schedule_entry *p = events;
50 | struct timeval now;
51 | struct timeval then;
52 | struct itimerval itv;
53 | static int cnt = 0;
54 | cnt++;
55 | if (cnt != 1)
56 | {
57 | /* Whoa, we got called from within ourselves! */
58 | log (LOG_DEBUG, "%s : Whoa... cnt = %d\n", __FUNCTION__, cnt);
59 | return;
60 | }
61 | while (events)
62 | {
63 | gettimeofday (&now, NULL);
64 | p = events;
65 | if (TVLESSEQ (p->tv, now))
66 | {
67 | events = events->next;
68 | /* This needs to be executed, as it has expired.
69 | It is expected that p->func will free p->data
70 | if it is necessary */
71 | (*p->func) (p->data);
72 | free (p);
73 | }
74 | else
75 | break;
76 | }
77 | /* When we get here, either there are no more events
78 | in the queue, or the remaining events need to happen
79 | in the future, so we should schedule another alarm */
80 | if (events)
81 | {
82 | then.tv_sec = events->tv.tv_sec - now.tv_sec;
83 | then.tv_usec = events->tv.tv_usec - now.tv_usec;
84 | if (then.tv_usec < 0)
85 | {
86 | then.tv_sec -= 1;
87 | then.tv_usec += 1000000;
88 | }
89 | if ((then.tv_sec <= 0) && (then.tv_usec <= 0))
90 | {
91 | log (LOG_WARN, "%s: Whoa... Scheduling for <=0 time???\n",
92 | __FUNCTION__);
93 | }
94 | else
95 | {
96 | itv.it_interval = zero;
97 | itv.it_value = then;
98 | setitimer (ITIMER_REAL, &itv, NULL);
99 | }
100 | }
101 | cnt--;
102 | }
103 |
104 | void schedule_lock ()
105 | {
106 | while (sigprocmask (SIG_BLOCK, &alarm, NULL));
107 | };
108 |
109 | void schedule_unlock ()
110 | {
111 | /* See if we missed any events */
112 | /* alarm_handler(0); */
113 | while (sigprocmask (SIG_UNBLOCK, &alarm, NULL));
114 | raise (SIGALRM);
115 | };
116 |
117 | struct schedule_entry *schedule (struct timeval tv, void (*func) (void *),
118 | void *data)
119 | {
120 | /* Schedule func to be run at relative time tv with data
121 | as arguments. If it has already expired, run it
122 | immediately. The queue should be in order of
123 | increasing time */
124 | struct schedule_entry *p = events, *q = NULL;
125 | int need_timer = 0;
126 | struct timeval diff;
127 | struct itimerval itv;
128 | diff = tv;
129 | gettimeofday (&tv, NULL);
130 | tv.tv_sec += diff.tv_sec;
131 | tv.tv_usec += diff.tv_usec;
132 | if (tv.tv_usec > 1000000)
133 | {
134 | tv.tv_sec++;
135 | tv.tv_usec -= 1000000;
136 | }
137 | while (p)
138 | {
139 | if (TVLESS (tv, p->tv))
140 | break;
141 | q = p;
142 | p = p->next;
143 | };
144 | if (q)
145 | {
146 | q->next =
147 | (struct schedule_entry *) malloc (sizeof (struct schedule_entry));
148 | q = q->next;
149 | }
150 | else
151 | {
152 | q = (struct schedule_entry *) malloc (sizeof (struct schedule_entry));
153 | events = q;
154 | need_timer = -1;
155 | }
156 | q->tv = tv;
157 | q->func = func;
158 | q->data = data;
159 | q->next = p;
160 | if (need_timer)
161 | {
162 | itv.it_interval = zero;
163 | itv.it_value = diff;
164 | setitimer (ITIMER_REAL, &itv, NULL);
165 |
166 | }
167 | return q;
168 |
169 | }
170 |
171 | inline struct schedule_entry *aschedule (struct timeval tv,
172 | void (*func) (void *), void *data)
173 | {
174 | /* Schedule func to be run at absolute time tv in the future with data
175 | as arguments */
176 | struct timeval now;
177 | gettimeofday (&now, NULL);
178 | tv.tv_usec -= now.tv_usec;
179 | if (tv.tv_usec < 0)
180 | {
181 | tv.tv_usec += 1000000;
182 | tv.tv_sec--;
183 | }
184 | tv.tv_sec -= now.tv_sec;
185 | return schedule (tv, func, data);
186 | }
187 |
188 | void deschedule (struct schedule_entry *s)
189 | {
190 | struct schedule_entry *p = events, *q = NULL;
191 | if (!s)
192 | return;
193 | while (p)
194 | {
195 | if (p == s)
196 | {
197 | if (q)
198 | {
199 | q->next = p->next;
200 | }
201 | else
202 | {
203 | events = events->next;
204 | }
205 | free (p);
206 | break;
207 | }
208 | q = p;
209 | p = p->next;
210 | }
211 | }