1 /* 2 * PPP Timer Processing Module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $FreeBSD$ 21 * 22 * TODO: 23 */ 24 #include "defs.h" 25 #include <sys/time.h> 26 #include <signal.h> 27 #include "timeout.h" 28 #ifdef SIGALRM 29 #include <errno.h> 30 #endif 31 void StopTimerNoBlock( struct pppTimer *); 32 void ShowTimers(void); 33 34 void 35 StopTimer( struct pppTimer *tp ) 36 { 37 #ifdef SIGALRM 38 int omask; 39 omask = sigblock(sigmask(SIGALRM)); 40 #endif 41 StopTimerNoBlock(tp); 42 #ifdef SIGALRM 43 sigsetmask(omask); 44 #endif 45 } 46 void 47 StartTimer(tp) 48 struct pppTimer *tp; 49 { 50 struct pppTimer *t, *pt; 51 u_long ticks = 0; 52 53 #ifdef SIGALRM 54 int omask; 55 omask = sigblock(sigmask(SIGALRM)); 56 #endif 57 58 if (tp->state != TIMER_STOPPED) { 59 StopTimerNoBlock(tp); 60 } 61 if (tp->load == 0) { 62 #ifdef DEBUG 63 logprintf("timer %x has 0 load!\n", tp); 64 #endif 65 sigsetmask(omask); 66 return; 67 } 68 pt = NULL; 69 for (t = TimerList; t; t = t->next) { 70 #ifdef DEBUG 71 logprintf("StartTimer: %x(%d): ticks: %d, rest: %d\n", t, t->state, ticks, t->rest); 72 #endif 73 if (ticks + t->rest >= tp->load) 74 break; 75 ticks += t->rest; 76 pt = t; 77 } 78 79 tp->state = TIMER_RUNNING; 80 tp->rest = tp->load - ticks; 81 #ifdef DEBUG 82 logprintf("Inserting %x before %x, rest = %d\n", tp, t, tp->rest); 83 #endif 84 /* Insert given *tp just before *t */ 85 tp->next = t; 86 if (pt) { 87 pt->next = tp; 88 } else { 89 InitTimerService(); 90 TimerList = tp; 91 } 92 if (t) 93 t->rest -= tp->rest; 94 95 #ifdef SIGALRM 96 sigsetmask(omask); 97 #endif 98 } 99 100 void 101 StopTimerNoBlock(tp) 102 struct pppTimer *tp; 103 { 104 struct pppTimer *t, *pt; 105 106 /* 107 * A Running Timer should be removing TimerList, 108 * But STOPPED/EXPIRED is already removing TimerList. 109 * So just marked as TIMER_STOPPED. 110 * Do not change tp->enext!! (Might be Called by expired proc) 111 */ 112 #ifdef DEBUG 113 logprintf("StopTimer: %x, next = %x state=%x\n", tp, tp->next, tp->state); 114 #endif 115 if (tp->state != TIMER_RUNNING) { 116 tp->next = NULL; 117 tp->state = TIMER_STOPPED; 118 return; 119 } 120 121 pt = NULL; 122 for (t = TimerList; t != tp && t !=NULL ; t = t->next) 123 pt = t; 124 if (t) { 125 if (pt) { 126 pt->next = t->next; 127 } else { 128 TimerList = t->next; 129 if ( TimerList == NULL ) /* Last one ? */ 130 TermTimerService(); /* Terminate Timer Service */ 131 } 132 if (t->next) 133 t->next->rest += tp->rest; 134 } else { 135 logprintf("Oops, timer not found!!\n"); 136 } 137 tp->next = NULL; 138 tp->state = TIMER_STOPPED; 139 } 140 141 /* 142 This is used to decide at the top level if it's time for a TimerService() 143 call. This'll work fine as long as select() is interrupted by the 144 SIGALRM. 145 */ 146 int TimerServiceRequest = 0; 147 148 void 149 SetTimerServiceRequest( int Sig ) 150 { 151 /* Maybe a bit cautious.... */ 152 if( TimerServiceRequest >= 0 ) 153 TimerServiceRequest++; 154 #ifdef DEBUG 155 logprintf( "Setting TimerServiceRequest\n" ); 156 #endif 157 } 158 159 void 160 TimerService() 161 { 162 struct pppTimer *tp, *exp, *wt; 163 164 #ifdef DEBUG 165 ShowTimers(); 166 #endif 167 tp = TimerList; 168 if (tp) { 169 tp->rest--; 170 if (tp->rest == 0) { 171 /* 172 * Multiple timers may expires at once. Create list of expired timers. 173 */ 174 exp = NULL; 175 do { 176 tp->state = TIMER_EXPIRED; 177 wt = tp->next; 178 tp->enext = exp; 179 exp = tp; 180 #ifdef DEBUG 181 logprintf("Add %x to exp\n", tp); 182 #endif 183 tp = wt; 184 } while (tp && (tp->rest == 0)); 185 186 TimerList = tp; 187 if ( TimerList == NULL ) /* No timers ? */ 188 TermTimerService(); /* Terminate Timer Service */ 189 #ifdef DEBUG 190 logprintf("TimerService: next is %x(%d)\n", 191 TimerList, TimerList? TimerList->rest : 0); 192 #endif 193 /* 194 * Process all expired timers. 195 */ 196 while (exp) { 197 #ifdef notdef 198 StopTimer(exp); 199 #endif 200 if (exp->func) 201 (*exp->func)(exp->arg); 202 /* 203 * Just Removing each item from expired list 204 * And exp->enext will be intialized at next expire 205 * in this funtion. 206 */ 207 exp = exp->enext; 208 } 209 } 210 } 211 } 212 213 void 214 ShowTimers() 215 { 216 struct pppTimer *pt; 217 218 logprintf("---- Begin of Timer Service List---\n"); 219 for (pt = TimerList; pt; pt = pt->next) 220 logprintf("%x: load = %d, rest = %d, state =%x\n", 221 pt, pt->load, pt->rest, pt->state); 222 logprintf("---- End of Timer Service List ---\n"); 223 } 224 225 #ifdef SIGALRM 226 u_int 227 sleep( u_int sec ) 228 { 229 struct timeval to,st,et; 230 long sld, nwd, std; 231 232 gettimeofday( &st, NULL ); 233 to.tv_sec = sec; 234 to.tv_usec = 0; 235 std = st.tv_sec * 1000000 + st.tv_usec; 236 for (;;) { 237 if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 238 errno != EINTR ) { 239 break; 240 } else { 241 gettimeofday( &et, NULL ); 242 sld = to.tv_sec * 1000000 + to.tv_sec; 243 nwd = et.tv_sec * 1000000 + et.tv_usec - std; 244 if ( sld > nwd ) 245 sld -= nwd; 246 else 247 sld = 1; /* Avoid both tv_sec/usec is 0 */ 248 249 /* Calculate timeout value for select */ 250 to.tv_sec = sld / 1000000; 251 to.tv_usec = sld % 1000000; 252 } 253 } 254 return (0L); 255 } 256 257 void usleep( u_int usec) 258 { 259 struct timeval to,st,et; 260 long sld, nwd, std; 261 262 gettimeofday( &st, NULL ); 263 to.tv_sec = 0; 264 to.tv_usec = usec; 265 std = st.tv_sec * 1000000 + st.tv_usec; 266 for (;;) { 267 if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 268 errno != EINTR ) { 269 break; 270 } else { 271 gettimeofday( &et, NULL ); 272 sld = to.tv_sec * 1000000 + to.tv_sec; 273 nwd = et.tv_sec * 1000000 + et.tv_usec - std; 274 if ( sld > nwd ) 275 sld -= nwd; 276 else 277 sld = 1; /* Avoid both tv_sec/usec is 0 */ 278 279 /* Calculate timeout value for select */ 280 to.tv_sec = sld / 1000000; 281 to.tv_usec = sld % 1000000; 282 283 } 284 } 285 } 286 287 void InitTimerService( void ) { 288 struct itimerval itimer; 289 290 /* 291 Let's not do this - it's a bit dangerous (potential recursion into the 292 likes of malloc() etc. 293 294 signal(SIGALRM, (void (*)(int))TimerService); 295 */ 296 signal(SIGALRM, SetTimerServiceRequest); 297 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 298 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT; 299 setitimer(ITIMER_REAL, &itimer, NULL); 300 } 301 302 void TermTimerService( void ) { 303 struct itimerval itimer; 304 305 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 306 itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0; 307 setitimer(ITIMER_REAL, &itimer, NULL); 308 /* 309 * Notes: after disabling timer here, we will get one 310 * SIGALRM will be got. 311 */ 312 signal(SIGALRM, SIG_IGN); 313 } 314 #endif 315