xref: /csrg-svn/sys/netiso/tp_timer.c (revision 36415)
1*36415Ssklower /***********************************************************
2*36415Ssklower 		Copyright IBM Corporation 1987
3*36415Ssklower 
4*36415Ssklower                       All Rights Reserved
5*36415Ssklower 
6*36415Ssklower Permission to use, copy, modify, and distribute this software and its
7*36415Ssklower documentation for any purpose and without fee is hereby granted,
8*36415Ssklower provided that the above copyright notice appear in all copies and that
9*36415Ssklower both that copyright notice and this permission notice appear in
10*36415Ssklower supporting documentation, and that the name of IBM not be
11*36415Ssklower used in advertising or publicity pertaining to distribution of the
12*36415Ssklower software without specific, written prior permission.
13*36415Ssklower 
14*36415Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15*36415Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16*36415Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17*36415Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18*36415Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19*36415Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20*36415Ssklower SOFTWARE.
21*36415Ssklower 
22*36415Ssklower ******************************************************************/
23*36415Ssklower 
24*36415Ssklower /*
25*36415Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26*36415Ssklower  */
27*36415Ssklower /*
28*36415Ssklower  * ARGO TP
29*36415Ssklower  *
30*36415Ssklower  * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
31*36415Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
32*36415Ssklower  *
33*36415Ssklower  * Contains all the timer code.
34*36415Ssklower  * There are two sources of calls to these routines:
35*36415Ssklower  * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time)
36*36415Ssklower  *
37*36415Ssklower  * Timers come in two flavors - those that generally get
38*36415Ssklower  * cancelled (tp_ctimeout, tp_cuntimeout)
39*36415Ssklower  * and those that either usually expire (tp_etimeout,
40*36415Ssklower  * tp_euntimeout, tp_slowtimo) or may require more than one instance
41*36415Ssklower  * of the timer active at a time.
42*36415Ssklower  *
43*36415Ssklower  * The C timers are stored in the tp_ref structure. Their "going off"
44*36415Ssklower  * is manifested by a driver event of the TM_xxx form.
45*36415Ssklower  *
46*36415Ssklower  * The E timers are handled like the generic kernel callouts.
47*36415Ssklower  * Their "going off" is manifested by a function call w/ 3 arguments.
48*36415Ssklower  */
49*36415Ssklower 
50*36415Ssklower #ifndef lint
51*36415Ssklower static char *rcsid = "$Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $";
52*36415Ssklower #endif lint
53*36415Ssklower 
54*36415Ssklower #include "param.h"
55*36415Ssklower #include "types.h"
56*36415Ssklower #include "time.h"
57*36415Ssklower 
58*36415Ssklower #include "../netiso/tp_param.h"
59*36415Ssklower #include "../netiso/tp_timer.h"
60*36415Ssklower #include "../netiso/tp_stat.h"
61*36415Ssklower #include "../netiso/tp_pcb.h"
62*36415Ssklower #include "../netiso/tp_tpdu.h"
63*36415Ssklower #include "../netiso/argo_debug.h"
64*36415Ssklower #include "../netiso/tp_trace.h"
65*36415Ssklower #include "../netiso/tp_seq.h"
66*36415Ssklower 
67*36415Ssklower static  struct	Ecallout *TP_callfree;
68*36415Ssklower static  struct	Ecallout TP_callout[N_TPREF*2];
69*36415Ssklower 
70*36415Ssklower extern int tp_maxrefopen;  /* highest ref # of an open tp connection */
71*36415Ssklower 
72*36415Ssklower /*
73*36415Ssklower  * CALLED FROM:
74*36415Ssklower  *  at autoconfig time from tp_init()
75*36415Ssklower  * 	a combo of event, state, predicate
76*36415Ssklower  * FUNCTION and ARGUMENTS:
77*36415Ssklower  *  initialize data structures for the timers
78*36415Ssklower  */
79*36415Ssklower void
80*36415Ssklower tp_timerinit()
81*36415Ssklower {
82*36415Ssklower 	register int i;
83*36415Ssklower 	/*
84*36415Ssklower 	 * Initialize callouts
85*36415Ssklower 	 */
86*36415Ssklower 	TP_callfree = TP_callout;
87*36415Ssklower 	for (i = 1; i < N_TPREF*2; i++)
88*36415Ssklower 		TP_callout[i-1].c_next = &TP_callout[i];
89*36415Ssklower 
90*36415Ssklower 	bzero( (caddr_t)tp_ref, N_TPREF * sizeof(struct tp_ref) );
91*36415Ssklower 
92*36415Ssklower 	/* hate to do this but we really don't want zero to be a legit ref */
93*36415Ssklower 	tp_maxrefopen = 1;
94*36415Ssklower 	tp_ref[0].tpr_state = REF_FROZEN;  /* white lie -- no ref timer, don't
95*36415Ssklower 		* want this one to be allocated- ever
96*36415Ssklower 		* unless, of course, you make refs and address instead of an
97*36415Ssklower 		* index - then 0 can be allocated
98*36415Ssklower 		*/
99*36415Ssklower 
100*36415Ssklower }
101*36415Ssklower 
102*36415Ssklower /**********************  e timers *************************/
103*36415Ssklower 
104*36415Ssklower /*
105*36415Ssklower  * CALLED FROM:
106*36415Ssklower  *  tp_slowtimo() every 1/2 second, for each open reference
107*36415Ssklower  * FUNCTION and ARGUMENTS:
108*36415Ssklower  *  (refp) indicates a reference structure that is in use.
109*36415Ssklower  *  This ref structure may contain active E-type timers.
110*36415Ssklower  *  Update the timers and if any expire, create an event and
111*36415Ssklower  *  call the driver.
112*36415Ssklower  */
113*36415Ssklower static void
114*36415Ssklower tp_Eclock(refp)
115*36415Ssklower 	struct tp_ref	*refp; /* the reference structure */
116*36415Ssklower {
117*36415Ssklower 	register struct Ecallout *p1; /* to drift through the list of callouts */
118*36415Ssklower 	struct tp_event			 E; /* event to pass to tp_driver() */
119*36415Ssklower 	int						 tp_driver(); /* drives the FSM */
120*36415Ssklower 
121*36415Ssklower 	/*
122*36415Ssklower 	 * Update real-time timeout queue.
123*36415Ssklower 	 * At front of queue are some number of events which are ``due''.
124*36415Ssklower 	 * The time to these is <= 0 and if negative represents the
125*36415Ssklower 	 * number of ticks which have passed since it was supposed to happen.
126*36415Ssklower 	 * The rest of the q elements (times > 0) are events yet to happen,
127*36415Ssklower 	 * where the time for each is given as a delta from the previous.
128*36415Ssklower 	 * Decrementing just the first of these serves to decrement the time
129*36415Ssklower 	 * to all events.
130*36415Ssklower 	 *
131*36415Ssklower 	 * This version, which calls the driver directly, doesn't pass
132*36415Ssklower 	 * along the ticks - may want to add the ticks if there's any use
133*36415Ssklower 	 * for them.
134*36415Ssklower 	 */
135*36415Ssklower 	IncStat(ts_Eticks);
136*36415Ssklower 	p1 = refp->tpr_calltodo.c_next;
137*36415Ssklower 	while (p1) {
138*36415Ssklower 		if (--p1->c_time > 0)
139*36415Ssklower 			break;
140*36415Ssklower 		if (p1->c_time == 0)
141*36415Ssklower 			break;
142*36415Ssklower 		p1 = p1->c_next;
143*36415Ssklower 	}
144*36415Ssklower 
145*36415Ssklower 	for (;;) {
146*36415Ssklower 		if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) {
147*36415Ssklower 			break;
148*36415Ssklower 		}
149*36415Ssklower 		refp->tpr_calltodo.c_next = p1->c_next;
150*36415Ssklower 		p1->c_next = TP_callfree;
151*36415Ssklower 
152*36415Ssklower #ifndef lint
153*36415Ssklower 		E.ev_number = p1->c_func;
154*36415Ssklower 		E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
155*36415Ssklower 		E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
156*36415Ssklower 		E.ATTR(TM_data_retrans).e_retrans =  p1->c_arg3;
157*36415Ssklower #endif lint
158*36415Ssklower 		IFDEBUG(D_TIMER)
159*36415Ssklower 			printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n",
160*36415Ssklower 				p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb,
161*36415Ssklower 				refp-tp_ref);
162*36415Ssklower 		ENDDEBUG
163*36415Ssklower 
164*36415Ssklower 		TP_callfree = p1;
165*36415Ssklower 		IncStat(ts_Eexpired);
166*36415Ssklower 		(void) tp_driver( refp->tpr_pcb, &E);
167*36415Ssklower 	}
168*36415Ssklower }
169*36415Ssklower 
170*36415Ssklower /*
171*36415Ssklower  * CALLED FROM:
172*36415Ssklower  *  tp.trans all over
173*36415Ssklower  * FUNCTION and ARGUMENTS:
174*36415Ssklower  * Set an E type timer.  (refp) is the ref structure.
175*36415Ssklower  * Causes  fun(arg1,arg2,arg3) to be called after time t.
176*36415Ssklower  */
177*36415Ssklower void
178*36415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
179*36415Ssklower 	struct tp_ref	*refp;
180*36415Ssklower 	int 			fun; 	/* function to be called */
181*36415Ssklower 	u_int			arg1, arg2;
182*36415Ssklower 	int				arg3;
183*36415Ssklower 	register int	ticks;
184*36415Ssklower {
185*36415Ssklower 	register struct Ecallout *p1, *p2, *pnew;
186*36415Ssklower 		/* p1 and p2 drift through the list of timeout callout structures,
187*36415Ssklower 		 * pnew points to the newly created callout structure
188*36415Ssklower 		 */
189*36415Ssklower 
190*36415Ssklower 	IFDEBUG(D_TIMER)
191*36415Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
192*36415Ssklower 		refp->tpr_pcb->tp_state);
193*36415Ssklower 	ENDDEBUG
194*36415Ssklower 	IFTRACE(D_TIMER)
195*36415Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
196*36415Ssklower 		refp->tpr_state, ticks, tp_stat.ts_Eticks);
197*36415Ssklower 	ENDTRACE
198*36415Ssklower 
199*36415Ssklower 	IncStat(ts_Eset);
200*36415Ssklower 	if (ticks == 0)
201*36415Ssklower 		ticks = 1;
202*36415Ssklower 	pnew = TP_callfree;
203*36415Ssklower 	if (pnew == (struct Ecallout *)0)
204*36415Ssklower 		panic("tp timeout table overflow");
205*36415Ssklower 	TP_callfree = pnew->c_next;
206*36415Ssklower 	pnew->c_arg1 = arg1;
207*36415Ssklower 	pnew->c_arg2 = arg2;
208*36415Ssklower 	pnew->c_arg3 = arg3;
209*36415Ssklower 	pnew->c_func = fun;
210*36415Ssklower 	for (p1 = &(refp->tpr_calltodo);
211*36415Ssklower 							(p2 = p1->c_next) && p2->c_time < ticks; p1 = p2)
212*36415Ssklower 		if (p2->c_time > 0)
213*36415Ssklower 			ticks -= p2->c_time;
214*36415Ssklower 	p1->c_next = pnew;
215*36415Ssklower 	pnew->c_next = p2;
216*36415Ssklower 	pnew->c_time = ticks;
217*36415Ssklower 	if (p2)
218*36415Ssklower 		p2->c_time -= ticks;
219*36415Ssklower }
220*36415Ssklower 
221*36415Ssklower /*
222*36415Ssklower  * CALLED FROM:
223*36415Ssklower  *  tp.trans all over
224*36415Ssklower  * FUNCTION and ARGUMENTS:
225*36415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
226*36415Ssklower  */
227*36415Ssklower void
228*36415Ssklower tp_euntimeout(refp, fun)
229*36415Ssklower 	struct tp_ref *refp;
230*36415Ssklower 	int			  fun;
231*36415Ssklower {
232*36415Ssklower 	register struct Ecallout *p1, *p2; /* ptrs to drift through the list */
233*36415Ssklower 
234*36415Ssklower 	IFTRACE(D_TIMER)
235*36415Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
236*36415Ssklower 	ENDTRACE
237*36415Ssklower 
238*36415Ssklower 	p1 = &refp->tpr_calltodo;
239*36415Ssklower 	while ( (p2 = p1->c_next) != 0) {
240*36415Ssklower 		if (p2->c_func == fun)  {
241*36415Ssklower 			if (p2->c_next && p2->c_time > 0)
242*36415Ssklower 				p2->c_next->c_time += p2->c_time;
243*36415Ssklower 			p1->c_next = p2->c_next;
244*36415Ssklower 			p2->c_next = TP_callfree;
245*36415Ssklower 			TP_callfree = p2;
246*36415Ssklower 			IncStat(ts_Ecan_act);
247*36415Ssklower 			continue;
248*36415Ssklower 		}
249*36415Ssklower 		p1 = p2;
250*36415Ssklower 	}
251*36415Ssklower }
252*36415Ssklower 
253*36415Ssklower /*
254*36415Ssklower  * CALLED FROM:
255*36415Ssklower  *  tp.trans, when an incoming ACK causes things to be dropped
256*36415Ssklower  *  from the retransmission queue, and we want their associated
257*36415Ssklower  *  timers to be cancelled.
258*36415Ssklower  * FUNCTION and ARGUMENTS:
259*36415Ssklower  *  cancel all occurrences of function (fun) where (arg2) < (seq)
260*36415Ssklower  */
261*36415Ssklower void
262*36415Ssklower tp_euntimeout_lss(refp, fun, seq)
263*36415Ssklower 	struct tp_ref *refp;
264*36415Ssklower 	int			  fun;
265*36415Ssklower 	SeqNum		  seq;
266*36415Ssklower {
267*36415Ssklower 	register struct Ecallout *p1, *p2;
268*36415Ssklower 
269*36415Ssklower 	IFTRACE(D_TIMER)
270*36415Ssklower 		tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
271*36415Ssklower 	ENDTRACE
272*36415Ssklower 
273*36415Ssklower 	p1 = &refp->tpr_calltodo;
274*36415Ssklower 	while ( (p2 = p1->c_next) != 0) {
275*36415Ssklower 		if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq))  {
276*36415Ssklower 			if (p2->c_next && p2->c_time > 0)
277*36415Ssklower 				p2->c_next->c_time += p2->c_time;
278*36415Ssklower 			p1->c_next = p2->c_next;
279*36415Ssklower 			p2->c_next = TP_callfree;
280*36415Ssklower 			TP_callfree = p2;
281*36415Ssklower 			IncStat(ts_Ecan_act);
282*36415Ssklower 			continue;
283*36415Ssklower 		}
284*36415Ssklower 		p1 = p2;
285*36415Ssklower 	}
286*36415Ssklower }
287*36415Ssklower 
288*36415Ssklower /****************  c timers **********************
289*36415Ssklower  *
290*36415Ssklower  * These are not chained together; they sit
291*36415Ssklower  * in the tp_ref structure. they are the kind that
292*36415Ssklower  * are typically cancelled so it's faster not to
293*36415Ssklower  * mess with the chains
294*36415Ssklower  */
295*36415Ssklower 
296*36415Ssklower /*
297*36415Ssklower  * CALLED FROM:
298*36415Ssklower  *  the clock, every 500 ms
299*36415Ssklower  * FUNCTION and ARGUMENTS:
300*36415Ssklower  *  Look for open references with active timers.
301*36415Ssklower  *  If they exist, call the appropriate timer routines to update
302*36415Ssklower  *  the timers and possibly generate events.
303*36415Ssklower  *  (The E timers are done in other procedures; the C timers are
304*36415Ssklower  *  updated here, and events for them are generated here.)
305*36415Ssklower  */
306*36415Ssklower ProtoHook
307*36415Ssklower tp_slowtimo()
308*36415Ssklower {
309*36415Ssklower 	register int 		r,t;
310*36415Ssklower 	struct Ccallout 	*cp;
311*36415Ssklower 	struct tp_ref		*rp = tp_ref;
312*36415Ssklower 	struct tp_event		E;
313*36415Ssklower 	int 				s = splnet();
314*36415Ssklower 
315*36415Ssklower 	/* check only open reference structures */
316*36415Ssklower 	IncStat(ts_Cticks);
317*36415Ssklower 	rp++;	/* tp_ref[0] is never used */
318*36415Ssklower 	for(  r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
319*36415Ssklower 		if (rp->tpr_state < REF_OPEN)
320*36415Ssklower 			continue;
321*36415Ssklower 
322*36415Ssklower 		/* check the C-type timers */
323*36415Ssklower 		cp = rp->tpr_callout;
324*36415Ssklower 		for (t=0 ; t < N_CTIMERS; t++,cp++) {
325*36415Ssklower 			if( cp->c_active ) {
326*36415Ssklower 				if( --cp->c_time <= 0 ) {
327*36415Ssklower 					cp->c_active = FALSE;
328*36415Ssklower 					E.ev_number = t;
329*36415Ssklower 					IFDEBUG(D_TIMER)
330*36415Ssklower 						printf("C expired! type 0x%x\n", t);
331*36415Ssklower 					ENDDEBUG
332*36415Ssklower 					IncStat(ts_Cexpired);
333*36415Ssklower 					tp_driver( rp->tpr_pcb, &E);
334*36415Ssklower 				}
335*36415Ssklower 			}
336*36415Ssklower 		}
337*36415Ssklower 		/* now update the list */
338*36415Ssklower 		tp_Eclock(rp);
339*36415Ssklower 	}
340*36415Ssklower 	splx(s);
341*36415Ssklower 	return 0;
342*36415Ssklower }
343*36415Ssklower 
344*36415Ssklower /*
345*36415Ssklower  * CALLED FROM:
346*36415Ssklower  *  tp.trans, tp_emit()
347*36415Ssklower  * FUNCTION and ARGUMENTS:
348*36415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
349*36415Ssklower  */
350*36415Ssklower void
351*36415Ssklower tp_ctimeout(refp, which, ticks)
352*36415Ssklower 	register struct tp_ref	*refp;
353*36415Ssklower 	int 					which, ticks;
354*36415Ssklower {
355*36415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
356*36415Ssklower 
357*36415Ssklower 	IFTRACE(D_TIMER)
358*36415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
359*36415Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
360*36415Ssklower 	ENDTRACE
361*36415Ssklower 	if(cp->c_active)
362*36415Ssklower 		IncStat(ts_Ccan_act);
363*36415Ssklower 	IncStat(ts_Cset);
364*36415Ssklower 	cp->c_time = ticks;
365*36415Ssklower 	cp->c_active = TRUE;
366*36415Ssklower }
367*36415Ssklower 
368*36415Ssklower /*
369*36415Ssklower  * CALLED FROM:
370*36415Ssklower  *  tp.trans
371*36415Ssklower  * FUNCTION and ARGUMENTS:
372*36415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
373*36415Ssklower  * 	parameter (ticks) is > the current value of the timer.
374*36415Ssklower  */
375*36415Ssklower void
376*36415Ssklower tp_ctimeout_MIN(refp, which, ticks)
377*36415Ssklower 	register struct tp_ref	*refp;
378*36415Ssklower 	int						which, ticks;
379*36415Ssklower {
380*36415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
381*36415Ssklower 
382*36415Ssklower 	IFTRACE(D_TIMER)
383*36415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
384*36415Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
385*36415Ssklower 	ENDTRACE
386*36415Ssklower 	if(cp->c_active)
387*36415Ssklower 		IncStat(ts_Ccan_act);
388*36415Ssklower 	IncStat(ts_Cset);
389*36415Ssklower 	if( cp->c_active )
390*36415Ssklower 		cp->c_time = MIN(ticks, cp->c_time);
391*36415Ssklower 	else  {
392*36415Ssklower 		cp->c_time = ticks;
393*36415Ssklower 		cp->c_active = TRUE;
394*36415Ssklower 	}
395*36415Ssklower }
396*36415Ssklower 
397*36415Ssklower /*
398*36415Ssklower  * CALLED FROM:
399*36415Ssklower  *  tp.trans
400*36415Ssklower  * FUNCTION and ARGUMENTS:
401*36415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
402*36415Ssklower  */
403*36415Ssklower void
404*36415Ssklower tp_cuntimeout(refp, which)
405*36415Ssklower 	int						which;
406*36415Ssklower 	register struct tp_ref	*refp;
407*36415Ssklower {
408*36415Ssklower 	register struct Ccallout *cp;
409*36415Ssklower 
410*36415Ssklower 	cp = &(refp->tpr_callout[which]);
411*36415Ssklower 
412*36415Ssklower 	IFDEBUG(D_TIMER)
413*36415Ssklower 		printf("tp_cuntimeout(0x%x, %d) active\n", refp, which, cp->c_active);
414*36415Ssklower 	ENDDEBUG
415*36415Ssklower 
416*36415Ssklower 	IFTRACE(D_TIMER)
417*36415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
418*36415Ssklower 			which, cp->c_active, 0);
419*36415Ssklower 	ENDTRACE
420*36415Ssklower 
421*36415Ssklower 	if(cp->c_active)
422*36415Ssklower 		IncStat(ts_Ccan_act);
423*36415Ssklower 	else
424*36415Ssklower 		IncStat(ts_Ccan_inact);
425*36415Ssklower 	cp->c_active = FALSE;
426*36415Ssklower }
427