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 * $Id: timer.c,v 1.4 1995/05/30 03:50:59 rgrimes Exp $ 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 void 142 TimerService() 143 { 144 struct pppTimer *tp, *exp, *wt; 145 146 #ifdef DEBUG 147 ShowTimers(); 148 #endif 149 tp = TimerList; 150 if (tp) { 151 tp->rest--; 152 if (tp->rest == 0) { 153 /* 154 * Multiple timers may expires at once. Create list of expired timers. 155 */ 156 exp = NULL; 157 do { 158 tp->state = TIMER_EXPIRED; 159 wt = tp->next; 160 tp->enext = exp; 161 exp = tp; 162 #ifdef DEBUG 163 logprintf("Add %x to exp\n", tp); 164 #endif 165 tp = wt; 166 } while (tp && (tp->rest == 0)); 167 168 TimerList = tp; 169 if ( TimerList == NULL ) /* No timers ? */ 170 TermTimerService(); /* Terminate Timer Service */ 171 #ifdef DEBUG 172 logprintf("TimerService: next is %x(%d)\n", 173 TimerList, TimerList? TimerList->rest : 0); 174 #endif 175 /* 176 * Process all expired timers. 177 */ 178 while (exp) { 179 #ifdef notdef 180 StopTimer(exp); 181 #endif 182 if (exp->func) 183 (*exp->func)(exp->arg); 184 /* 185 * Just Removing each item from expired list 186 * And exp->enext will be intialized at next expire 187 * in this funtion. 188 */ 189 exp = exp->enext; 190 } 191 } 192 } 193 } 194 195 void 196 ShowTimers() 197 { 198 struct pppTimer *pt; 199 200 logprintf("---- Begin of Timer Service List---\n"); 201 for (pt = TimerList; pt; pt = pt->next) 202 logprintf("%x: load = %d, rest = %d, state =%x\n", 203 pt, pt->load, pt->rest, pt->state); 204 logprintf("---- End of Timer Service List ---\n"); 205 } 206 207 #ifdef SIGALRM 208 u_int 209 sleep( u_int sec ) 210 { 211 struct timeval to,st,et; 212 long sld, nwd, std; 213 214 gettimeofday( &st, NULL ); 215 to.tv_sec = sec; 216 to.tv_usec = 0; 217 std = st.tv_sec * 1000000 + st.tv_usec; 218 for (;;) { 219 if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 220 errno != EINTR ) { 221 break; 222 } else { 223 gettimeofday( &et, NULL ); 224 sld = to.tv_sec * 1000000 + to.tv_sec; 225 nwd = et.tv_sec * 1000000 + et.tv_usec - std; 226 if ( sld > nwd ) 227 sld -= nwd; 228 else 229 sld = 1; /* Avoid both tv_sec/usec is 0 */ 230 231 /* Calculate timeout value for select */ 232 to.tv_sec = sld / 1000000; 233 to.tv_usec = sld % 1000000; 234 } 235 } 236 return (0L); 237 } 238 239 void usleep( u_int usec) 240 { 241 struct timeval to,st,et; 242 long sld, nwd, std; 243 244 gettimeofday( &st, NULL ); 245 to.tv_sec = 0; 246 to.tv_usec = usec; 247 std = st.tv_sec * 1000000 + st.tv_usec; 248 for (;;) { 249 if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 250 errno != EINTR ) { 251 break; 252 } else { 253 gettimeofday( &et, NULL ); 254 sld = to.tv_sec * 1000000 + to.tv_sec; 255 nwd = et.tv_sec * 1000000 + et.tv_usec - std; 256 if ( sld > nwd ) 257 sld -= nwd; 258 else 259 sld = 1; /* Avoid both tv_sec/usec is 0 */ 260 261 /* Calculate timeout value for select */ 262 to.tv_sec = sld / 1000000; 263 to.tv_usec = sld % 1000000; 264 265 } 266 } 267 } 268 269 void InitTimerService( void ) { 270 struct itimerval itimer; 271 272 signal(SIGALRM, (void (*)(int))TimerService); 273 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 274 itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT; 275 setitimer(ITIMER_REAL, &itimer, NULL); 276 } 277 278 void TermTimerService( void ) { 279 struct itimerval itimer; 280 281 itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 282 itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0; 283 setitimer(ITIMER_REAL, &itimer, NULL); 284 /* 285 * Notes: after disabling timer here, we will get one 286 * SIGALRM will be got. 287 */ 288 signal(SIGALRM, SIG_IGN); 289 } 290 #endif 291