timer.c revision 23585
1244953Sadrian/* 2244953Sadrian * PPP Timer Processing Module 3244953Sadrian * 4244953Sadrian * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5244953Sadrian * 6244953Sadrian * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7244953Sadrian * 8244953Sadrian * Redistribution and use in source and binary forms are permitted 9244953Sadrian * provided that the above copyright notice and this paragraph are 10244953Sadrian * duplicated in all such forms and that any documentation, 11244953Sadrian * advertising materials, and other materials related to such 12244953Sadrian * distribution and use acknowledge that the software was developed 13244953Sadrian * by the Internet Initiative Japan, Inc. The name of the 14244953Sadrian * IIJ may not be used to endorse or promote products derived 15244953Sadrian * from this software without specific prior written permission. 16244953Sadrian * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17244953Sadrian * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18244953Sadrian * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19244953Sadrian * 20244953Sadrian * $Id: timer.c,v 1.12 1997/03/09 20:03:51 ache Exp $ 21244953Sadrian * 22244953Sadrian * TODO: 23244953Sadrian */ 24244953Sadrian#include "defs.h" 25244953Sadrian#include <sys/time.h> 26244953Sadrian#include <signal.h> 27244953Sadrian#include "timeout.h" 28244953Sadrian#ifdef SIGALRM 29244953Sadrian#include <errno.h> 30244953Sadrian#endif 31244953Sadrianvoid StopTimerNoBlock( struct pppTimer *); 32244953Sadrianvoid ShowTimers(void); 33244953Sadrian 34244953Sadrianvoid 35244953SadrianStopTimer( struct pppTimer *tp ) 36244953Sadrian{ 37244953Sadrian#ifdef SIGALRM 38244953Sadrian int omask; 39244953Sadrian omask = sigblock(sigmask(SIGALRM)); 40244953Sadrian#endif 41244953Sadrian StopTimerNoBlock(tp); 42244953Sadrian#ifdef SIGALRM 43244953Sadrian sigsetmask(omask); 44244953Sadrian#endif 45244953Sadrian} 46244953Sadrianvoid 47244953SadrianStartTimer(tp) 48244953Sadrianstruct pppTimer *tp; 49244953Sadrian{ 50244953Sadrian struct pppTimer *t, *pt; 51244953Sadrian u_long ticks = 0; 52244953Sadrian 53244953Sadrian#ifdef SIGALRM 54244953Sadrian int omask; 55244953Sadrian omask = sigblock(sigmask(SIGALRM)); 56244953Sadrian#endif 57244953Sadrian 58244953Sadrian if (tp->state != TIMER_STOPPED) { 59244953Sadrian StopTimerNoBlock(tp); 60244953Sadrian } 61244953Sadrian if (tp->load == 0) { 62244953Sadrian#ifdef DEBUG 63244953Sadrian logprintf("timer %x has 0 load!\n", tp); 64244953Sadrian#endif 65244953Sadrian sigsetmask(omask); 66244953Sadrian return; 67244953Sadrian } 68244953Sadrian pt = NULL; 69244953Sadrian for (t = TimerList; t; t = t->next) { 70244953Sadrian#ifdef DEBUG 71244953Sadrian logprintf("StartTimer: %x(%d): ticks: %d, rest: %d\n", t, t->state, ticks, t->rest); 72244953Sadrian#endif 73244953Sadrian if (ticks + t->rest >= tp->load) 74244953Sadrian break; 75244953Sadrian ticks += t->rest; 76244953Sadrian pt = t; 77244953Sadrian } 78244953Sadrian 79244953Sadrian tp->state = TIMER_RUNNING; 80244953Sadrian tp->rest = tp->load - ticks; 81244953Sadrian#ifdef DEBUG 82244953Sadrian logprintf("Inserting %x before %x, rest = %d\n", tp, t, tp->rest); 83244953Sadrian#endif 84244953Sadrian /* Insert given *tp just before *t */ 85244953Sadrian tp->next = t; 86244953Sadrian if (pt) { 87244953Sadrian pt->next = tp; 88244953Sadrian } else { 89244953Sadrian InitTimerService(); 90244953Sadrian TimerList = tp; 91244953Sadrian } 92244953Sadrian if (t) 93244953Sadrian t->rest -= tp->rest; 94244953Sadrian 95244953Sadrian#ifdef SIGALRM 96244953Sadrian sigsetmask(omask); 97244953Sadrian#endif 98244953Sadrian} 99244953Sadrian 100244953Sadrianvoid 101244953SadrianStopTimerNoBlock(tp) 102244953Sadrianstruct pppTimer *tp; 103244953Sadrian{ 104244953Sadrian struct pppTimer *t, *pt; 105244953Sadrian 106244953Sadrian /* 107244953Sadrian * A Running Timer should be removing TimerList, 108244953Sadrian * But STOPPED/EXPIRED is already removing TimerList. 109244953Sadrian * So just marked as TIMER_STOPPED. 110244953Sadrian * Do not change tp->enext!! (Might be Called by expired proc) 111244953Sadrian */ 112244953Sadrian#ifdef DEBUG 113244953Sadrian logprintf("StopTimer: %x, next = %x state=%x\n", tp, tp->next, tp->state); 114244953Sadrian#endif 115244953Sadrian if (tp->state != TIMER_RUNNING) { 116244953Sadrian tp->next = NULL; 117244953Sadrian tp->state = TIMER_STOPPED; 118244953Sadrian return; 119244953Sadrian } 120244953Sadrian 121244953Sadrian pt = NULL; 122244953Sadrian for (t = TimerList; t != tp && t !=NULL ; t = t->next) 123244953Sadrian pt = t; 124244953Sadrian if (t) { 125244953Sadrian if (pt) { 126244953Sadrian pt->next = t->next; 127244953Sadrian } else { 128244953Sadrian TimerList = t->next; 129244953Sadrian if ( TimerList == NULL ) /* Last one ? */ 130244953Sadrian TermTimerService(); /* Terminate Timer Service */ 131244953Sadrian } 132244953Sadrian if (t->next) 133244953Sadrian t->next->rest += tp->rest; 134244953Sadrian } else { 135244953Sadrian logprintf("Oops, timer not found!!\n"); 136244953Sadrian } 137244953Sadrian tp->next = NULL; 138244953Sadrian tp->state = TIMER_STOPPED; 139244953Sadrian} 140244953Sadrian 141244953Sadrianvoid 142244953SadrianTimerService() 143244953Sadrian{ 144244953Sadrian struct pppTimer *tp, *exp, *wt; 145244953Sadrian 146244953Sadrian#ifdef DEBUG 147244953Sadrian ShowTimers(); 148244953Sadrian#endif 149244953Sadrian tp = TimerList; 150244953Sadrian if (tp) { 151244953Sadrian tp->rest--; 152244953Sadrian if (tp->rest == 0) { 153244953Sadrian /* 154244953Sadrian * Multiple timers may expires at once. Create list of expired timers. 155244953Sadrian */ 156244953Sadrian exp = NULL; 157244953Sadrian do { 158244953Sadrian tp->state = TIMER_EXPIRED; 159244953Sadrian wt = tp->next; 160244953Sadrian tp->enext = exp; 161244953Sadrian exp = tp; 162244953Sadrian#ifdef DEBUG 163244953Sadrian logprintf("Add %x to exp\n", tp); 164244953Sadrian#endif 165244953Sadrian tp = wt; 166244953Sadrian } while (tp && (tp->rest == 0)); 167244953Sadrian 168244953Sadrian TimerList = tp; 169244953Sadrian if ( TimerList == NULL ) /* No timers ? */ 170244953Sadrian TermTimerService(); /* Terminate Timer Service */ 171244953Sadrian#ifdef DEBUG 172244953Sadrian logprintf("TimerService: next is %x(%d)\n", 173244953Sadrian TimerList, TimerList? TimerList->rest : 0); 174244953Sadrian#endif 175244953Sadrian /* 176244953Sadrian * Process all expired timers. 177244953Sadrian */ 178244953Sadrian while (exp) { 179244953Sadrian#ifdef notdef 180244953Sadrian StopTimer(exp); 181244953Sadrian#endif 182244953Sadrian if (exp->func) 183244953Sadrian (*exp->func)(exp->arg); 184244953Sadrian /* 185244953Sadrian * Just Removing each item from expired list 186244953Sadrian * And exp->enext will be intialized at next expire 187244953Sadrian * in this funtion. 188244953Sadrian */ 189244953Sadrian exp = exp->enext; 190244953Sadrian } 191244953Sadrian } 192244953Sadrian } 193244953Sadrian} 194244953Sadrian 195244953Sadrianvoid 196244953SadrianShowTimers() 197244953Sadrian{ 198244953Sadrian struct pppTimer *pt; 199244953Sadrian 200244953Sadrian logprintf("---- Begin of Timer Service List---\n"); 201244953Sadrian for (pt = TimerList; pt; pt = pt->next) 202244953Sadrian logprintf("%x: load = %d, rest = %d, state =%x\n", 203244953Sadrian pt, pt->load, pt->rest, pt->state); 204244953Sadrian logprintf("---- End of Timer Service List ---\n"); 205244953Sadrian} 206244953Sadrian 207244953Sadrian#ifdef SIGALRM 208244953Sadrianu_int 209244953Sadriansleep( u_int sec ) 210244953Sadrian{ 211244953Sadrian struct timeval to,st,et; 212244953Sadrian long sld, nwd, std; 213244953Sadrian 214244953Sadrian gettimeofday( &st, NULL ); 215244953Sadrian to.tv_sec = sec; 216244953Sadrian to.tv_usec = 0; 217244953Sadrian std = st.tv_sec * 1000000 + st.tv_usec; 218244953Sadrian for (;;) { 219244953Sadrian if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 220244953Sadrian errno != EINTR ) { 221244953Sadrian break; 222244953Sadrian } else { 223244953Sadrian gettimeofday( &et, NULL ); 224244953Sadrian sld = to.tv_sec * 1000000 + to.tv_sec; 225244953Sadrian nwd = et.tv_sec * 1000000 + et.tv_usec - std; 226244953Sadrian if ( sld > nwd ) 227244953Sadrian sld -= nwd; 228244953Sadrian else 229244953Sadrian sld = 1; /* Avoid both tv_sec/usec is 0 */ 230244953Sadrian 231244953Sadrian /* Calculate timeout value for select */ 232244953Sadrian to.tv_sec = sld / 1000000; 233244953Sadrian to.tv_usec = sld % 1000000; 234244953Sadrian } 235244953Sadrian } 236244953Sadrian return (0L); 237244953Sadrian} 238244953Sadrian 239244953Sadrianvoid usleep( u_int usec) 240244953Sadrian{ 241244953Sadrian struct timeval to,st,et; 242244953Sadrian long sld, nwd, std; 243244953Sadrian 244244953Sadrian gettimeofday( &st, NULL ); 245244953Sadrian to.tv_sec = 0; 246244953Sadrian to.tv_usec = usec; 247244953Sadrian std = st.tv_sec * 1000000 + st.tv_usec; 248244953Sadrian for (;;) { 249244953Sadrian if ( select ( 0, NULL, NULL, NULL, &to) == 0 || 250244953Sadrian errno != EINTR ) { 251244953Sadrian break; 252244953Sadrian } else { 253244953Sadrian gettimeofday( &et, NULL ); 254244953Sadrian sld = to.tv_sec * 1000000 + to.tv_sec; 255244953Sadrian nwd = et.tv_sec * 1000000 + et.tv_usec - std; 256244953Sadrian if ( sld > nwd ) 257244953Sadrian sld -= nwd; 258244953Sadrian else 259244953Sadrian sld = 1; /* Avoid both tv_sec/usec is 0 */ 260244953Sadrian 261244953Sadrian /* Calculate timeout value for select */ 262244953Sadrian to.tv_sec = sld / 1000000; 263244953Sadrian to.tv_usec = sld % 1000000; 264244953Sadrian 265244953Sadrian } 266244953Sadrian } 267244953Sadrian} 268244953Sadrian 269244953Sadrianvoid InitTimerService( void ) { 270244953Sadrian struct itimerval itimer; 271244953Sadrian 272244953Sadrian signal(SIGALRM, (void (*)(int))TimerService); 273244953Sadrian itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 274244953Sadrian itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT; 275244953Sadrian setitimer(ITIMER_REAL, &itimer, NULL); 276244953Sadrian} 277244953Sadrian 278244953Sadrianvoid TermTimerService( void ) { 279244953Sadrian struct itimerval itimer; 280244953Sadrian 281244953Sadrian itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0; 282244953Sadrian itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0; 283244953Sadrian setitimer(ITIMER_REAL, &itimer, NULL); 284244953Sadrian /* 285244953Sadrian * Notes: after disabling timer here, we will get one 286244953Sadrian * SIGALRM will be got. 287244953Sadrian */ 288244953Sadrian signal(SIGALRM, SIG_IGN); 289244953Sadrian} 290244953Sadrian#endif 291244953Sadrian