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