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