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