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