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