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