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