xref: /csrg-svn/sys/netiso/tp_timer.c (revision 37469)
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 $
3236415Ssklower  *
3336415Ssklower  * Contains all the timer code.
3436415Ssklower  * There are two sources of calls to these routines:
3536415Ssklower  * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time)
3636415Ssklower  *
3736415Ssklower  * Timers come in two flavors - those that generally get
3836415Ssklower  * cancelled (tp_ctimeout, tp_cuntimeout)
3936415Ssklower  * and those that either usually expire (tp_etimeout,
4036415Ssklower  * tp_euntimeout, tp_slowtimo) or may require more than one instance
4136415Ssklower  * of the timer active at a time.
4236415Ssklower  *
4336415Ssklower  * The C timers are stored in the tp_ref structure. Their "going off"
4436415Ssklower  * is manifested by a driver event of the TM_xxx form.
4536415Ssklower  *
4636415Ssklower  * The E timers are handled like the generic kernel callouts.
4736415Ssklower  * Their "going off" is manifested by a function call w/ 3 arguments.
4836415Ssklower  */
4936415Ssklower 
5036415Ssklower #ifndef lint
5136415Ssklower static char *rcsid = "$Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $";
5236415Ssklower #endif lint
5336415Ssklower 
5436415Ssklower #include "param.h"
5536415Ssklower #include "types.h"
5636415Ssklower #include "time.h"
57*37469Ssklower #include "malloc.h"
5836415Ssklower 
59*37469Ssklower #include "tp_param.h"
60*37469Ssklower #include "tp_timer.h"
61*37469Ssklower #include "tp_stat.h"
62*37469Ssklower #include "tp_pcb.h"
63*37469Ssklower #include "tp_tpdu.h"
64*37469Ssklower #include "argo_debug.h"
65*37469Ssklower #include "tp_trace.h"
66*37469Ssklower #include "tp_seq.h"
6736415Ssklower 
6836415Ssklower static  struct	Ecallout *TP_callfree;
6936415Ssklower static  struct	Ecallout TP_callout[N_TPREF*2];
7036415Ssklower 
7136415Ssklower extern int tp_maxrefopen;  /* highest ref # of an open tp connection */
7236415Ssklower 
7336415Ssklower /*
7436415Ssklower  * CALLED FROM:
7536415Ssklower  *  at autoconfig time from tp_init()
7636415Ssklower  * 	a combo of event, state, predicate
7736415Ssklower  * FUNCTION and ARGUMENTS:
7836415Ssklower  *  initialize data structures for the timers
7936415Ssklower  */
8036415Ssklower void
8136415Ssklower tp_timerinit()
8236415Ssklower {
8336415Ssklower 	register int i;
8436415Ssklower 	/*
8536415Ssklower 	 * Initialize callouts
8636415Ssklower 	 */
8736415Ssklower 	TP_callfree = TP_callout;
8836415Ssklower 	for (i = 1; i < N_TPREF*2; i++)
8936415Ssklower 		TP_callout[i-1].c_next = &TP_callout[i];
9036415Ssklower 
9136415Ssklower 	bzero( (caddr_t)tp_ref, N_TPREF * sizeof(struct tp_ref) );
9236415Ssklower 
9336415Ssklower 	/* hate to do this but we really don't want zero to be a legit ref */
9436415Ssklower 	tp_maxrefopen = 1;
9536415Ssklower 	tp_ref[0].tpr_state = REF_FROZEN;  /* white lie -- no ref timer, don't
9636415Ssklower 		* want this one to be allocated- ever
9736415Ssklower 		* unless, of course, you make refs and address instead of an
9836415Ssklower 		* index - then 0 can be allocated
9936415Ssklower 		*/
10036415Ssklower 
10136415Ssklower }
10236415Ssklower 
10336415Ssklower /**********************  e timers *************************/
10436415Ssklower 
10536415Ssklower /*
10636415Ssklower  * CALLED FROM:
10736415Ssklower  *  tp_slowtimo() every 1/2 second, for each open reference
10836415Ssklower  * FUNCTION and ARGUMENTS:
10936415Ssklower  *  (refp) indicates a reference structure that is in use.
11036415Ssklower  *  This ref structure may contain active E-type timers.
11136415Ssklower  *  Update the timers and if any expire, create an event and
11236415Ssklower  *  call the driver.
11336415Ssklower  */
11436415Ssklower static void
11536415Ssklower tp_Eclock(refp)
11636415Ssklower 	struct tp_ref	*refp; /* the reference structure */
11736415Ssklower {
11836415Ssklower 	register struct Ecallout *p1; /* to drift through the list of callouts */
11936415Ssklower 	struct tp_event			 E; /* event to pass to tp_driver() */
12036415Ssklower 	int						 tp_driver(); /* drives the FSM */
12136415Ssklower 
12236415Ssklower 	/*
12336415Ssklower 	 * Update real-time timeout queue.
12436415Ssklower 	 * At front of queue are some number of events which are ``due''.
12536415Ssklower 	 * The time to these is <= 0 and if negative represents the
12636415Ssklower 	 * number of ticks which have passed since it was supposed to happen.
12736415Ssklower 	 * The rest of the q elements (times > 0) are events yet to happen,
12836415Ssklower 	 * where the time for each is given as a delta from the previous.
12936415Ssklower 	 * Decrementing just the first of these serves to decrement the time
13036415Ssklower 	 * to all events.
13136415Ssklower 	 *
13236415Ssklower 	 * This version, which calls the driver directly, doesn't pass
13336415Ssklower 	 * along the ticks - may want to add the ticks if there's any use
13436415Ssklower 	 * for them.
13536415Ssklower 	 */
13636415Ssklower 	IncStat(ts_Eticks);
13736415Ssklower 	p1 = refp->tpr_calltodo.c_next;
13836415Ssklower 	while (p1) {
13936415Ssklower 		if (--p1->c_time > 0)
14036415Ssklower 			break;
14136415Ssklower 		if (p1->c_time == 0)
14236415Ssklower 			break;
14336415Ssklower 		p1 = p1->c_next;
14436415Ssklower 	}
14536415Ssklower 
14636415Ssklower 	for (;;) {
147*37469Ssklower 		struct tp_pcb *tpcb;
14836415Ssklower 		if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) {
14936415Ssklower 			break;
15036415Ssklower 		}
15136415Ssklower 		refp->tpr_calltodo.c_next = p1->c_next;
15236415Ssklower 		p1->c_next = TP_callfree;
15336415Ssklower 
15436415Ssklower #ifndef lint
15536415Ssklower 		E.ev_number = p1->c_func;
15636415Ssklower 		E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
15736415Ssklower 		E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
15836415Ssklower 		E.ATTR(TM_data_retrans).e_retrans =  p1->c_arg3;
15936415Ssklower #endif lint
16036415Ssklower 		IFDEBUG(D_TIMER)
16136415Ssklower 			printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n",
16236415Ssklower 				p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb,
16336415Ssklower 				refp-tp_ref);
16436415Ssklower 		ENDDEBUG
16536415Ssklower 
16636415Ssklower 		TP_callfree = p1;
16736415Ssklower 		IncStat(ts_Eexpired);
168*37469Ssklower 		(void) tp_driver( tpcb = refp->tpr_pcb, &E);
169*37469Ssklower 		if (p1->c_func == TM_reference && tpcb->tp_state == TP_CLOSED)
170*37469Ssklower 			free((caddr_t)tpcb, M_PCB); /* XXX wart; where else to do it? */
17136415Ssklower 	}
17236415Ssklower }
17336415Ssklower 
17436415Ssklower /*
17536415Ssklower  * CALLED FROM:
17636415Ssklower  *  tp.trans all over
17736415Ssklower  * FUNCTION and ARGUMENTS:
17836415Ssklower  * Set an E type timer.  (refp) is the ref structure.
17936415Ssklower  * Causes  fun(arg1,arg2,arg3) to be called after time t.
18036415Ssklower  */
18136415Ssklower void
18236415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
18336415Ssklower 	struct tp_ref	*refp;
18436415Ssklower 	int 			fun; 	/* function to be called */
18536415Ssklower 	u_int			arg1, arg2;
18636415Ssklower 	int				arg3;
18736415Ssklower 	register int	ticks;
18836415Ssklower {
18936415Ssklower 	register struct Ecallout *p1, *p2, *pnew;
19036415Ssklower 		/* p1 and p2 drift through the list of timeout callout structures,
19136415Ssklower 		 * pnew points to the newly created callout structure
19236415Ssklower 		 */
19336415Ssklower 
19436415Ssklower 	IFDEBUG(D_TIMER)
19536415Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
19636415Ssklower 		refp->tpr_pcb->tp_state);
19736415Ssklower 	ENDDEBUG
19836415Ssklower 	IFTRACE(D_TIMER)
19936415Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
20036415Ssklower 		refp->tpr_state, ticks, tp_stat.ts_Eticks);
20136415Ssklower 	ENDTRACE
20236415Ssklower 
20336415Ssklower 	IncStat(ts_Eset);
20436415Ssklower 	if (ticks == 0)
20536415Ssklower 		ticks = 1;
20636415Ssklower 	pnew = TP_callfree;
20736415Ssklower 	if (pnew == (struct Ecallout *)0)
20836415Ssklower 		panic("tp timeout table overflow");
20936415Ssklower 	TP_callfree = pnew->c_next;
21036415Ssklower 	pnew->c_arg1 = arg1;
21136415Ssklower 	pnew->c_arg2 = arg2;
21236415Ssklower 	pnew->c_arg3 = arg3;
21336415Ssklower 	pnew->c_func = fun;
21436415Ssklower 	for (p1 = &(refp->tpr_calltodo);
21536415Ssklower 							(p2 = p1->c_next) && p2->c_time < ticks; p1 = p2)
21636415Ssklower 		if (p2->c_time > 0)
21736415Ssklower 			ticks -= p2->c_time;
21836415Ssklower 	p1->c_next = pnew;
21936415Ssklower 	pnew->c_next = p2;
22036415Ssklower 	pnew->c_time = ticks;
22136415Ssklower 	if (p2)
22236415Ssklower 		p2->c_time -= ticks;
22336415Ssklower }
22436415Ssklower 
22536415Ssklower /*
22636415Ssklower  * CALLED FROM:
22736415Ssklower  *  tp.trans all over
22836415Ssklower  * FUNCTION and ARGUMENTS:
22936415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
23036415Ssklower  */
23136415Ssklower void
23236415Ssklower tp_euntimeout(refp, fun)
23336415Ssklower 	struct tp_ref *refp;
23436415Ssklower 	int			  fun;
23536415Ssklower {
23636415Ssklower 	register struct Ecallout *p1, *p2; /* ptrs to drift through the list */
23736415Ssklower 
23836415Ssklower 	IFTRACE(D_TIMER)
23936415Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
24036415Ssklower 	ENDTRACE
24136415Ssklower 
24236415Ssklower 	p1 = &refp->tpr_calltodo;
24336415Ssklower 	while ( (p2 = p1->c_next) != 0) {
24436415Ssklower 		if (p2->c_func == fun)  {
24536415Ssklower 			if (p2->c_next && p2->c_time > 0)
24636415Ssklower 				p2->c_next->c_time += p2->c_time;
24736415Ssklower 			p1->c_next = p2->c_next;
24836415Ssklower 			p2->c_next = TP_callfree;
24936415Ssklower 			TP_callfree = p2;
25036415Ssklower 			IncStat(ts_Ecan_act);
25136415Ssklower 			continue;
25236415Ssklower 		}
25336415Ssklower 		p1 = p2;
25436415Ssklower 	}
25536415Ssklower }
25636415Ssklower 
25736415Ssklower /*
25836415Ssklower  * CALLED FROM:
25936415Ssklower  *  tp.trans, when an incoming ACK causes things to be dropped
26036415Ssklower  *  from the retransmission queue, and we want their associated
26136415Ssklower  *  timers to be cancelled.
26236415Ssklower  * FUNCTION and ARGUMENTS:
26336415Ssklower  *  cancel all occurrences of function (fun) where (arg2) < (seq)
26436415Ssklower  */
26536415Ssklower void
26636415Ssklower tp_euntimeout_lss(refp, fun, seq)
26736415Ssklower 	struct tp_ref *refp;
26836415Ssklower 	int			  fun;
26936415Ssklower 	SeqNum		  seq;
27036415Ssklower {
27136415Ssklower 	register struct Ecallout *p1, *p2;
27236415Ssklower 
27336415Ssklower 	IFTRACE(D_TIMER)
27436415Ssklower 		tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
27536415Ssklower 	ENDTRACE
27636415Ssklower 
27736415Ssklower 	p1 = &refp->tpr_calltodo;
27836415Ssklower 	while ( (p2 = p1->c_next) != 0) {
27936415Ssklower 		if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq))  {
28036415Ssklower 			if (p2->c_next && p2->c_time > 0)
28136415Ssklower 				p2->c_next->c_time += p2->c_time;
28236415Ssklower 			p1->c_next = p2->c_next;
28336415Ssklower 			p2->c_next = TP_callfree;
28436415Ssklower 			TP_callfree = p2;
28536415Ssklower 			IncStat(ts_Ecan_act);
28636415Ssklower 			continue;
28736415Ssklower 		}
28836415Ssklower 		p1 = p2;
28936415Ssklower 	}
29036415Ssklower }
29136415Ssklower 
29236415Ssklower /****************  c timers **********************
29336415Ssklower  *
29436415Ssklower  * These are not chained together; they sit
29536415Ssklower  * in the tp_ref structure. they are the kind that
29636415Ssklower  * are typically cancelled so it's faster not to
29736415Ssklower  * mess with the chains
29836415Ssklower  */
29936415Ssklower 
30036415Ssklower /*
30136415Ssklower  * CALLED FROM:
30236415Ssklower  *  the clock, every 500 ms
30336415Ssklower  * FUNCTION and ARGUMENTS:
30436415Ssklower  *  Look for open references with active timers.
30536415Ssklower  *  If they exist, call the appropriate timer routines to update
30636415Ssklower  *  the timers and possibly generate events.
30736415Ssklower  *  (The E timers are done in other procedures; the C timers are
30836415Ssklower  *  updated here, and events for them are generated here.)
30936415Ssklower  */
31036415Ssklower ProtoHook
31136415Ssklower tp_slowtimo()
31236415Ssklower {
31336415Ssklower 	register int 		r,t;
31436415Ssklower 	struct Ccallout 	*cp;
31536415Ssklower 	struct tp_ref		*rp = tp_ref;
31636415Ssklower 	struct tp_event		E;
31736415Ssklower 	int 				s = splnet();
31836415Ssklower 
31936415Ssklower 	/* check only open reference structures */
32036415Ssklower 	IncStat(ts_Cticks);
32136415Ssklower 	rp++;	/* tp_ref[0] is never used */
32236415Ssklower 	for(  r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
32336415Ssklower 		if (rp->tpr_state < REF_OPEN)
32436415Ssklower 			continue;
32536415Ssklower 
32636415Ssklower 		/* check the C-type timers */
32736415Ssklower 		cp = rp->tpr_callout;
32836415Ssklower 		for (t=0 ; t < N_CTIMERS; t++,cp++) {
32936415Ssklower 			if( cp->c_active ) {
33036415Ssklower 				if( --cp->c_time <= 0 ) {
33136415Ssklower 					cp->c_active = FALSE;
33236415Ssklower 					E.ev_number = t;
33336415Ssklower 					IFDEBUG(D_TIMER)
33436415Ssklower 						printf("C expired! type 0x%x\n", t);
33536415Ssklower 					ENDDEBUG
33636415Ssklower 					IncStat(ts_Cexpired);
33736415Ssklower 					tp_driver( rp->tpr_pcb, &E);
33836415Ssklower 				}
33936415Ssklower 			}
34036415Ssklower 		}
34136415Ssklower 		/* now update the list */
34236415Ssklower 		tp_Eclock(rp);
34336415Ssklower 	}
34436415Ssklower 	splx(s);
34536415Ssklower 	return 0;
34636415Ssklower }
34736415Ssklower 
34836415Ssklower /*
34936415Ssklower  * CALLED FROM:
35036415Ssklower  *  tp.trans, tp_emit()
35136415Ssklower  * FUNCTION and ARGUMENTS:
35236415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
35336415Ssklower  */
35436415Ssklower void
35536415Ssklower tp_ctimeout(refp, which, ticks)
35636415Ssklower 	register struct tp_ref	*refp;
35736415Ssklower 	int 					which, ticks;
35836415Ssklower {
35936415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
36036415Ssklower 
36136415Ssklower 	IFTRACE(D_TIMER)
36236415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
36336415Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
36436415Ssklower 	ENDTRACE
36536415Ssklower 	if(cp->c_active)
36636415Ssklower 		IncStat(ts_Ccan_act);
36736415Ssklower 	IncStat(ts_Cset);
36836415Ssklower 	cp->c_time = ticks;
36936415Ssklower 	cp->c_active = TRUE;
37036415Ssklower }
37136415Ssklower 
37236415Ssklower /*
37336415Ssklower  * CALLED FROM:
37436415Ssklower  *  tp.trans
37536415Ssklower  * FUNCTION and ARGUMENTS:
37636415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
37736415Ssklower  * 	parameter (ticks) is > the current value of the timer.
37836415Ssklower  */
37936415Ssklower void
38036415Ssklower tp_ctimeout_MIN(refp, which, ticks)
38136415Ssklower 	register struct tp_ref	*refp;
38236415Ssklower 	int						which, ticks;
38336415Ssklower {
38436415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
38536415Ssklower 
38636415Ssklower 	IFTRACE(D_TIMER)
38736415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
38836415Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
38936415Ssklower 	ENDTRACE
39036415Ssklower 	if(cp->c_active)
39136415Ssklower 		IncStat(ts_Ccan_act);
39236415Ssklower 	IncStat(ts_Cset);
39336415Ssklower 	if( cp->c_active )
39436415Ssklower 		cp->c_time = MIN(ticks, cp->c_time);
39536415Ssklower 	else  {
39636415Ssklower 		cp->c_time = ticks;
39736415Ssklower 		cp->c_active = TRUE;
39836415Ssklower 	}
39936415Ssklower }
40036415Ssklower 
40136415Ssklower /*
40236415Ssklower  * CALLED FROM:
40336415Ssklower  *  tp.trans
40436415Ssklower  * FUNCTION and ARGUMENTS:
40536415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
40636415Ssklower  */
40736415Ssklower void
40836415Ssklower tp_cuntimeout(refp, which)
40936415Ssklower 	int						which;
41036415Ssklower 	register struct tp_ref	*refp;
41136415Ssklower {
41236415Ssklower 	register struct Ccallout *cp;
41336415Ssklower 
41436415Ssklower 	cp = &(refp->tpr_callout[which]);
41536415Ssklower 
41636415Ssklower 	IFDEBUG(D_TIMER)
417*37469Ssklower 		printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_active);
41836415Ssklower 	ENDDEBUG
41936415Ssklower 
42036415Ssklower 	IFTRACE(D_TIMER)
42136415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
42236415Ssklower 			which, cp->c_active, 0);
42336415Ssklower 	ENDTRACE
42436415Ssklower 
42536415Ssklower 	if(cp->c_active)
42636415Ssklower 		IncStat(ts_Ccan_act);
42736415Ssklower 	else
42836415Ssklower 		IncStat(ts_Ccan_inact);
42936415Ssklower 	cp->c_active = FALSE;
43036415Ssklower }
431