xref: /freebsd/usr.sbin/ppp/timer.c (revision 5ebc7e6281887681c3a348a5a4c902e262ccd656)
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.3 1995/03/11 15:18:51 amurai 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 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 void
142 TimerService()
143 {
144   struct pppTimer *tp, *exp, *wt;
145 
146 #ifdef DEBUG
147   ShowTimers();
148 #endif
149   if (tp = TimerList) {
150     tp->rest--;
151     if (tp->rest == 0) {
152       /*
153        * Multiple timers may expires at once. Create list of expired timers.
154        */
155       exp = NULL;
156       do {
157 	tp->state = TIMER_EXPIRED;
158 	wt = tp->next;
159 	tp->enext = exp;
160 	exp = tp;
161 #ifdef DEBUG
162 	logprintf("Add %x to exp\n", tp);
163 #endif
164 	tp = wt;
165       } while (tp && (tp->rest == 0));
166 
167       TimerList = tp;
168       if ( TimerList == NULL )			/* No timers ? */
169 	 TermTimerService();			/* Terminate Timer Service */
170 #ifdef DEBUG
171       logprintf("TimerService: next is %x(%d)\n",
172 		TimerList, TimerList? TimerList->rest : 0);
173 #endif
174       /*
175        * Process all expired timers.
176        */
177       while (exp) {
178 #ifdef notdef
179 	StopTimer(exp);
180 #endif
181 	if (exp->func)
182 	  (*exp->func)(exp->arg);
183 	/*
184          * Just Removing each item from expired list
185          * And exp->enext will be intialized at next expire
186          * in this funtion.
187          */
188 	exp =  exp->enext;
189       }
190     }
191   }
192 }
193 
194 void
195 ShowTimers()
196 {
197   struct pppTimer *pt;
198 
199   logprintf("---- Begin of Timer Service List---\n");
200   for (pt = TimerList; pt; pt = pt->next)
201     logprintf("%x: load = %d, rest = %d, state =%x\n",
202 	pt, pt->load, pt->rest, pt->state);
203   logprintf("---- End of Timer Service List ---\n");
204 }
205 
206 #ifdef SIGALRM
207 u_int sleep( u_int sec )
208 {
209   struct timeval  to,st,et;
210   long sld, nwd, std;
211 
212   gettimeofday( &st, NULL );
213   to.tv_sec =  sec;
214   to.tv_usec = 0;
215   std = st.tv_sec * 1000000 + st.tv_usec;
216   for (;;) {
217     if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
218          errno != EINTR ) {
219        break;
220     } else  {
221        gettimeofday( &et, NULL );
222        sld = to.tv_sec * 1000000 + to.tv_sec;
223        nwd = et.tv_sec * 1000000 + et.tv_usec - std;
224        if ( sld > nwd )
225           sld -= nwd;
226        else
227           sld  = 1; /* Avoid both tv_sec/usec is 0 */
228 
229        /* Calculate timeout value for select */
230        to.tv_sec  = sld / 1000000;
231        to.tv_usec = sld % 1000000;
232     }
233   }
234 }
235 
236 void usleep( u_int usec)
237 {
238   struct timeval  to,st,et;
239   long sld, nwd, std;
240 
241   gettimeofday( &st, NULL );
242   to.tv_sec =  0;
243   to.tv_usec = usec;
244   std = st.tv_sec * 1000000 + st.tv_usec;
245   for (;;) {
246     if ( select ( 0, NULL, NULL, NULL, &to) == 0 ||
247          errno != EINTR ) {
248        break;
249     } else  {
250        gettimeofday( &et, NULL );
251        sld = to.tv_sec * 1000000 + to.tv_sec;
252        nwd = et.tv_sec * 1000000 + et.tv_usec - std;
253        if ( sld > nwd )
254           sld -= nwd;
255        else
256           sld  = 1; /* Avoid both tv_sec/usec is 0 */
257 
258        /* Calculate timeout value for select */
259        to.tv_sec  = sld / 1000000;
260        to.tv_usec = sld % 1000000;
261 
262     }
263   }
264 }
265 
266 void InitTimerService( void ) {
267   struct itimerval itimer;
268 
269   signal(SIGALRM, (void (*)(int))TimerService);
270   itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
271   itimer.it_interval.tv_usec = itimer.it_value.tv_usec = TICKUNIT;
272   setitimer(ITIMER_REAL, &itimer, NULL);
273 }
274 
275 void TermTimerService( void ) {
276   struct itimerval itimer;
277 
278   itimer.it_interval.tv_sec = itimer.it_value.tv_sec = 0;
279   itimer.it_value.tv_usec = itimer.it_value.tv_sec = 0;
280   setitimer(ITIMER_REAL, &itimer, NULL);
281   /*
282    * Notes: after disabling timer here, we will get one
283    *        SIGALRM will be got.
284    */
285   signal(SIGALRM, SIG_IGN);
286 }
287 #endif
288