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 #include "sig.h" 29 #ifdef SIGALRM 30 #include <errno.h> 31 #endif 32 void StopTimerNoBlock( struct pppTimer *); 33 void ShowTimers(void); 34 35 void 36 StopTimer( struct pppTimer *tp ) 37 { 38 #ifdef SIGALRM 39 int omask; 40 omask = sigblock(sigmask(SIGALRM)); 41 #endif 42 StopTimerNoBlock(tp); 43 #ifdef SIGALRM 44 sigsetmask(omask); 45 #endif 46 } 47 void 48 StartTimer(tp) 49 struct pppTimer *tp; 50 { 51 struct pppTimer *t, *pt; 52 u_long ticks = 0; 53 54 #ifdef SIGALRM 55 int omask; 56 omask = sigblock(sigmask(SIGALRM)); 57 #endif 58 59 if (tp->state != TIMER_STOPPED) { 60 StopTimerNoBlock(tp); 61 } 62 if (tp->load == 0) { 63 #ifdef DEBUG 64 logprintf("timer %x has 0 load!\n", tp); 65 #endif 66 sigsetmask(omask); 67 return; 68 } 69 pt = NULL; 70 for (t = TimerList; t; t = t->next) { 71 #ifdef DEBUG 72 logprintf("StartTimer: %x(%d): ticks: %d, rest: %d\n", t, t->state, ticks, t->rest); 73 #endif 74 if (ticks + t->rest >= tp->load) 75 break; 76 ticks += t->rest; 77 pt = t; 78 } 79 80 tp->state = TIMER_RUNNING; 81 tp->rest = tp->load - ticks; 82 #ifdef DEBUG 83 logprintf("Inserting %x before %x, rest = %d\n", tp, t, tp->rest); 84 #endif 85 /* Insert given *tp just before *t */ 86 tp->next = t; 87 if (pt) { 88 pt->next = tp; 89 } else { 90 InitTimerService(); 91 TimerList = tp; 92 } 93 if (t) 94 t->rest -= tp->rest; 95 96 #ifdef SIGALRM 97 sigsetmask(omask); 98 #endif 99 } 100 101 void 102 StopTimerNoBlock(tp) 103 struct pppTimer *tp; 104 { 105 struct pppTimer *t, *pt; 106 107 /* 108 * A Running Timer should be removing TimerList, 109 * But STOPPED/EXPIRED is already removing TimerList. 110 * So just marked as TIMER_STOPPED. 111 * Do not change tp->enext!! (Might be Called by expired proc) 112 */ 113 #ifdef DEBUG 114 logprintf("StopTimer: %x, next = %x state=%x\n", tp, tp->next, tp->state); 115 #endif 116 if (tp->state != TIMER_RUNNING) { 117 tp->next = NULL; 118 tp->state = TIMER_STOPPED; 119 return; 120 } 121 122 pt = NULL; 123 for (t = TimerList; t != tp && t !=NULL ; t = t->next) 124 pt = t; 125 if (t) { 126 if (pt) { 127 pt->next = t->next; 128 } else { 129 TimerList = t->next; 130 if ( TimerList == NULL ) /* Last one ? */ 131 TermTimerService(); /* Terminate Timer Service */ 132 } 133 if (t->next) 134 t->next->rest += tp->rest; 135 } else { 136 logprintf("Oops, timer not found!!\n"); 137 } 138 tp->next = NULL; 139 tp->state = TIMER_STOPPED; 140 } 141 142 void 143 TimerService() 144 { 145 struct pppTimer *tp, *exp, *wt; 146 147 #ifdef DEBUG 148 ShowTimers(); 149 #endif 150 tp = TimerList; 151 if (tp) { 152 tp->rest--; 153 if (tp->rest == 0) { 154 /* 155 * Multiple timers may expires at once. Create list of expired timers. 156 */ 157 exp = NULL; 158 do { 159 tp->state = TIMER_EXPIRED; 160 wt = tp->next; 161 tp->enext = exp; 162 exp = tp; 163 #ifdef DEBUG 164 logprintf("Add %x to exp\n", tp); 165 #endif 166 tp = wt; 167 } while (tp && (tp->rest == 0)); 168 169 TimerList = tp; 170 if ( TimerList == NULL ) /* No timers ? */ 171 TermTimerService(); /* Terminate Timer Service */ 172 #ifdef DEBUG 173 logprintf("TimerService: next is %x(%d)\n", 174 TimerList, TimerList? TimerList->rest : 0); 175 #endif 176 /* 177 * Process all expired timers. 178 */ 179 while (exp) { 180 #ifdef notdef 181 StopTimer(exp); 182 #endif 183 if (exp->func) 184 (*exp->func)(exp->arg); 185 /* 186 * Just Removing each item from expired list 187 * And exp->enext will be intialized at next expire 188 * in this funtion. 189 */ 190 exp = exp->enext; 191 } 192 } 193 } 194 } 195 196 void 197 ShowTimers() 198 { 199 struct pppTimer *pt; 200 201 logprintf("---- Begin of Timer Service List---\n"); 202 for (pt = TimerList; pt; pt = pt->next) 203 logprintf("%x: load = %d, rest = %d, state =%x\n", 204 pt, pt->load, pt->rest, pt->state); 205 logprintf("---- End of Timer Service List ---\n"); 206 } 207 208 #ifdef SIGALRM 209 u_int 210 sleep( u_int sec ) 211 { 212 struct timeval to,st,et; 213 long sld, nwd, std; 214 215 gettimeofday( &st, NULL ); 216 to.tv_sec = sec; 217 to.tv_usec = 0; 218 std = st.tv_sec * 1000000 + st.tv_usec; 219 for (;;) { 220 if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 221 errno != EINTR ) { 222 break; 223 } else { 224 gettimeofday( &et, NULL ); 225 sld = to.tv_sec * 1000000 + to.tv_sec; 226 nwd = et.tv_sec * 1000000 + et.tv_usec - std; 227 if ( sld > nwd ) 228 sld -= nwd; 229 else 230 sld = 1; /* Avoid both tv_sec/usec is 0 */ 231 232 /* Calculate timeout value for select */ 233 to.tv_sec = sld / 1000000; 234 to.tv_usec = sld % 1000000; 235 } 236 } 237 return (0L); 238 } 239 240 void usleep( u_int usec) 241 { 242 struct timeval to,st,et; 243 long sld, nwd, std; 244 245 gettimeofday( &st, NULL ); 246 to.tv_sec = 0; 247 to.tv_usec = usec; 248 std = st.tv_sec * 1000000 + st.tv_usec; 249 for (;;) { 250 if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 251 errno != EINTR ) { 252 break; 253 } else { 254 gettimeofday( &et, NULL ); 255 sld = to.tv_sec * 1000000 + to.tv_sec; 256 nwd = et.tv_sec * 1000000 + et.tv_usec - std; 257 if ( sld > nwd ) 258 sld -= nwd; 259 else 260 sld = 1; /* Avoid both tv_sec/usec is 0 */ 261 262 /* Calculate timeout value for select */ 263 to.tv_sec = sld / 1000000; 264 to.tv_usec = sld % 1000000; 265 266 } 267 } 268 } 269 270 void InitTimerService( void ) { 271 struct itimerval itimer; 272 273 pending_signal(SIGALRM, (void (*)(int))TimerService); 274 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 275 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT; 276 setitimer(ITIMER_REAL, &itimer, NULL); 277 } 278 279 void TermTimerService( void ) { 280 struct itimerval itimer; 281 282 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 283 itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0; 284 setitimer(ITIMER_REAL, &itimer, NULL); 285 /* 286 * Notes: after disabling timer here, we will get one 287 * SIGALRM will be got. 288 */ 289 pending_signal(SIGALRM, SIG_IGN); 290 } 291 #endif 292