timer.c revision 23114
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.9 1997/02/22 16:10:59 peter Exp $
21 *
22 *  TODO:
23 */
24#include "defs.h"
25#include <sys/time.h>
26#include <signal.h>
27#include "timeout.h"
28#include <sys/cdefs.h>
29#include "sig.h"
30#ifdef SIGALRM
31#include <errno.h>
32#endif
33void StopTimerNoBlock( struct pppTimer *);
34void ShowTimers(void);
35
36void
37StopTimer( struct pppTimer *tp )
38{
39#ifdef SIGALRM
40  int	omask;
41  omask = sigblock(sigmask(SIGALRM));
42#endif
43  StopTimerNoBlock(tp);
44#ifdef SIGALRM
45  sigsetmask(omask);
46#endif
47}
48void
49StartTimer(tp)
50struct pppTimer *tp;
51{
52  struct pppTimer *t, *pt;
53  u_long ticks = 0;
54
55#ifdef SIGALRM
56  int	omask;
57  omask = sigblock(sigmask(SIGALRM));
58#endif
59
60  if (tp->state != TIMER_STOPPED) {
61    StopTimerNoBlock(tp);
62  }
63  if (tp->load == 0) {
64#ifdef DEBUG
65    logprintf("timer %x has 0 load!\n", tp);
66#endif
67    sigsetmask(omask);
68    return;
69  }
70  pt = NULL;
71  for (t = TimerList; t; t = t->next) {
72#ifdef DEBUG
73    logprintf("StartTimer: %x(%d):  ticks: %d, rest: %d\n", t, t->state, ticks, t->rest);
74#endif
75    if (ticks + t->rest >= tp->load)
76      break;
77    ticks += t->rest;
78    pt = t;
79  }
80
81  tp->state = TIMER_RUNNING;
82  tp->rest = tp->load - ticks;
83#ifdef DEBUG
84  logprintf("Inserting %x before %x, rest = %d\n", tp, t, tp->rest);
85#endif
86  /* Insert given *tp just before *t */
87  tp->next = t;
88  if (pt) {
89    pt->next = tp;
90  } else {
91    InitTimerService();
92    TimerList = tp;
93  }
94  if (t)
95    t->rest -= tp->rest;
96
97#ifdef SIGALRM
98  sigsetmask(omask);
99#endif
100}
101
102void
103StopTimerNoBlock(tp)
104struct pppTimer *tp;
105{
106  struct pppTimer *t, *pt;
107
108  /*
109   * A Running Timer should be removing TimerList,
110   * But STOPPED/EXPIRED is already removing TimerList.
111   * So just marked as TIMER_STOPPED.
112   * Do not change tp->enext!! (Might be Called by expired proc)
113   */
114#ifdef DEBUG
115  logprintf("StopTimer: %x, next = %x state=%x\n", tp, tp->next, tp->state);
116#endif
117  if (tp->state != TIMER_RUNNING) {
118    tp->next   = NULL;
119    tp->state  = TIMER_STOPPED;
120    return;
121  }
122
123  pt = NULL;
124  for (t = TimerList; t != tp && t !=NULL ; t = t->next)
125    pt = t;
126  if (t) {
127    if (pt) {
128      pt->next = t->next;
129    } else {
130      TimerList = t->next;
131      if ( TimerList == NULL )			/* Last one ? */
132	 TermTimerService();			/* Terminate Timer Service */
133    }
134    if (t->next)
135      t->next->rest += tp->rest;
136  } else {
137    logprintf("Oops, timer not found!!\n");
138  }
139  tp->next = NULL;
140  tp->state = TIMER_STOPPED;
141}
142
143void
144TimerService()
145{
146  struct pppTimer *tp, *exp, *wt;
147
148#ifdef DEBUG
149  ShowTimers();
150#endif
151  tp = TimerList;
152  if (tp) {
153    tp->rest--;
154    if (tp->rest == 0) {
155      /*
156       * Multiple timers may expires at once. Create list of expired timers.
157       */
158      exp = NULL;
159      do {
160	tp->state = TIMER_EXPIRED;
161	wt = tp->next;
162	tp->enext = exp;
163	exp = tp;
164#ifdef DEBUG
165	logprintf("Add %x to exp\n", tp);
166#endif
167	tp = wt;
168      } while (tp && (tp->rest == 0));
169
170      TimerList = tp;
171      if ( TimerList == NULL )			/* No timers ? */
172	 TermTimerService();			/* Terminate Timer Service */
173#ifdef DEBUG
174      logprintf("TimerService: next is %x(%d)\n",
175		TimerList, TimerList? TimerList->rest : 0);
176#endif
177      /*
178       * Process all expired timers.
179       */
180      while (exp) {
181#ifdef notdef
182	StopTimer(exp);
183#endif
184	if (exp->func)
185	  (*exp->func)(exp->arg);
186	/*
187         * Just Removing each item from expired list
188         * And exp->enext will be intialized at next expire
189         * in this funtion.
190         */
191	exp =  exp->enext;
192      }
193    }
194  }
195}
196
197void
198ShowTimers()
199{
200  struct pppTimer *pt;
201
202  logprintf("---- Begin of Timer Service List---\n");
203  for (pt = TimerList; pt; pt = pt->next)
204    logprintf("%x: load = %d, rest = %d, state =%x\n",
205	pt, pt->load, pt->rest, pt->state);
206  logprintf("---- End of Timer Service List ---\n");
207}
208
209#ifdef SIGALRM
210u_int
211sleep( u_int sec )
212{
213  struct timeval  to,st,et;
214  long sld, nwd, std;
215
216  gettimeofday( &st, NULL );
217  to.tv_sec =  sec;
218  to.tv_usec = 0;
219  std = st.tv_sec * 1000000 + st.tv_usec;
220  for (;;) {
221    if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
222         errno != EINTR ) {
223       break;
224    } else  {
225       gettimeofday( &et, NULL );
226       sld = to.tv_sec * 1000000 + to.tv_sec;
227       nwd = et.tv_sec * 1000000 + et.tv_usec - std;
228       if ( sld > nwd )
229          sld -= nwd;
230       else
231          sld  = 1; /* Avoid both tv_sec/usec is 0 */
232
233       /* Calculate timeout value for select */
234       to.tv_sec  = sld / 1000000;
235       to.tv_usec = sld % 1000000;
236    }
237  }
238  return (0L);
239}
240
241void usleep( u_int usec)
242{
243  struct timeval  to,st,et;
244  long sld, nwd, std;
245
246  gettimeofday( &st, NULL );
247  to.tv_sec =  0;
248  to.tv_usec = usec;
249  std = st.tv_sec * 1000000 + st.tv_usec;
250  for (;;) {
251    if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
252         errno != EINTR ) {
253       break;
254    } else  {
255       gettimeofday( &et, NULL );
256       sld = to.tv_sec * 1000000 + to.tv_sec;
257       nwd = et.tv_sec * 1000000 + et.tv_usec - std;
258       if ( sld > nwd )
259          sld -= nwd;
260       else
261          sld  = 1; /* Avoid both tv_sec/usec is 0 */
262
263       /* Calculate timeout value for select */
264       to.tv_sec  = sld / 1000000;
265       to.tv_usec = sld % 1000000;
266
267    }
268  }
269}
270
271void InitTimerService( void ) {
272  struct itimerval itimer;
273
274  pending_signal(SIGALRM, (void (*)(int))TimerService);
275  itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
276  itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
277  setitimer(ITIMER_REAL, &itimer, NULL);
278}
279
280void TermTimerService( void ) {
281  struct itimerval itimer;
282
283  itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
284  itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
285  setitimer(ITIMER_REAL, &itimer, NULL);
286  /*
287   * Notes: after disabling timer here, we will get one
288   *        SIGALRM will be got.
289   */
290  pending_signal(SIGALRM, SIG_IGN);
291}
292#endif
293