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