xref: /csrg-svn/sys/netiso/tp_timer.c (revision 48752)
136415Ssklower /***********************************************************
236415Ssklower 		Copyright IBM Corporation 1987
336415Ssklower 
436415Ssklower                       All Rights Reserved
536415Ssklower 
636415Ssklower Permission to use, copy, modify, and distribute this software and its
736415Ssklower documentation for any purpose and without fee is hereby granted,
836415Ssklower provided that the above copyright notice appear in all copies and that
936415Ssklower both that copyright notice and this permission notice appear in
1036415Ssklower supporting documentation, and that the name of IBM not be
1136415Ssklower used in advertising or publicity pertaining to distribution of the
1236415Ssklower software without specific, written prior permission.
1336415Ssklower 
1436415Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
1536415Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
1636415Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
1736415Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
1836415Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
1936415Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2036415Ssklower SOFTWARE.
2136415Ssklower 
2236415Ssklower ******************************************************************/
2336415Ssklower 
2436415Ssklower /*
2536415Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
2636415Ssklower  */
2736415Ssklower /*
2836415Ssklower  * ARGO TP
2936415Ssklower  *
3036415Ssklower  * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
3136415Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
32*48752Ssklower  *	@(#)tp_timer.c	7.4 (Berkeley) 04/26/91 *
3336415Ssklower  *
3436415Ssklower  * Contains all the timer code.
3536415Ssklower  * There are two sources of calls to these routines:
3636415Ssklower  * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time)
3736415Ssklower  *
3836415Ssklower  * Timers come in two flavors - those that generally get
3936415Ssklower  * cancelled (tp_ctimeout, tp_cuntimeout)
4036415Ssklower  * and those that either usually expire (tp_etimeout,
4136415Ssklower  * tp_euntimeout, tp_slowtimo) or may require more than one instance
4236415Ssklower  * of the timer active at a time.
4336415Ssklower  *
4436415Ssklower  * The C timers are stored in the tp_ref structure. Their "going off"
4536415Ssklower  * is manifested by a driver event of the TM_xxx form.
4636415Ssklower  *
4736415Ssklower  * The E timers are handled like the generic kernel callouts.
4836415Ssklower  * Their "going off" is manifested by a function call w/ 3 arguments.
4936415Ssklower  */
5036415Ssklower 
5136415Ssklower #ifndef lint
5236415Ssklower static char *rcsid = "$Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $";
5336415Ssklower #endif lint
5436415Ssklower 
5536415Ssklower #include "param.h"
5636415Ssklower #include "types.h"
5736415Ssklower #include "time.h"
5837469Ssklower #include "malloc.h"
59*48752Ssklower #include "socket.h"
6036415Ssklower 
6137469Ssklower #include "tp_param.h"
6237469Ssklower #include "tp_timer.h"
6337469Ssklower #include "tp_stat.h"
6437469Ssklower #include "tp_pcb.h"
6537469Ssklower #include "tp_tpdu.h"
6637469Ssklower #include "argo_debug.h"
6737469Ssklower #include "tp_trace.h"
6837469Ssklower #include "tp_seq.h"
6936415Ssklower 
70*48752Ssklower struct	Ecallout *TP_callfree;
71*48752Ssklower struct	Ecallout *TP_callout;
72*48752Ssklower struct	tp_ref *tp_ref;
73*48752Ssklower int		N_TPREF = 100;
7436415Ssklower 
7536415Ssklower extern int tp_maxrefopen;  /* highest ref # of an open tp connection */
7636415Ssklower 
7736415Ssklower /*
7836415Ssklower  * CALLED FROM:
7936415Ssklower  *  at autoconfig time from tp_init()
8036415Ssklower  * 	a combo of event, state, predicate
8136415Ssklower  * FUNCTION and ARGUMENTS:
8236415Ssklower  *  initialize data structures for the timers
8336415Ssklower  */
8436415Ssklower void
8536415Ssklower tp_timerinit()
8636415Ssklower {
87*48752Ssklower 	register struct Ecallout *e;
88*48752Ssklower 	register int s;
89*48752Ssklower #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\
90*48752Ssklower if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);}
9136415Ssklower 	/*
92*48752Ssklower 	 * Initialize storage
9336415Ssklower 	 */
94*48752Ssklower 	GETME(TP_callout, struct Ecallout *, 2 * N_TPREF);
95*48752Ssklower 	GETME(tp_ref, struct tp_ref *, 1 +  N_TPREF);
9636415Ssklower 
97*48752Ssklower 	TP_callfree = TP_callout + ((2 * N_TPREF) - 1);
98*48752Ssklower 	for (e = TP_callfree; e > TP_callout; e--)
99*48752Ssklower 		e->c_next = e - 1;
10036415Ssklower 
10136415Ssklower 	/* hate to do this but we really don't want zero to be a legit ref */
10236415Ssklower 	tp_maxrefopen = 1;
10336415Ssklower 	tp_ref[0].tpr_state = REF_FROZEN;  /* white lie -- no ref timer, don't
10436415Ssklower 		* want this one to be allocated- ever
10536415Ssklower 		* unless, of course, you make refs and address instead of an
10636415Ssklower 		* index - then 0 can be allocated
10736415Ssklower 		*/
108*48752Ssklower #undef GETME
10936415Ssklower }
11036415Ssklower 
11136415Ssklower /**********************  e timers *************************/
11236415Ssklower 
11336415Ssklower /*
11436415Ssklower  * CALLED FROM:
11536415Ssklower  *  tp_slowtimo() every 1/2 second, for each open reference
11636415Ssklower  * FUNCTION and ARGUMENTS:
11736415Ssklower  *  (refp) indicates a reference structure that is in use.
11836415Ssklower  *  This ref structure may contain active E-type timers.
11936415Ssklower  *  Update the timers and if any expire, create an event and
12036415Ssklower  *  call the driver.
12136415Ssklower  */
12236415Ssklower static void
12336415Ssklower tp_Eclock(refp)
12436415Ssklower 	struct tp_ref	*refp; /* the reference structure */
12536415Ssklower {
12636415Ssklower 	register struct Ecallout *p1; /* to drift through the list of callouts */
12736415Ssklower 	struct tp_event			 E; /* event to pass to tp_driver() */
12836415Ssklower 	int						 tp_driver(); /* drives the FSM */
12936415Ssklower 
13036415Ssklower 	/*
13136415Ssklower 	 * Update real-time timeout queue.
13236415Ssklower 	 * At front of queue are some number of events which are ``due''.
13336415Ssklower 	 * The time to these is <= 0 and if negative represents the
13436415Ssklower 	 * number of ticks which have passed since it was supposed to happen.
13536415Ssklower 	 * The rest of the q elements (times > 0) are events yet to happen,
13636415Ssklower 	 * where the time for each is given as a delta from the previous.
13736415Ssklower 	 * Decrementing just the first of these serves to decrement the time
13836415Ssklower 	 * to all events.
13936415Ssklower 	 *
14036415Ssklower 	 * This version, which calls the driver directly, doesn't pass
14136415Ssklower 	 * along the ticks - may want to add the ticks if there's any use
14236415Ssklower 	 * for them.
14336415Ssklower 	 */
14436415Ssklower 	IncStat(ts_Eticks);
14536415Ssklower 	p1 = refp->tpr_calltodo.c_next;
14636415Ssklower 	while (p1) {
14736415Ssklower 		if (--p1->c_time > 0)
14836415Ssklower 			break;
14936415Ssklower 		if (p1->c_time == 0)
15036415Ssklower 			break;
15136415Ssklower 		p1 = p1->c_next;
15236415Ssklower 	}
15336415Ssklower 
15436415Ssklower 	for (;;) {
15537469Ssklower 		struct tp_pcb *tpcb;
15636415Ssklower 		if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) {
15736415Ssklower 			break;
15836415Ssklower 		}
15936415Ssklower 		refp->tpr_calltodo.c_next = p1->c_next;
16036415Ssklower 		p1->c_next = TP_callfree;
16136415Ssklower 
16236415Ssklower #ifndef lint
16336415Ssklower 		E.ev_number = p1->c_func;
16436415Ssklower 		E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
16536415Ssklower 		E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
16636415Ssklower 		E.ATTR(TM_data_retrans).e_retrans =  p1->c_arg3;
16736415Ssklower #endif lint
16836415Ssklower 		IFDEBUG(D_TIMER)
16936415Ssklower 			printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n",
17036415Ssklower 				p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb,
17136415Ssklower 				refp-tp_ref);
17236415Ssklower 		ENDDEBUG
17336415Ssklower 
17436415Ssklower 		TP_callfree = p1;
17536415Ssklower 		IncStat(ts_Eexpired);
17637469Ssklower 		(void) tp_driver( tpcb = refp->tpr_pcb, &E);
17737469Ssklower 		if (p1->c_func == TM_reference && tpcb->tp_state == TP_CLOSED)
17837469Ssklower 			free((caddr_t)tpcb, M_PCB); /* XXX wart; where else to do it? */
17936415Ssklower 	}
18036415Ssklower }
18136415Ssklower 
18236415Ssklower /*
18336415Ssklower  * CALLED FROM:
18436415Ssklower  *  tp.trans all over
18536415Ssklower  * FUNCTION and ARGUMENTS:
18636415Ssklower  * Set an E type timer.  (refp) is the ref structure.
18736415Ssklower  * Causes  fun(arg1,arg2,arg3) to be called after time t.
18836415Ssklower  */
18936415Ssklower void
19036415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
19136415Ssklower 	struct tp_ref	*refp;
19236415Ssklower 	int 			fun; 	/* function to be called */
19336415Ssklower 	u_int			arg1, arg2;
19436415Ssklower 	int				arg3;
19536415Ssklower 	register int	ticks;
19636415Ssklower {
19736415Ssklower 	register struct Ecallout *p1, *p2, *pnew;
19836415Ssklower 		/* p1 and p2 drift through the list of timeout callout structures,
19936415Ssklower 		 * pnew points to the newly created callout structure
20036415Ssklower 		 */
20136415Ssklower 
20236415Ssklower 	IFDEBUG(D_TIMER)
20336415Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
20436415Ssklower 		refp->tpr_pcb->tp_state);
20536415Ssklower 	ENDDEBUG
20636415Ssklower 	IFTRACE(D_TIMER)
20736415Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
20836415Ssklower 		refp->tpr_state, ticks, tp_stat.ts_Eticks);
20936415Ssklower 	ENDTRACE
21036415Ssklower 
21136415Ssklower 	IncStat(ts_Eset);
21236415Ssklower 	if (ticks == 0)
21336415Ssklower 		ticks = 1;
21436415Ssklower 	pnew = TP_callfree;
21536415Ssklower 	if (pnew == (struct Ecallout *)0)
21636415Ssklower 		panic("tp timeout table overflow");
21736415Ssklower 	TP_callfree = pnew->c_next;
21836415Ssklower 	pnew->c_arg1 = arg1;
21936415Ssklower 	pnew->c_arg2 = arg2;
22036415Ssklower 	pnew->c_arg3 = arg3;
22136415Ssklower 	pnew->c_func = fun;
22236415Ssklower 	for (p1 = &(refp->tpr_calltodo);
22336415Ssklower 							(p2 = p1->c_next) && p2->c_time < ticks; p1 = p2)
22436415Ssklower 		if (p2->c_time > 0)
22536415Ssklower 			ticks -= p2->c_time;
22636415Ssklower 	p1->c_next = pnew;
22736415Ssklower 	pnew->c_next = p2;
22836415Ssklower 	pnew->c_time = ticks;
22936415Ssklower 	if (p2)
23036415Ssklower 		p2->c_time -= ticks;
23136415Ssklower }
23236415Ssklower 
23336415Ssklower /*
23436415Ssklower  * CALLED FROM:
23536415Ssklower  *  tp.trans all over
23636415Ssklower  * FUNCTION and ARGUMENTS:
23736415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
23836415Ssklower  */
23936415Ssklower void
24036415Ssklower tp_euntimeout(refp, fun)
24136415Ssklower 	struct tp_ref *refp;
24236415Ssklower 	int			  fun;
24336415Ssklower {
24436415Ssklower 	register struct Ecallout *p1, *p2; /* ptrs to drift through the list */
24536415Ssklower 
24636415Ssklower 	IFTRACE(D_TIMER)
24736415Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
24836415Ssklower 	ENDTRACE
24936415Ssklower 
25036415Ssklower 	p1 = &refp->tpr_calltodo;
25136415Ssklower 	while ( (p2 = p1->c_next) != 0) {
25236415Ssklower 		if (p2->c_func == fun)  {
25336415Ssklower 			if (p2->c_next && p2->c_time > 0)
25436415Ssklower 				p2->c_next->c_time += p2->c_time;
25536415Ssklower 			p1->c_next = p2->c_next;
25636415Ssklower 			p2->c_next = TP_callfree;
25736415Ssklower 			TP_callfree = p2;
25836415Ssklower 			IncStat(ts_Ecan_act);
25936415Ssklower 			continue;
26036415Ssklower 		}
26136415Ssklower 		p1 = p2;
26236415Ssklower 	}
26336415Ssklower }
26436415Ssklower 
26536415Ssklower /*
26636415Ssklower  * CALLED FROM:
26736415Ssklower  *  tp.trans, when an incoming ACK causes things to be dropped
26836415Ssklower  *  from the retransmission queue, and we want their associated
26936415Ssklower  *  timers to be cancelled.
27036415Ssklower  * FUNCTION and ARGUMENTS:
27136415Ssklower  *  cancel all occurrences of function (fun) where (arg2) < (seq)
27236415Ssklower  */
27336415Ssklower void
27436415Ssklower tp_euntimeout_lss(refp, fun, seq)
27536415Ssklower 	struct tp_ref *refp;
27636415Ssklower 	int			  fun;
27736415Ssklower 	SeqNum		  seq;
27836415Ssklower {
27936415Ssklower 	register struct Ecallout *p1, *p2;
28036415Ssklower 
28136415Ssklower 	IFTRACE(D_TIMER)
28236415Ssklower 		tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
28336415Ssklower 	ENDTRACE
28436415Ssklower 
28536415Ssklower 	p1 = &refp->tpr_calltodo;
28636415Ssklower 	while ( (p2 = p1->c_next) != 0) {
28736415Ssklower 		if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq))  {
28836415Ssklower 			if (p2->c_next && p2->c_time > 0)
28936415Ssklower 				p2->c_next->c_time += p2->c_time;
29036415Ssklower 			p1->c_next = p2->c_next;
29136415Ssklower 			p2->c_next = TP_callfree;
29236415Ssklower 			TP_callfree = p2;
29336415Ssklower 			IncStat(ts_Ecan_act);
29436415Ssklower 			continue;
29536415Ssklower 		}
29636415Ssklower 		p1 = p2;
29736415Ssklower 	}
29836415Ssklower }
29936415Ssklower 
30036415Ssklower /****************  c timers **********************
30136415Ssklower  *
30236415Ssklower  * These are not chained together; they sit
30336415Ssklower  * in the tp_ref structure. they are the kind that
30436415Ssklower  * are typically cancelled so it's faster not to
30536415Ssklower  * mess with the chains
30636415Ssklower  */
30736415Ssklower 
30836415Ssklower /*
30936415Ssklower  * CALLED FROM:
31036415Ssklower  *  the clock, every 500 ms
31136415Ssklower  * FUNCTION and ARGUMENTS:
31236415Ssklower  *  Look for open references with active timers.
31336415Ssklower  *  If they exist, call the appropriate timer routines to update
31436415Ssklower  *  the timers and possibly generate events.
31536415Ssklower  *  (The E timers are done in other procedures; the C timers are
31636415Ssklower  *  updated here, and events for them are generated here.)
31736415Ssklower  */
31836415Ssklower ProtoHook
31936415Ssklower tp_slowtimo()
32036415Ssklower {
32136415Ssklower 	register int 		r,t;
32236415Ssklower 	struct Ccallout 	*cp;
32336415Ssklower 	struct tp_ref		*rp = tp_ref;
32436415Ssklower 	struct tp_event		E;
32536415Ssklower 	int 				s = splnet();
32636415Ssklower 
32736415Ssklower 	/* check only open reference structures */
32836415Ssklower 	IncStat(ts_Cticks);
32936415Ssklower 	rp++;	/* tp_ref[0] is never used */
33036415Ssklower 	for(  r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
33136415Ssklower 		if (rp->tpr_state < REF_OPEN)
33236415Ssklower 			continue;
33336415Ssklower 
33436415Ssklower 		/* check the C-type timers */
33536415Ssklower 		cp = rp->tpr_callout;
33636415Ssklower 		for (t=0 ; t < N_CTIMERS; t++,cp++) {
33736415Ssklower 			if( cp->c_active ) {
33836415Ssklower 				if( --cp->c_time <= 0 ) {
33936415Ssklower 					cp->c_active = FALSE;
34036415Ssklower 					E.ev_number = t;
34136415Ssklower 					IFDEBUG(D_TIMER)
34236415Ssklower 						printf("C expired! type 0x%x\n", t);
34336415Ssklower 					ENDDEBUG
34436415Ssklower 					IncStat(ts_Cexpired);
34536415Ssklower 					tp_driver( rp->tpr_pcb, &E);
34636415Ssklower 				}
34736415Ssklower 			}
34836415Ssklower 		}
34936415Ssklower 		/* now update the list */
35036415Ssklower 		tp_Eclock(rp);
35136415Ssklower 	}
35236415Ssklower 	splx(s);
35336415Ssklower 	return 0;
35436415Ssklower }
35536415Ssklower 
35636415Ssklower /*
35736415Ssklower  * CALLED FROM:
35836415Ssklower  *  tp.trans, tp_emit()
35936415Ssklower  * FUNCTION and ARGUMENTS:
36036415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
36136415Ssklower  */
36236415Ssklower void
36336415Ssklower tp_ctimeout(refp, which, ticks)
36436415Ssklower 	register struct tp_ref	*refp;
36536415Ssklower 	int 					which, ticks;
36636415Ssklower {
36736415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
36836415Ssklower 
36936415Ssklower 	IFTRACE(D_TIMER)
37036415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
37136415Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
37236415Ssklower 	ENDTRACE
37336415Ssklower 	if(cp->c_active)
37436415Ssklower 		IncStat(ts_Ccan_act);
37536415Ssklower 	IncStat(ts_Cset);
37636415Ssklower 	cp->c_time = ticks;
37736415Ssklower 	cp->c_active = TRUE;
37836415Ssklower }
37936415Ssklower 
38036415Ssklower /*
38136415Ssklower  * CALLED FROM:
38236415Ssklower  *  tp.trans
38336415Ssklower  * FUNCTION and ARGUMENTS:
38436415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
38536415Ssklower  * 	parameter (ticks) is > the current value of the timer.
38636415Ssklower  */
38736415Ssklower void
38836415Ssklower tp_ctimeout_MIN(refp, which, ticks)
38936415Ssklower 	register struct tp_ref	*refp;
39036415Ssklower 	int						which, ticks;
39136415Ssklower {
39236415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
39336415Ssklower 
39436415Ssklower 	IFTRACE(D_TIMER)
39536415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
39636415Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
39736415Ssklower 	ENDTRACE
39836415Ssklower 	if(cp->c_active)
39936415Ssklower 		IncStat(ts_Ccan_act);
40036415Ssklower 	IncStat(ts_Cset);
40136415Ssklower 	if( cp->c_active )
40236415Ssklower 		cp->c_time = MIN(ticks, cp->c_time);
40336415Ssklower 	else  {
40436415Ssklower 		cp->c_time = ticks;
40536415Ssklower 		cp->c_active = TRUE;
40636415Ssklower 	}
40736415Ssklower }
40836415Ssklower 
40936415Ssklower /*
41036415Ssklower  * CALLED FROM:
41136415Ssklower  *  tp.trans
41236415Ssklower  * FUNCTION and ARGUMENTS:
41336415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
41436415Ssklower  */
41536415Ssklower void
41636415Ssklower tp_cuntimeout(refp, which)
41736415Ssklower 	int						which;
41836415Ssklower 	register struct tp_ref	*refp;
41936415Ssklower {
42036415Ssklower 	register struct Ccallout *cp;
42136415Ssklower 
42236415Ssklower 	cp = &(refp->tpr_callout[which]);
42336415Ssklower 
42436415Ssklower 	IFDEBUG(D_TIMER)
42537469Ssklower 		printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_active);
42636415Ssklower 	ENDDEBUG
42736415Ssklower 
42836415Ssklower 	IFTRACE(D_TIMER)
42936415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
43036415Ssklower 			which, cp->c_active, 0);
43136415Ssklower 	ENDTRACE
43236415Ssklower 
43336415Ssklower 	if(cp->c_active)
43436415Ssklower 		IncStat(ts_Ccan_act);
43536415Ssklower 	else
43636415Ssklower 		IncStat(ts_Ccan_inact);
43736415Ssklower 	cp->c_active = FALSE;
43836415Ssklower }
439