xref: /freebsd/usr.sbin/ppp/timer.c (revision ce834215a70ff69e7e222827437116eee2f9ac6f)
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.16 1997/05/10 01:22:19 brian Exp $
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 #include "sig.h"
32 
33 void StopTimerNoBlock( struct pppTimer *);
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 
48 void
49 StartTimer(tp)
50 struct pppTimer *tp;
51 {
52   struct pppTimer *t, *pt;
53   u_long ticks = 0;
54 
55 #ifdef SIGALRM
56   int	omask;
57   omask = sigblock(sigmask(SIGALRM));
58 #endif
59 
60   if (tp->state != TIMER_STOPPED) {
61     StopTimerNoBlock(tp);
62   }
63   if (tp->load == 0) {
64     LogPrintf(LogDEBUG, "timer %x has 0 load!\n", tp);
65     sigsetmask(omask);
66     return;
67   }
68   pt = NULL;
69   for (t = TimerList; t; t = t->next) {
70     LogPrintf(LogDEBUG, "StartTimer: %x(%d):  ticks: %d, rest: %d\n",
71               t, t->state, ticks, t->rest);
72     if (ticks + t->rest >= tp->load)
73       break;
74     ticks += t->rest;
75     pt = t;
76   }
77 
78   tp->state = TIMER_RUNNING;
79   tp->rest = tp->load - ticks;
80   LogPrintf(LogDEBUG, "StartTimer: Inserting %x before %x, rest = %d\n",
81             tp, t, tp->rest);
82   /* Insert given *tp just before *t */
83   tp->next = t;
84   if (pt) {
85     pt->next = tp;
86   } else {
87     InitTimerService();
88     TimerList = tp;
89   }
90   if (t)
91     t->rest -= tp->rest;
92 
93 #ifdef SIGALRM
94   sigsetmask(omask);
95 #endif
96 }
97 
98 void
99 StopTimerNoBlock(tp)
100 struct 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   LogPrintf(LogDEBUG, "StopTimer: %x, next = %x state=%x\n",
111             tp, tp->next, tp->state);
112   if (tp->state != TIMER_RUNNING) {
113     tp->next   = NULL;
114     tp->state  = TIMER_STOPPED;
115     return;
116   }
117 
118   pt = NULL;
119   for (t = TimerList; t != tp && t !=NULL ; t = t->next)
120     pt = t;
121   if (t) {
122     if (pt) {
123       pt->next = t->next;
124     } else {
125       TimerList = t->next;
126       if ( TimerList == NULL )			/* Last one ? */
127 	 TermTimerService();			/* Terminate Timer Service */
128     }
129     if (t->next)
130       t->next->rest += tp->rest;
131   } else
132     LogPrintf(LogERROR, "Oops, timer not found!!\n");
133 
134   tp->next = NULL;
135   tp->state = TIMER_STOPPED;
136 }
137 
138 void
139 TimerService()
140 {
141   struct pppTimer *tp, *exp, *wt;
142 
143   if (LogIsKept(LogDEBUG))
144     ShowTimers();
145   tp = TimerList;
146   if (tp) {
147     tp->rest--;
148     if (tp->rest == 0) {
149       /*
150        * Multiple timers may expires at once. Create list of expired timers.
151        */
152       exp = NULL;
153       do {
154 	tp->state = TIMER_EXPIRED;
155 	wt = tp->next;
156 	tp->enext = exp;
157 	exp = tp;
158 	LogPrintf(LogDEBUG, "TimerService: Add %x to exp\n", tp);
159 	tp = wt;
160       } while (tp && (tp->rest == 0));
161 
162       TimerList = tp;
163       if ( TimerList == NULL )			/* No timers ? */
164 	 TermTimerService();			/* Terminate Timer Service */
165       LogPrintf(LogDEBUG, "TimerService: next is %x(%d)\n",
166 		TimerList, TimerList? TimerList->rest : 0);
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 
187 void
188 ShowTimers()
189 {
190   struct pppTimer *pt;
191 
192   LogPrintf(LogDEBUG, "---- Begin of Timer Service List---\n");
193   for (pt = TimerList; pt; pt = pt->next)
194     LogPrintf(LogDEBUG, "%x: load = %d, rest = %d, state =%x\n",
195 	pt, pt->load, pt->rest, pt->state);
196   LogPrintf(LogDEBUG, "---- End of Timer Service List ---\n");
197 }
198 
199 #ifdef SIGALRM
200 u_int
201 sleep( u_int sec )
202 {
203   struct timeval  to,st,et;
204   long sld, nwd, std;
205 
206   gettimeofday( &st, NULL );
207   to.tv_sec =  sec;
208   to.tv_usec = 0;
209   std = st.tv_sec * 1000000 + st.tv_usec;
210   for (;;) {
211     if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
212          errno != EINTR ) {
213        break;
214     } else  {
215        gettimeofday( &et, NULL );
216        sld = to.tv_sec * 1000000 + to.tv_sec;
217        nwd = et.tv_sec * 1000000 + et.tv_usec - std;
218        if ( sld > nwd )
219           sld -= nwd;
220        else
221           sld  = 1; /* Avoid both tv_sec/usec is 0 */
222 
223        /* Calculate timeout value for select */
224        to.tv_sec  = sld / 1000000;
225        to.tv_usec = sld % 1000000;
226     }
227   }
228   return (0L);
229 }
230 
231 void usleep( u_int usec)
232 {
233   struct timeval  to,st,et;
234   long sld, nwd, std;
235 
236   gettimeofday( &st, NULL );
237   to.tv_sec =  0;
238   to.tv_usec = usec;
239   std = st.tv_sec * 1000000 + st.tv_usec;
240   for (;;) {
241     if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
242          errno != EINTR ) {
243        break;
244     } else  {
245        gettimeofday( &et, NULL );
246        sld = to.tv_sec * 1000000 + to.tv_sec;
247        nwd = et.tv_sec * 1000000 + et.tv_usec - std;
248        if ( sld > nwd )
249           sld -= nwd;
250        else
251           sld  = 1; /* Avoid both tv_sec/usec is 0 */
252 
253        /* Calculate timeout value for select */
254        to.tv_sec  = sld / 1000000;
255        to.tv_usec = sld % 1000000;
256 
257     }
258   }
259 }
260 
261 void InitTimerService( void ) {
262   struct itimerval itimer;
263 
264   pending_signal(SIGALRM, (void (*)(int))TimerService);
265   itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
266   itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
267   if (setitimer(ITIMER_REAL, &itimer, NULL) == -1)
268     LogPrintf(LogERROR, "Unable to set itimer.\n");
269 }
270 
271 void TermTimerService( void ) {
272   struct itimerval itimer;
273 
274   itimer.it_interval.tv_usec = itimer.it_interval.tv_sec = 0;
275   itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
276   if (setitimer(ITIMER_REAL, &itimer, NULL) == -1)
277     LogPrintf(LogERROR, "Unable to set itimer.\n");
278   pending_signal(SIGALRM, SIG_IGN);
279 }
280 #endif
281