xref: /freebsd/usr.sbin/ppp/timer.c (revision 02f2e93b60c2b91feac8f45c4c889a5a8e40d8a2)
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.21 1997/10/24 22:36:31 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 "mbuf.h"
33 #include "log.h"
34 #include "defs.h"
35 #include "sig.h"
36 #include "timer.h"
37 
38 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 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 u_int
209 nointr_sleep(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 
239 void
240 nointr_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 
270 static void
271 InitTimerService()
272 {
273   struct itimerval itimer;
274 
275   pending_signal(SIGALRM, (void (*) (int)) TimerService);
276   itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
277   itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
278   if (setitimer(ITIMER_REAL, &itimer, NULL) == -1)
279     LogPrintf(LogERROR, "Unable to set itimer.\n");
280 }
281 
282 void
283 TermTimerService(void)
284 {
285   struct itimerval itimer;
286 
287   itimer.it_interval.tv_usec = itimer.it_interval.tv_sec = 0;
288   itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
289   if (setitimer(ITIMER_REAL, &itimer, NULL) == -1)
290     LogPrintf(LogERROR, "Unable to set itimer.\n");
291   pending_signal(SIGALRM, SIG_IGN);
292 }
293 
294 #endif
295