X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/1c15e88899094343f75aeba04122cd96a96b428e..ad7871609881e73855d0b04da49b486cd93efca7:/usr/src/sys/netiso/tp_timer.c diff --git a/usr/src/sys/netiso/tp_timer.c b/usr/src/sys/netiso/tp_timer.c index f898df5e64..b3a0be3a94 100644 --- a/usr/src/sys/netiso/tp_timer.c +++ b/usr/src/sys/netiso/tp_timer.c @@ -1,3 +1,38 @@ +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tp_timer.c 8.1 (Berkeley) 6/10/93 + */ + /*********************************************************** Copyright IBM Corporation 1987 @@ -29,47 +64,30 @@ SOFTWARE. * * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $ * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $ - * @(#)tp_timer.c 7.3 (Berkeley) 8/29/89 * - * - * Contains all the timer code. - * There are two sources of calls to these routines: - * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time) * - * Timers come in two flavors - those that generally get - * cancelled (tp_ctimeout, tp_cuntimeout) - * and those that either usually expire (tp_etimeout, - * tp_euntimeout, tp_slowtimo) or may require more than one instance - * of the timer active at a time. - * - * The C timers are stored in the tp_ref structure. Their "going off" - * is manifested by a driver event of the TM_xxx form. - * - * The E timers are handled like the generic kernel callouts. - * Their "going off" is manifested by a function call w/ 3 arguments. */ -#ifndef lint -static char *rcsid = "$Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $"; -#endif lint - -#include "param.h" -#include "types.h" -#include "time.h" -#include "malloc.h" - -#include "tp_param.h" -#include "tp_timer.h" -#include "tp_stat.h" -#include "tp_pcb.h" -#include "tp_tpdu.h" -#include "argo_debug.h" -#include "tp_trace.h" -#include "tp_seq.h" - -static struct Ecallout *TP_callfree; -static struct Ecallout TP_callout[N_TPREF*2]; - -extern int tp_maxrefopen; /* highest ref # of an open tp connection */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct tp_ref *tp_ref; +int tp_rttdiv, tp_rttadd, N_TPREF = 127; +struct tp_refinfo tp_refinfo; +struct tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; /* * CALLED FROM: @@ -81,146 +99,53 @@ extern int tp_maxrefopen; /* highest ref # of an open tp connection */ void tp_timerinit() { - register int i; + register int s; /* - * Initialize callouts + * Initialize storage */ - TP_callfree = TP_callout; - for (i = 1; i < N_TPREF*2; i++) - TP_callout[i-1].c_next = &TP_callout[i]; - - bzero( (caddr_t)tp_ref, N_TPREF * sizeof(struct tp_ref) ); - - /* hate to do this but we really don't want zero to be a legit ref */ - tp_maxrefopen = 1; - tp_ref[0].tpr_state = REF_FROZEN; /* white lie -- no ref timer, don't - * want this one to be allocated- ever - * unless, of course, you make refs and address instead of an - * index - then 0 can be allocated - */ - + if (tp_refinfo.tpr_base) + return; + tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */ + s = sizeof(*tp_ref) * tp_refinfo.tpr_size; + if ((tp_ref = (struct tp_ref *) malloc(s, M_PCB, M_NOWAIT)) == 0) + panic("tp_timerinit"); + bzero((caddr_t)tp_ref, (unsigned) s); + tp_refinfo.tpr_base = tp_ref; + tp_rttdiv = hz / PR_SLOWHZ; + tp_rttadd = (2 * tp_rttdiv) - 1; } - +#ifdef TP_DEBUG_TIMERS /********************** e timers *************************/ -/* - * CALLED FROM: - * tp_slowtimo() every 1/2 second, for each open reference - * FUNCTION and ARGUMENTS: - * (refp) indicates a reference structure that is in use. - * This ref structure may contain active E-type timers. - * Update the timers and if any expire, create an event and - * call the driver. - */ -static void -tp_Eclock(refp) - struct tp_ref *refp; /* the reference structure */ -{ - register struct Ecallout *p1; /* to drift through the list of callouts */ - struct tp_event E; /* event to pass to tp_driver() */ - int tp_driver(); /* drives the FSM */ - - /* - * Update real-time timeout queue. - * At front of queue are some number of events which are ``due''. - * The time to these is <= 0 and if negative represents the - * number of ticks which have passed since it was supposed to happen. - * The rest of the q elements (times > 0) are events yet to happen, - * where the time for each is given as a delta from the previous. - * Decrementing just the first of these serves to decrement the time - * to all events. - * - * This version, which calls the driver directly, doesn't pass - * along the ticks - may want to add the ticks if there's any use - * for them. - */ - IncStat(ts_Eticks); - p1 = refp->tpr_calltodo.c_next; - while (p1) { - if (--p1->c_time > 0) - break; - if (p1->c_time == 0) - break; - p1 = p1->c_next; - } - - for (;;) { - struct tp_pcb *tpcb; - if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) { - break; - } - refp->tpr_calltodo.c_next = p1->c_next; - p1->c_next = TP_callfree; - -#ifndef lint - E.ev_number = p1->c_func; - E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1; - E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2; - E.ATTR(TM_data_retrans).e_retrans = p1->c_arg3; -#endif lint - IFDEBUG(D_TIMER) - printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n", - p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb, - refp-tp_ref); - ENDDEBUG - - TP_callfree = p1; - IncStat(ts_Eexpired); - (void) tp_driver( tpcb = refp->tpr_pcb, &E); - if (p1->c_func == TM_reference && tpcb->tp_state == TP_CLOSED) - free((caddr_t)tpcb, M_PCB); /* XXX wart; where else to do it? */ - } -} - /* * CALLED FROM: * tp.trans all over * FUNCTION and ARGUMENTS: - * Set an E type timer. (refp) is the ref structure. - * Causes fun(arg1,arg2,arg3) to be called after time t. + * Set an E type timer. */ void -tp_etimeout(refp, fun, arg1, arg2, arg3, ticks) - struct tp_ref *refp; - int fun; /* function to be called */ - u_int arg1, arg2; - int arg3; - register int ticks; +tp_etimeout(tpcb, fun, ticks) + register struct tp_pcb *tpcb; + int fun; /* function to be called */ + int ticks; { - register struct Ecallout *p1, *p2, *pnew; - /* p1 and p2 drift through the list of timeout callout structures, - * pnew points to the newly created callout structure - */ + register u_int *callp; IFDEBUG(D_TIMER) - printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb, - refp->tpr_pcb->tp_state); + printf("etimeout pcb 0x%x state 0x%x\n", tpcb, tpcb->tp_state); ENDDEBUG IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref, - refp->tpr_state, ticks, tp_stat.ts_Eticks); + tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", tpcb->tp_lref, + tpcb->tp_state, ticks, tp_stat.ts_Eticks); ENDTRACE - + if (tpcb == 0) + return; IncStat(ts_Eset); if (ticks == 0) ticks = 1; - pnew = TP_callfree; - if (pnew == (struct Ecallout *)0) - panic("tp timeout table overflow"); - TP_callfree = pnew->c_next; - pnew->c_arg1 = arg1; - pnew->c_arg2 = arg2; - pnew->c_arg3 = arg3; - pnew->c_func = fun; - for (p1 = &(refp->tpr_calltodo); - (p2 = p1->c_next) && p2->c_time < ticks; p1 = p2) - if (p2->c_time > 0) - ticks -= p2->c_time; - p1->c_next = pnew; - pnew->c_next = p2; - pnew->c_time = ticks; - if (p2) - p2->c_time -= ticks; + callp = tpcb->tp_timer + fun; + if (*callp == 0 || *callp > ticks) + *callp = ticks; } /* @@ -230,64 +155,16 @@ tp_etimeout(refp, fun, arg1, arg2, arg3, ticks) * Cancel all occurrences of E-timer function (fun) for reference (refp) */ void -tp_euntimeout(refp, fun) - struct tp_ref *refp; - int fun; -{ - register struct Ecallout *p1, *p2; /* ptrs to drift through the list */ - - IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0); - ENDTRACE - - p1 = &refp->tpr_calltodo; - while ( (p2 = p1->c_next) != 0) { - if (p2->c_func == fun) { - if (p2->c_next && p2->c_time > 0) - p2->c_next->c_time += p2->c_time; - p1->c_next = p2->c_next; - p2->c_next = TP_callfree; - TP_callfree = p2; - IncStat(ts_Ecan_act); - continue; - } - p1 = p2; - } -} - -/* - * CALLED FROM: - * tp.trans, when an incoming ACK causes things to be dropped - * from the retransmission queue, and we want their associated - * timers to be cancelled. - * FUNCTION and ARGUMENTS: - * cancel all occurrences of function (fun) where (arg2) < (seq) - */ -void -tp_euntimeout_lss(refp, fun, seq) - struct tp_ref *refp; +tp_euntimeout(tpcb, fun) + register struct tp_pcb *tpcb; int fun; - SeqNum seq; { - register struct Ecallout *p1, *p2; - IFTRACE(D_TIMER) - tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0); + tptrace(TPPTmisc, "tp_euntimeout ref", tpcb->tp_lref, 0, 0, 0); ENDTRACE - p1 = &refp->tpr_calltodo; - while ( (p2 = p1->c_next) != 0) { - if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq)) { - if (p2->c_next && p2->c_time > 0) - p2->c_next->c_time += p2->c_time; - p1->c_next = p2->c_next; - p2->c_next = TP_callfree; - TP_callfree = p2; - IncStat(ts_Ecan_act); - continue; - } - p1 = p2; - } + if (tpcb) + tpcb->tp_timer[fun] = 0; } /**************** c timers ********************** @@ -297,7 +174,7 @@ tp_euntimeout_lss(refp, fun, seq) * are typically cancelled so it's faster not to * mess with the chains */ - +#endif /* * CALLED FROM: * the clock, every 500 ms @@ -305,47 +182,123 @@ tp_euntimeout_lss(refp, fun, seq) * Look for open references with active timers. * If they exist, call the appropriate timer routines to update * the timers and possibly generate events. - * (The E timers are done in other procedures; the C timers are - * updated here, and events for them are generated here.) */ ProtoHook tp_slowtimo() { - register int r,t; - struct Ccallout *cp; - struct tp_ref *rp = tp_ref; + register u_int *cp; + register struct tp_ref *rp; + struct tp_pcb *tpcb; struct tp_event E; - int s = splnet(); + int s = splnet(), t; /* check only open reference structures */ IncStat(ts_Cticks); - rp++; /* tp_ref[0] is never used */ - for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) { - if (rp->tpr_state < REF_OPEN) + /* tp_ref[0] is never used */ + for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) { + if ((tpcb = rp->tpr_pcb) == 0 || tpcb->tp_refstate < REF_OPEN) continue; - - /* check the C-type timers */ - cp = rp->tpr_callout; - for (t=0 ; t < N_CTIMERS; t++,cp++) { - if( cp->c_active ) { - if( --cp->c_time <= 0 ) { - cp->c_active = FALSE; - E.ev_number = t; - IFDEBUG(D_TIMER) - printf("C expired! type 0x%x\n", t); - ENDDEBUG - IncStat(ts_Cexpired); - tp_driver( rp->tpr_pcb, &E); + /* check the timers */ + for (t = 0; t < TM_NTIMERS; t++) { + cp = tpcb->tp_timer + t; + if (*cp && --(*cp) <= 0 ) { + *cp = 0; + E.ev_number = t; + IFDEBUG(D_TIMER) + printf("tp_slowtimo: pcb 0x%x t %d\n", + tpcb, t); + ENDDEBUG + IncStat(ts_Cexpired); + tp_driver(tpcb, &E); + if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { + if (tpcb->tp_notdetached) { + IFDEBUG(D_CONN) + printf("PRU_DETACH: not detached\n"); + ENDDEBUG + tp_detach(tpcb); + } + /* XXX wart; where else to do it? */ + free((caddr_t)tpcb, M_PCB); } } } - /* now update the list */ - tp_Eclock(rp); } splx(s); return 0; } +/* + * Called From: tp.trans from tp_slowtimo() -- retransmission timer went off. + */ +tp_data_retrans(tpcb) +register struct tp_pcb *tpcb; +{ + int rexmt, win; + tpcb->tp_rttemit = 0; /* cancel current round trip time */ + tpcb->tp_dupacks = 0; + tpcb->tp_sndnxt = tpcb->tp_snduna; + if (tpcb->tp_fcredit == 0) { + /* + * We transmitted new data, started timing it and the window + * got shrunk under us. This can only happen if all data + * that they wanted us to send got acked, so don't + * bother shrinking the congestion windows, et. al. + * The retransmission timer should have been reset in goodack() + */ + IFDEBUG(D_ACKRECV) + printf("tp_data_retrans: 0 window tpcb 0x%x una 0x%x\n", + tpcb, tpcb->tp_snduna); + ENDDEBUG + tpcb->tp_rxtshift = 0; + tpcb->tp_timer[TM_data_retrans] = 0; + tpcb->tp_timer[TM_sendack] = tpcb->tp_dt_ticks; + return; + } + rexmt = tpcb->tp_dt_ticks << min(tpcb->tp_rxtshift, TP_MAXRXTSHIFT); + win = min(tpcb->tp_fcredit, (tpcb->tp_cong_win / tpcb->tp_l_tpdusize / 2)); + win = max(win, 2); + tpcb->tp_cong_win = tpcb->tp_l_tpdusize; /* slow start again. */ + tpcb->tp_ssthresh = win * tpcb->tp_l_tpdusize; + /* We're losing; our srtt estimate is probably bogus. + * Clobber it so we'll take the next rtt measurement as our srtt; + * Maintain current rxt times until then. + */ + if (++tpcb->tp_rxtshift > TP_NRETRANS / 4) { + /* tpcb->tp_nlprotosw->nlp_losing(tpcb->tp_npcb) someday */ + tpcb->tp_rtt = 0; + } + TP_RANGESET(tpcb->tp_rxtcur, rexmt, tpcb->tp_peer_acktime, 128); + tpcb->tp_timer[TM_data_retrans] = tpcb->tp_rxtcur; + tp_send(tpcb); +} + +int +tp_fasttimo() +{ + register struct tp_pcb *t; + int s = splnet(); + struct tp_event E; + + E.ev_number = TM_sendack; + while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) { + if (t == 0) { + printf("tp_fasttimeo: should panic"); + tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; + } else { + if (t->tp_flags & TPF_DELACK) { + IncStat(ts_Fdelack); + tp_driver(t, &E); + t->tp_flags &= ~TPF_DELACK; + } else + IncStat(ts_Fpruned); + tp_ftimeolist = t->tp_fasttimeo; + t->tp_fasttimeo = 0; + } + } + splx(s); +} + +#ifdef TP_DEBUG_TIMERS /* * CALLED FROM: * tp.trans, tp_emit() @@ -353,21 +306,21 @@ tp_slowtimo() * Set a C type timer of type (which) to go off after (ticks) time. */ void -tp_ctimeout(refp, which, ticks) - register struct tp_ref *refp; +tp_ctimeout(tpcb, which, ticks) + register struct tp_pcb *tpcb; int which, ticks; { - register struct Ccallout *cp = &(refp->tpr_callout[which]); IFTRACE(D_TIMER) tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", - (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active); + tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); ENDTRACE - if(cp->c_active) + if(tpcb->tp_timer[which]) IncStat(ts_Ccan_act); IncStat(ts_Cset); - cp->c_time = ticks; - cp->c_active = TRUE; + if (ticks <= 0) + ticks = 1; + tpcb->tp_timer[which] = ticks; } /* @@ -378,25 +331,20 @@ tp_ctimeout(refp, which, ticks) * parameter (ticks) is > the current value of the timer. */ void -tp_ctimeout_MIN(refp, which, ticks) - register struct tp_ref *refp; +tp_ctimeout_MIN(tpcb, which, ticks) + register struct tp_pcb *tpcb; int which, ticks; { - register struct Ccallout *cp = &(refp->tpr_callout[which]); - IFTRACE(D_TIMER) tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", - (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active); + tpcb->tp_lref, which, tpcb, tpcb->tp_timer[which]); ENDTRACE - if(cp->c_active) - IncStat(ts_Ccan_act); IncStat(ts_Cset); - if( cp->c_active ) - cp->c_time = MIN(ticks, cp->c_time); - else { - cp->c_time = ticks; - cp->c_active = TRUE; - } + if (tpcb->tp_timer[which]) { + tpcb->tp_timer[which] = min(ticks, tpcb->tp_timer[which]); + IncStat(ts_Ccan_act); + } else + tpcb->tp_timer[which] = ticks; } /* @@ -406,26 +354,24 @@ tp_ctimeout_MIN(refp, which, ticks) * Cancel the (which) timer in the ref structure indicated by (refp). */ void -tp_cuntimeout(refp, which) +tp_cuntimeout(tpcb, which) + register struct tp_pcb *tpcb; int which; - register struct tp_ref *refp; { - register struct Ccallout *cp; - - cp = &(refp->tpr_callout[which]); - IFDEBUG(D_TIMER) - printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_active); + printf("tp_cuntimeout(0x%x, %d) active %d\n", + tpcb, which, tpcb->tp_timer[which]); ENDDEBUG IFTRACE(D_TIMER) tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, - which, cp->c_active, 0); + which, tpcb->tp_timer[which], 0); ENDTRACE - if(cp->c_active) + if (tpcb->tp_timer[which]) IncStat(ts_Ccan_act); else IncStat(ts_Ccan_inact); - cp->c_active = FALSE; + tpcb->tp_timer[which] = 0; } +#endif