xref: /freebsd/usr.sbin/ppp/timer.c (revision 3e0f6b97b257a96f7275e4442204263e44b16686)
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$
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
31 void StopTimerNoBlock( struct pppTimer *);
32 void ShowTimers(void);
33 
34 void
35 StopTimer( 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 }
46 void
47 StartTimer(tp)
48 struct 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 
100 void
101 StopTimerNoBlock(tp)
102 struct 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 
141 /*
142   This is used to decide at the top level if it's time for a TimerService()
143   call.  This'll work fine as long as select() is interrupted by the
144   SIGALRM.
145 */
146 int TimerServiceRequest = 0;
147 
148 void
149 SetTimerServiceRequest( int Sig )
150 {
151   /* Maybe a bit cautious.... */
152   if( TimerServiceRequest >= 0 )
153     TimerServiceRequest++;
154 #ifdef DEBUG
155   logprintf( "Setting TimerServiceRequest\n" );
156 #endif
157 }
158 
159 void
160 TimerService()
161 {
162   struct pppTimer *tp, *exp, *wt;
163 
164 #ifdef DEBUG
165   ShowTimers();
166 #endif
167   tp = TimerList;
168   if (tp) {
169     tp->rest--;
170     if (tp->rest == 0) {
171       /*
172        * Multiple timers may expires at once. Create list of expired timers.
173        */
174       exp = NULL;
175       do {
176 	tp->state = TIMER_EXPIRED;
177 	wt = tp->next;
178 	tp->enext = exp;
179 	exp = tp;
180 #ifdef DEBUG
181 	logprintf("Add %x to exp\n", tp);
182 #endif
183 	tp = wt;
184       } while (tp && (tp->rest == 0));
185 
186       TimerList = tp;
187       if ( TimerList == NULL )			/* No timers ? */
188 	 TermTimerService();			/* Terminate Timer Service */
189 #ifdef DEBUG
190       logprintf("TimerService: next is %x(%d)\n",
191 		TimerList, TimerList? TimerList->rest : 0);
192 #endif
193       /*
194        * Process all expired timers.
195        */
196       while (exp) {
197 #ifdef notdef
198 	StopTimer(exp);
199 #endif
200 	if (exp->func)
201 	  (*exp->func)(exp->arg);
202 	/*
203          * Just Removing each item from expired list
204          * And exp->enext will be intialized at next expire
205          * in this funtion.
206          */
207 	exp =  exp->enext;
208       }
209     }
210   }
211 }
212 
213 void
214 ShowTimers()
215 {
216   struct pppTimer *pt;
217 
218   logprintf("---- Begin of Timer Service List---\n");
219   for (pt = TimerList; pt; pt = pt->next)
220     logprintf("%x: load = %d, rest = %d, state =%x\n",
221 	pt, pt->load, pt->rest, pt->state);
222   logprintf("---- End of Timer Service List ---\n");
223 }
224 
225 #ifdef SIGALRM
226 u_int
227 sleep( u_int sec )
228 {
229   struct timeval  to,st,et;
230   long sld, nwd, std;
231 
232   gettimeofday( &st, NULL );
233   to.tv_sec =  sec;
234   to.tv_usec = 0;
235   std = st.tv_sec * 1000000 + st.tv_usec;
236   for (;;) {
237     if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
238          errno != EINTR ) {
239        break;
240     } else  {
241        gettimeofday( &et, NULL );
242        sld = to.tv_sec * 1000000 + to.tv_sec;
243        nwd = et.tv_sec * 1000000 + et.tv_usec - std;
244        if ( sld > nwd )
245           sld -= nwd;
246        else
247           sld  = 1; /* Avoid both tv_sec/usec is 0 */
248 
249        /* Calculate timeout value for select */
250        to.tv_sec  = sld / 1000000;
251        to.tv_usec = sld % 1000000;
252     }
253   }
254   return (0L);
255 }
256 
257 void usleep( u_int usec)
258 {
259   struct timeval  to,st,et;
260   long sld, nwd, std;
261 
262   gettimeofday( &st, NULL );
263   to.tv_sec =  0;
264   to.tv_usec = usec;
265   std = st.tv_sec * 1000000 + st.tv_usec;
266   for (;;) {
267     if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
268          errno != EINTR ) {
269        break;
270     } else  {
271        gettimeofday( &et, NULL );
272        sld = to.tv_sec * 1000000 + to.tv_sec;
273        nwd = et.tv_sec * 1000000 + et.tv_usec - std;
274        if ( sld > nwd )
275           sld -= nwd;
276        else
277           sld  = 1; /* Avoid both tv_sec/usec is 0 */
278 
279        /* Calculate timeout value for select */
280        to.tv_sec  = sld / 1000000;
281        to.tv_usec = sld % 1000000;
282 
283     }
284   }
285 }
286 
287 void InitTimerService( void ) {
288   struct itimerval itimer;
289 
290   /*
291      Let's not do this - it's a bit dangerous (potential recursion into the
292      likes of malloc() etc.
293 
294      signal(SIGALRM, (void (*)(int))TimerService);
295   */
296   signal(SIGALRM, SetTimerServiceRequest);
297   itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
298   itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
299   setitimer(ITIMER_REAL, &itimer, NULL);
300 }
301 
302 void TermTimerService( void ) {
303   struct itimerval itimer;
304 
305   itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
306   itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
307   setitimer(ITIMER_REAL, &itimer, NULL);
308   /*
309    * Notes: after disabling timer here, we will get one
310    *        SIGALRM will be got.
311    */
312   signal(SIGALRM, SIG_IGN);
313 }
314 #endif
315