xref: /freebsd/usr.sbin/ppp/timer.c (revision 4a0f765fbf09711e612e86fce8bb09ec43f482d9)
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 #include "sig.h"
29 #ifdef SIGALRM
30 #include <errno.h>
31 #endif
32 void StopTimerNoBlock( struct pppTimer *);
33 void ShowTimers(void);
34 
35 void
36 StopTimer( struct pppTimer *tp )
37 {
38 #ifdef SIGALRM
39   int	omask;
40   omask = sigblock(sigmask(SIGALRM));
41 #endif
42   StopTimerNoBlock(tp);
43 #ifdef SIGALRM
44   sigsetmask(omask);
45 #endif
46 }
47 void
48 StartTimer(tp)
49 struct pppTimer *tp;
50 {
51   struct pppTimer *t, *pt;
52   u_long ticks = 0;
53 
54 #ifdef SIGALRM
55   int	omask;
56   omask = sigblock(sigmask(SIGALRM));
57 #endif
58 
59   if (tp->state != TIMER_STOPPED) {
60     StopTimerNoBlock(tp);
61   }
62   if (tp->load == 0) {
63 #ifdef DEBUG
64     logprintf("timer %x has 0 load!\n", tp);
65 #endif
66     sigsetmask(omask);
67     return;
68   }
69   pt = NULL;
70   for (t = TimerList; t; t = t->next) {
71 #ifdef DEBUG
72     logprintf("StartTimer: %x(%d):  ticks: %d, rest: %d\n", t, t->state, ticks, t->rest);
73 #endif
74     if (ticks + t->rest >= tp->load)
75       break;
76     ticks += t->rest;
77     pt = t;
78   }
79 
80   tp->state = TIMER_RUNNING;
81   tp->rest = tp->load - ticks;
82 #ifdef DEBUG
83   logprintf("Inserting %x before %x, rest = %d\n", tp, t, tp->rest);
84 #endif
85   /* Insert given *tp just before *t */
86   tp->next = t;
87   if (pt) {
88     pt->next = tp;
89   } else {
90     InitTimerService();
91     TimerList = tp;
92   }
93   if (t)
94     t->rest -= tp->rest;
95 
96 #ifdef SIGALRM
97   sigsetmask(omask);
98 #endif
99 }
100 
101 void
102 StopTimerNoBlock(tp)
103 struct pppTimer *tp;
104 {
105   struct pppTimer *t, *pt;
106 
107   /*
108    * A Running Timer should be removing TimerList,
109    * But STOPPED/EXPIRED is already removing TimerList.
110    * So just marked as TIMER_STOPPED.
111    * Do not change tp->enext!! (Might be Called by expired proc)
112    */
113 #ifdef DEBUG
114   logprintf("StopTimer: %x, next = %x state=%x\n", tp, tp->next, tp->state);
115 #endif
116   if (tp->state != TIMER_RUNNING) {
117     tp->next   = NULL;
118     tp->state  = TIMER_STOPPED;
119     return;
120   }
121 
122   pt = NULL;
123   for (t = TimerList; t != tp && t !=NULL ; t = t->next)
124     pt = t;
125   if (t) {
126     if (pt) {
127       pt->next = t->next;
128     } else {
129       TimerList = t->next;
130       if ( TimerList == NULL )			/* Last one ? */
131 	 TermTimerService();			/* Terminate Timer Service */
132     }
133     if (t->next)
134       t->next->rest += tp->rest;
135   } else {
136     logprintf("Oops, timer not found!!\n");
137   }
138   tp->next = NULL;
139   tp->state = TIMER_STOPPED;
140 }
141 
142 void
143 TimerService()
144 {
145   struct pppTimer *tp, *exp, *wt;
146 
147 #ifdef DEBUG
148   ShowTimers();
149 #endif
150   tp = TimerList;
151   if (tp) {
152     tp->rest--;
153     if (tp->rest == 0) {
154       /*
155        * Multiple timers may expires at once. Create list of expired timers.
156        */
157       exp = NULL;
158       do {
159 	tp->state = TIMER_EXPIRED;
160 	wt = tp->next;
161 	tp->enext = exp;
162 	exp = tp;
163 #ifdef DEBUG
164 	logprintf("Add %x to exp\n", tp);
165 #endif
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 #ifdef DEBUG
173       logprintf("TimerService: next is %x(%d)\n",
174 		TimerList, TimerList? TimerList->rest : 0);
175 #endif
176       /*
177        * Process all expired timers.
178        */
179       while (exp) {
180 #ifdef notdef
181 	StopTimer(exp);
182 #endif
183 	if (exp->func)
184 	  (*exp->func)(exp->arg);
185 	/*
186          * Just Removing each item from expired list
187          * And exp->enext will be intialized at next expire
188          * in this funtion.
189          */
190 	exp =  exp->enext;
191       }
192     }
193   }
194 }
195 
196 void
197 ShowTimers()
198 {
199   struct pppTimer *pt;
200 
201   logprintf("---- Begin of Timer Service List---\n");
202   for (pt = TimerList; pt; pt = pt->next)
203     logprintf("%x: load = %d, rest = %d, state =%x\n",
204 	pt, pt->load, pt->rest, pt->state);
205   logprintf("---- End of Timer Service List ---\n");
206 }
207 
208 #ifdef SIGALRM
209 u_int
210 sleep( u_int sec )
211 {
212   struct timeval  to,st,et;
213   long sld, nwd, std;
214 
215   gettimeofday( &st, NULL );
216   to.tv_sec =  sec;
217   to.tv_usec = 0;
218   std = st.tv_sec * 1000000 + st.tv_usec;
219   for (;;) {
220     if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
221          errno != EINTR ) {
222        break;
223     } else  {
224        gettimeofday( &et, NULL );
225        sld = to.tv_sec * 1000000 + to.tv_sec;
226        nwd = et.tv_sec * 1000000 + et.tv_usec - std;
227        if ( sld > nwd )
228           sld -= nwd;
229        else
230           sld  = 1; /* Avoid both tv_sec/usec is 0 */
231 
232        /* Calculate timeout value for select */
233        to.tv_sec  = sld / 1000000;
234        to.tv_usec = sld % 1000000;
235     }
236   }
237   return (0L);
238 }
239 
240 void 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 void InitTimerService( void ) {
271   struct itimerval itimer;
272 
273   pending_signal(SIGALRM, (void (*)(int))TimerService);
274   itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
275   itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
276   setitimer(ITIMER_REAL, &itimer, NULL);
277 }
278 
279 void TermTimerService( void ) {
280   struct itimerval itimer;
281 
282   itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
283   itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
284   setitimer(ITIMER_REAL, &itimer, NULL);
285   /*
286    * Notes: after disabling timer here, we will get one
287    *        SIGALRM will be got.
288    */
289   pending_signal(SIGALRM, SIG_IGN);
290 }
291 #endif
292