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