timer.c revision 21673
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 * $FreeBSD: head/usr.sbin/ppp/timer.c 21673 1997-01-14 07:20:47Z jkh $
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  tp = TimerList;
150  if (tp) {
151    tp->rest--;
152    if (tp->rest == 0) {
153      /*
154       * Multiple timers may expires at once. Create list of expired timers.
155       */
156      exp = NULL;
157      do {
158	tp->state = TIMER_EXPIRED;
159	wt = tp->next;
160	tp->enext = exp;
161	exp = tp;
162#ifdef DEBUG
163	logprintf("Add %x to exp\n", tp);
164#endif
165	tp = wt;
166      } while (tp && (tp->rest == 0));
167
168      TimerList = tp;
169      if ( TimerList == NULL )			/* No timers ? */
170	 TermTimerService();			/* Terminate Timer Service */
171#ifdef DEBUG
172      logprintf("TimerService: next is %x(%d)\n",
173		TimerList, TimerList? TimerList->rest : 0);
174#endif
175      /*
176       * Process all expired timers.
177       */
178      while (exp) {
179#ifdef notdef
180	StopTimer(exp);
181#endif
182	if (exp->func)
183	  (*exp->func)(exp->arg);
184	/*
185         * Just Removing each item from expired list
186         * And exp->enext will be intialized at next expire
187         * in this funtion.
188         */
189	exp =  exp->enext;
190      }
191    }
192  }
193}
194
195void
196ShowTimers()
197{
198  struct pppTimer *pt;
199
200  logprintf("---- Begin of Timer Service List---\n");
201  for (pt = TimerList; pt; pt = pt->next)
202    logprintf("%x: load = %d, rest = %d, state =%x\n",
203	pt, pt->load, pt->rest, pt->state);
204  logprintf("---- End of Timer Service List ---\n");
205}
206
207#ifdef SIGALRM
208u_int
209sleep( u_int sec )
210{
211  struct timeval  to,st,et;
212  long sld, nwd, std;
213
214  gettimeofday( &st, NULL );
215  to.tv_sec =  sec;
216  to.tv_usec = 0;
217  std = st.tv_sec * 1000000 + st.tv_usec;
218  for (;;) {
219    if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
220         errno != EINTR ) {
221       break;
222    } else  {
223       gettimeofday( &et, NULL );
224       sld = to.tv_sec * 1000000 + to.tv_sec;
225       nwd = et.tv_sec * 1000000 + et.tv_usec - std;
226       if ( sld > nwd )
227          sld -= nwd;
228       else
229          sld  = 1; /* Avoid both tv_sec/usec is 0 */
230
231       /* Calculate timeout value for select */
232       to.tv_sec  = sld / 1000000;
233       to.tv_usec = sld % 1000000;
234    }
235  }
236  return (0L);
237}
238
239void usleep( u_int usec)
240{
241  struct timeval  to,st,et;
242  long sld, nwd, std;
243
244  gettimeofday( &st, NULL );
245  to.tv_sec =  0;
246  to.tv_usec = usec;
247  std = st.tv_sec * 1000000 + st.tv_usec;
248  for (;;) {
249    if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
250         errno != EINTR ) {
251       break;
252    } else  {
253       gettimeofday( &et, NULL );
254       sld = to.tv_sec * 1000000 + to.tv_sec;
255       nwd = et.tv_sec * 1000000 + et.tv_usec - std;
256       if ( sld > nwd )
257          sld -= nwd;
258       else
259          sld  = 1; /* Avoid both tv_sec/usec is 0 */
260
261       /* Calculate timeout value for select */
262       to.tv_sec  = sld / 1000000;
263       to.tv_usec = sld % 1000000;
264
265    }
266  }
267}
268
269void InitTimerService( void ) {
270  struct itimerval itimer;
271
272  signal(SIGALRM, (void (*)(int))TimerService);
273  itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
274  itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
275  setitimer(ITIMER_REAL, &itimer, NULL);
276}
277
278void TermTimerService( void ) {
279  struct itimerval itimer;
280
281  itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
282  itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
283  setitimer(ITIMER_REAL, &itimer, NULL);
284  /*
285   * Notes: after disabling timer here, we will get one
286   *        SIGALRM will be got.
287   */
288  signal(SIGALRM, SIG_IGN);
289}
290#endif
291