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