timer.c revision 6735
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#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    TimerList = tp;
90  if (t)
91    t->rest -= tp->rest;
92
93#ifdef SIGALRM
94  sigsetmask(omask);
95#endif
96}
97
98void
99StopTimerNoBlock(tp)
100struct pppTimer *tp;
101{
102  struct pppTimer *t, *pt;
103
104  /*
105   * A Running Timer should be removing TimerList,
106   * But STOPPED/EXPIRED is already removing TimerList.
107   * So just marked as TIMER_STOPPED.
108   * Do not change tp->enext!! (Might be Called by expired proc)
109   */
110#ifdef DEBUG
111  logprintf("StopTimer: %x, next = %x state=%x\n", tp, tp->next, tp->state);
112#endif
113  if (tp->state != TIMER_RUNNING) {
114    tp->next   = NULL;
115    tp->state  = TIMER_STOPPED;
116    return;
117  }
118
119  pt = NULL;
120  for (t = TimerList; t != tp && t !=NULL ; t = t->next)
121    pt = t;
122  if (t) {
123    if (pt)
124      pt->next = t->next;
125    else
126      TimerList = t->next;
127    if (t->next)
128      t->next->rest += tp->rest;
129  } else {
130    logprintf("Oops, timer not found!!\n");
131  }
132  tp->next = NULL;
133  tp->state = TIMER_STOPPED;
134}
135
136void
137TimerService()
138{
139  struct pppTimer *tp, *exp, *wt;
140
141#ifdef DEBUG
142  ShowTimers();
143#endif
144  if (tp = TimerList) {
145    tp->rest--;
146    if (tp->rest == 0) {
147      /*
148       * Multiple timers may expires at once. Create list of expired timers.
149       */
150      exp = NULL;
151      do {
152	tp->state = TIMER_EXPIRED;
153	wt = tp->next;
154	tp->enext = exp;
155	exp = tp;
156#ifdef DEBUG
157	logprintf("Add %x to exp\n", tp);
158#endif
159	tp = wt;
160      } while (tp && (tp->rest == 0));
161
162      TimerList = tp;
163#ifdef DEBUG
164      logprintf("TimerService: next is %x(%d)\n",
165		TimerList, TimerList? TimerList->rest : 0);
166#endif
167      /*
168       * Process all expired timers.
169       */
170      while (exp) {
171#ifdef notdef
172	StopTimer(exp);
173#endif
174	if (exp->func)
175	  (*exp->func)(exp->arg);
176	/*
177         * Just Removing each item from expired list
178         * And exp->enext will be intialized at next expire
179         * in this funtion.
180         */
181	exp =  exp->enext;
182      }
183    }
184  }
185}
186
187void
188ShowTimers()
189{
190  struct pppTimer *pt;
191
192  logprintf("---- Begin of Timer Service List---\n");
193  for (pt = TimerList; pt; pt = pt->next)
194    logprintf("%x: load = %d, rest = %d, state =%x\n",
195	pt, pt->load, pt->rest, pt->state);
196  logprintf("---- End of Timer Service List ---\n");
197}
198
199#ifdef SIGALRM
200u_int sleep( u_int sec )
201{
202  struct timeval  to,st,et;
203  long sld, nwd, std;
204
205  gettimeofday( &st, NULL );
206  to.tv_sec =  sec;
207  to.tv_usec = 0;
208  std = st.tv_sec * 1000000 + st.tv_usec;
209  for (;;) {
210    if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
211         errno != EINTR ) {
212       break;
213    } else  {
214       gettimeofday( &et, NULL );
215       sld = to.tv_sec * 1000000 + to.tv_sec;
216       nwd = et.tv_sec * 1000000 + et.tv_usec - std;
217       if ( sld > nwd )
218          sld -= nwd;
219       else
220          sld  = 1; /* Avoid both tv_sec/usec is 0 */
221
222       /* Calculate timeout value for select */
223       to.tv_sec  = sld / 1000000;
224       to.tv_usec = sld % 1000000;
225
226       /* Forwarding signal as normal */
227       kill(getpid(), SIGALRM);
228    }
229  }
230}
231
232void usleep( u_int usec)
233{
234  struct timeval  to,st,et;
235  long sld, nwd, std;
236
237  gettimeofday( &st, NULL );
238  to.tv_sec =  0;
239  to.tv_usec = usec;
240  std = st.tv_sec * 1000000 + st.tv_usec;
241  for (;;) {
242    if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
243         errno != EINTR ) {
244       break;
245    } else  {
246       gettimeofday( &et, NULL );
247       sld = to.tv_sec * 1000000 + to.tv_sec;
248       nwd = et.tv_sec * 1000000 + et.tv_usec - std;
249       if ( sld > nwd )
250          sld -= nwd;
251       else
252          sld  = 1; /* Avoid both tv_sec/usec is 0 */
253
254       /* Calculate timeout value for select */
255       to.tv_sec  = sld / 1000000;
256       to.tv_usec = sld % 1000000;
257
258       /* Forwarding signal as normal */
259       kill(getpid(), SIGALRM);
260    }
261  }
262}
263#endif
264