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  | }