timer.c revision 25616
1101704Smjacob/* 2101704Smjacob * PPP Timer Processing Module 3101704Smjacob * 4101704Smjacob * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5101704Smjacob * 6101704Smjacob * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7101704Smjacob * 8101704Smjacob * Redistribution and use in source and binary forms are permitted 9101704Smjacob * provided that the above copyright notice and this paragraph are 10101704Smjacob * duplicated in all such forms and that any documentation, 11101704Smjacob * advertising materials, and other materials related to such 12101704Smjacob * distribution and use acknowledge that the software was developed 13101704Smjacob * by the Internet Initiative Japan, Inc. The name of the 14101704Smjacob * IIJ may not be used to endorse or promote products derived 15101704Smjacob * from this software without specific prior written permission. 16101704Smjacob * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17101704Smjacob * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18101704Smjacob * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19101704Smjacob * 20101704Smjacob * $Id: timer.c,v 1.14 1997/03/13 12:45:26 brian Exp $ 21101704Smjacob * 22101704Smjacob * TODO: 23101704Smjacob */ 24101704Smjacob#include "defs.h" 25101704Smjacob#include <sys/time.h> 26101704Smjacob#include <signal.h> 27101704Smjacob#include "timeout.h" 28101704Smjacob#ifdef SIGALRM 29101704Smjacob#include <errno.h> 30101704Smjacob#endif 31101704Smjacob#include "sig.h" 32101704Smjacob 33101704Smjacobvoid StopTimerNoBlock( struct pppTimer *); 34101704Smjacobvoid ShowTimers(void); 35101704Smjacob 36101704Smjacobvoid 37101704SmjacobStopTimer( struct pppTimer *tp ) 38101704Smjacob{ 39101704Smjacob#ifdef SIGALRM 40101704Smjacob int omask; 41101704Smjacob omask = sigblock(sigmask(SIGALRM)); 42101704Smjacob#endif 43101704Smjacob StopTimerNoBlock(tp); 44101704Smjacob#ifdef SIGALRM 45101704Smjacob sigsetmask(omask); 46101704Smjacob#endif 47101704Smjacob} 48101704Smjacobvoid 49101704SmjacobStartTimer(tp) 50101704Smjacobstruct pppTimer *tp; 51101704Smjacob{ 52101704Smjacob struct pppTimer *t, *pt; 53101704Smjacob u_long ticks = 0; 54101704Smjacob 55101704Smjacob#ifdef SIGALRM 56101704Smjacob int omask; 57101704Smjacob omask = sigblock(sigmask(SIGALRM)); 58101704Smjacob#endif 59101704Smjacob 60101704Smjacob if (tp->state != TIMER_STOPPED) { 61101704Smjacob StopTimerNoBlock(tp); 62101704Smjacob } 63101704Smjacob if (tp->load == 0) { 64101704Smjacob#ifdef DEBUG 65101704Smjacob logprintf("timer %x has 0 load!\n", tp); 66101704Smjacob#endif 67101704Smjacob sigsetmask(omask); 68101704Smjacob return; 69101704Smjacob } 70101704Smjacob pt = NULL; 71101704Smjacob for (t = TimerList; t; t = t->next) { 72101704Smjacob#ifdef DEBUG 73101704Smjacob logprintf("StartTimer: %x(%d): ticks: %d, rest: %d\n", t, t->state, ticks, t->rest); 74101704Smjacob#endif 75101704Smjacob if (ticks + t->rest >= tp->load) 76101704Smjacob break; 77101704Smjacob ticks += t->rest; 78101704Smjacob pt = t; 79101704Smjacob } 80101704Smjacob 81101704Smjacob tp->state = TIMER_RUNNING; 82101704Smjacob tp->rest = tp->load - ticks; 83101704Smjacob#ifdef DEBUG 84101704Smjacob logprintf("Inserting %x before %x, rest = %d\n", tp, t, tp->rest); 85101704Smjacob#endif 86101704Smjacob /* Insert given *tp just before *t */ 87101704Smjacob tp->next = t; 88101704Smjacob if (pt) { 89101704Smjacob pt->next = tp; 90101704Smjacob } else { 91101704Smjacob InitTimerService(); 92101704Smjacob TimerList = tp; 93101704Smjacob } 94101704Smjacob if (t) 95101704Smjacob t->rest -= tp->rest; 96101704Smjacob 97101704Smjacob#ifdef SIGALRM 98101704Smjacob sigsetmask(omask); 99101704Smjacob#endif 100101704Smjacob} 101101704Smjacob 102101704Smjacobvoid 103101704SmjacobStopTimerNoBlock(tp) 104101704Smjacobstruct pppTimer *tp; 105101704Smjacob{ 106101704Smjacob struct pppTimer *t, *pt; 107101704Smjacob 108101704Smjacob /* 109101704Smjacob * A Running Timer should be removing TimerList, 110101704Smjacob * But STOPPED/EXPIRED is already removing TimerList. 111101704Smjacob * So just marked as TIMER_STOPPED. 112101704Smjacob * Do not change tp->enext!! (Might be Called by expired proc) 113101704Smjacob */ 114101704Smjacob#ifdef DEBUG 115101704Smjacob logprintf("StopTimer: %x, next = %x state=%x\n", tp, tp->next, tp->state); 116101704Smjacob#endif 117101704Smjacob if (tp->state != TIMER_RUNNING) { 118101704Smjacob tp->next = NULL; 119101704Smjacob tp->state = TIMER_STOPPED; 120101704Smjacob return; 121101704Smjacob } 122101704Smjacob 123101704Smjacob pt = NULL; 124101704Smjacob for (t = TimerList; t != tp && t !=NULL ; t = t->next) 125101704Smjacob pt = t; 126101704Smjacob if (t) { 127101704Smjacob if (pt) { 128101704Smjacob pt->next = t->next; 129101704Smjacob } else { 130101704Smjacob TimerList = t->next; 131101704Smjacob if ( TimerList == NULL ) /* Last one ? */ 132101704Smjacob TermTimerService(); /* Terminate Timer Service */ 133101704Smjacob } 134101704Smjacob if (t->next) 135101704Smjacob t->next->rest += tp->rest; 136101704Smjacob } else { 137101704Smjacob logprintf("Oops, timer not found!!\n"); 138101704Smjacob } 139101704Smjacob tp->next = NULL; 140101704Smjacob tp->state = TIMER_STOPPED; 141101704Smjacob} 142101704Smjacob 143101704Smjacobvoid 144101704SmjacobTimerService() 145101704Smjacob{ 146101704Smjacob struct pppTimer *tp, *exp, *wt; 147101704Smjacob 148101704Smjacob#ifdef DEBUG 149101704Smjacob ShowTimers(); 150101704Smjacob#endif 151101704Smjacob tp = TimerList; 152101704Smjacob if (tp) { 153101704Smjacob tp->rest--; 154101704Smjacob if (tp->rest == 0) { 155101704Smjacob /* 156101704Smjacob * Multiple timers may expires at once. Create list of expired timers. 157101704Smjacob */ 158101704Smjacob exp = NULL; 159101704Smjacob do { 160101704Smjacob tp->state = TIMER_EXPIRED; 161101704Smjacob wt = tp->next; 162101704Smjacob tp->enext = exp; 163101704Smjacob exp = tp; 164101704Smjacob#ifdef DEBUG 165101704Smjacob logprintf("Add %x to exp\n", tp); 166101704Smjacob#endif 167101704Smjacob tp = wt; 168101704Smjacob } while (tp && (tp->rest == 0)); 169101704Smjacob 170101704Smjacob TimerList = tp; 171101704Smjacob if ( TimerList == NULL ) /* No timers ? */ 172101704Smjacob TermTimerService(); /* Terminate Timer Service */ 173101704Smjacob#ifdef DEBUG 174101704Smjacob logprintf("TimerService: next is %x(%d)\n", 175101704Smjacob TimerList, TimerList? TimerList->rest : 0); 176101704Smjacob#endif 177101704Smjacob /* 178101704Smjacob * Process all expired timers. 179101704Smjacob */ 180101704Smjacob while (exp) { 181101704Smjacob#ifdef notdef 182101704Smjacob StopTimer(exp); 183101704Smjacob#endif 184101704Smjacob if (exp->func) 185101704Smjacob (*exp->func)(exp->arg); 186101704Smjacob /* 187101704Smjacob * Just Removing each item from expired list 188101704Smjacob * And exp->enext will be intialized at next expire 189101704Smjacob * in this funtion. 190101704Smjacob */ 191101704Smjacob exp = exp->enext; 192101704Smjacob } 193101704Smjacob } 194101704Smjacob } 195101704Smjacob} 196101704Smjacob 197101704Smjacobvoid 198101704SmjacobShowTimers() 199101704Smjacob{ 200101704Smjacob struct pppTimer *pt; 201101704Smjacob 202101704Smjacob logprintf("---- Begin of Timer Service List---\n"); 203101704Smjacob for (pt = TimerList; pt; pt = pt->next) 204101704Smjacob logprintf("%x: load = %d, rest = %d, state =%x\n", 205101704Smjacob pt, pt->load, pt->rest, pt->state); 206101704Smjacob logprintf("---- End of Timer Service List ---\n"); 207101704Smjacob} 208101704Smjacob 209101704Smjacob#ifdef SIGALRM 210101704Smjacobu_int 211101704Smjacobsleep( u_int sec ) 212101704Smjacob{ 213101704Smjacob struct timeval to,st,et; 214101704Smjacob long sld, nwd, std; 215101704Smjacob 216101704Smjacob gettimeofday( &st, NULL ); 217101704Smjacob to.tv_sec = sec; 218101704Smjacob to.tv_usec = 0; 219101704Smjacob std = st.tv_sec * 1000000 + st.tv_usec; 220101704Smjacob for (;;) { 221101704Smjacob if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 222101704Smjacob errno != EINTR ) { 223101704Smjacob break; 224101704Smjacob } else { 225101704Smjacob gettimeofday( &et, NULL ); 226101704Smjacob sld = to.tv_sec * 1000000 + to.tv_sec; 227101704Smjacob nwd = et.tv_sec * 1000000 + et.tv_usec - std; 228101704Smjacob if ( sld > nwd ) 229101704Smjacob sld -= nwd; 230101704Smjacob else 231101704Smjacob sld = 1; /* Avoid both tv_sec/usec is 0 */ 232101704Smjacob 233101704Smjacob /* Calculate timeout value for select */ 234101704Smjacob to.tv_sec = sld / 1000000; 235101704Smjacob to.tv_usec = sld % 1000000; 236101704Smjacob } 237101704Smjacob } 238101704Smjacob return (0L); 239101704Smjacob} 240101704Smjacob 241101704Smjacobvoid usleep( u_int usec) 242101704Smjacob{ 243101704Smjacob struct timeval to,st,et; 244101704Smjacob long sld, nwd, std; 245101704Smjacob 246101704Smjacob gettimeofday( &st, NULL ); 247101704Smjacob to.tv_sec = 0; 248101704Smjacob to.tv_usec = usec; 249101704Smjacob std = st.tv_sec * 1000000 + st.tv_usec; 250101704Smjacob for (;;) { 251101704Smjacob if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 252101704Smjacob errno != EINTR ) { 253101704Smjacob break; 254101704Smjacob } else { 255101704Smjacob gettimeofday( &et, NULL ); 256101704Smjacob sld = to.tv_sec * 1000000 + to.tv_sec; 257101704Smjacob nwd = et.tv_sec * 1000000 + et.tv_usec - std; 258101704Smjacob if ( sld > nwd ) 259101704Smjacob sld -= nwd; 260101704Smjacob else 261101704Smjacob sld = 1; /* Avoid both tv_sec/usec is 0 */ 262101704Smjacob 263101704Smjacob /* Calculate timeout value for select */ 264101704Smjacob to.tv_sec = sld / 1000000; 265101704Smjacob to.tv_usec = sld % 1000000; 266101704Smjacob 267101704Smjacob } 268101704Smjacob } 269101704Smjacob} 270101704Smjacob 271101704Smjacobvoid InitTimerService( void ) { 272101704Smjacob struct itimerval itimer; 273101704Smjacob 274101704Smjacob pending_signal(SIGALRM, (void (*)(int))TimerService); 275101704Smjacob itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 276101704Smjacob itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT; 277101704Smjacob setitimer(ITIMER_REAL, &itimer, NULL); 278101704Smjacob} 279101704Smjacob 280101704Smjacobvoid TermTimerService( void ) { 281101704Smjacob struct itimerval itimer; 282101704Smjacob 283101704Smjacob itimer.it_interval.tv_usec = itimer.it_interval.tv_sec = 0; 284101704Smjacob itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0; 285101704Smjacob setitimer(ITIMER_REAL, &itimer, NULL); 286101704Smjacob pending_signal(SIGALRM, SIG_IGN); 287101704Smjacob} 288101704Smjacob#endif 289101704Smjacob