149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51024Ssklower * @(#)tp_timer.c 7.9 (Berkeley) 09/06/91 849268Sbostic */ 949268Sbostic 1036415Ssklower /*********************************************************** 1136415Ssklower Copyright IBM Corporation 1987 1236415Ssklower 1336415Ssklower All Rights Reserved 1436415Ssklower 1536415Ssklower Permission to use, copy, modify, and distribute this software and its 1636415Ssklower documentation for any purpose and without fee is hereby granted, 1736415Ssklower provided that the above copyright notice appear in all copies and that 1836415Ssklower both that copyright notice and this permission notice appear in 1936415Ssklower supporting documentation, and that the name of IBM not be 2036415Ssklower used in advertising or publicity pertaining to distribution of the 2136415Ssklower software without specific, written prior permission. 2236415Ssklower 2336415Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 2436415Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 2536415Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 2636415Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 2736415Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 2836415Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 2936415Ssklower SOFTWARE. 3036415Ssklower 3136415Ssklower ******************************************************************/ 3236415Ssklower 3336415Ssklower /* 3436415Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 3536415Ssklower */ 3636415Ssklower /* 3736415Ssklower * ARGO TP 3836415Ssklower * 3936415Ssklower * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $ 4036415Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $ 4136415Ssklower * 4236415Ssklower * Contains all the timer code. 4336415Ssklower * There are two sources of calls to these routines: 4436415Ssklower * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time) 4536415Ssklower * 4636415Ssklower * Timers come in two flavors - those that generally get 4736415Ssklower * cancelled (tp_ctimeout, tp_cuntimeout) 4836415Ssklower * and those that either usually expire (tp_etimeout, 4936415Ssklower * tp_euntimeout, tp_slowtimo) or may require more than one instance 5036415Ssklower * of the timer active at a time. 5136415Ssklower * 5236415Ssklower * The C timers are stored in the tp_ref structure. Their "going off" 5336415Ssklower * is manifested by a driver event of the TM_xxx form. 5436415Ssklower * 5536415Ssklower * The E timers are handled like the generic kernel callouts. 5636415Ssklower * Their "going off" is manifested by a function call w/ 3 arguments. 5736415Ssklower */ 5836415Ssklower 5936415Ssklower #include "param.h" 6036415Ssklower #include "types.h" 6136415Ssklower #include "time.h" 6237469Ssklower #include "malloc.h" 6348752Ssklower #include "socket.h" 6436415Ssklower 6537469Ssklower #include "tp_param.h" 6637469Ssklower #include "tp_timer.h" 6737469Ssklower #include "tp_stat.h" 6837469Ssklower #include "tp_pcb.h" 6937469Ssklower #include "tp_tpdu.h" 7037469Ssklower #include "argo_debug.h" 7137469Ssklower #include "tp_trace.h" 7237469Ssklower #include "tp_seq.h" 7336415Ssklower 7448752Ssklower struct Ecallout *TP_callfree; 7548752Ssklower struct Ecallout *TP_callout; 7648752Ssklower struct tp_ref *tp_ref; 7751007Ssklower int N_TPREF = 127; 7851006Ssklower struct tp_refinfo tp_refinfo; 79*51024Ssklower struct tp_pcb *tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; 8036415Ssklower 8136415Ssklower /* 8236415Ssklower * CALLED FROM: 8336415Ssklower * at autoconfig time from tp_init() 8436415Ssklower * a combo of event, state, predicate 8536415Ssklower * FUNCTION and ARGUMENTS: 8636415Ssklower * initialize data structures for the timers 8736415Ssklower */ 8836415Ssklower void 8936415Ssklower tp_timerinit() 9036415Ssklower { 9148752Ssklower register struct Ecallout *e; 9248752Ssklower register int s; 9348752Ssklower #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\ 9448752Ssklower if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);} 9536415Ssklower /* 9648752Ssklower * Initialize storage 9736415Ssklower */ 9848752Ssklower GETME(tp_ref, struct tp_ref *, 1 + N_TPREF); 9951006Ssklower tp_refinfo.tpr_base = tp_ref; 10051007Ssklower tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */ 10148752Ssklower #undef GETME 10236415Ssklower } 10336415Ssklower 10436415Ssklower /********************** e timers *************************/ 10536415Ssklower 10651007Ssklower int Enoisy = 1; 10736415Ssklower /* 10836415Ssklower * CALLED FROM: 10936415Ssklower * tp.trans all over 11036415Ssklower * FUNCTION and ARGUMENTS: 11136415Ssklower * Set an E type timer. (refp) is the ref structure. 11236415Ssklower * Causes fun(arg1,arg2,arg3) to be called after time t. 11336415Ssklower */ 11436415Ssklower void 11536415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks) 11636415Ssklower struct tp_ref *refp; 11736415Ssklower int fun; /* function to be called */ 11836415Ssklower u_int arg1, arg2; 11936415Ssklower int arg3; 12036415Ssklower register int ticks; 12136415Ssklower { 12236415Ssklower 12351007Ssklower register struct tp_pcb *tpcb = refp->tpr_pcb; 12451007Ssklower register struct Ccallout *callp; 12536415Ssklower IFDEBUG(D_TIMER) 12636415Ssklower printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb, 12736415Ssklower refp->tpr_pcb->tp_state); 12836415Ssklower ENDDEBUG 12936415Ssklower IFTRACE(D_TIMER) 13036415Ssklower tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref, 13136415Ssklower refp->tpr_state, ticks, tp_stat.ts_Eticks); 13236415Ssklower ENDTRACE 13351007Ssklower if (tpcb == 0) 13451007Ssklower return; 13536415Ssklower IncStat(ts_Eset); 13636415Ssklower if (ticks == 0) 13736415Ssklower ticks = 1; 13851007Ssklower if (fun == TM_data_retrans) { 13951007Ssklower tpcb->tp_retransargs.c_arg1 = arg1; 14051007Ssklower tpcb->tp_retransargs.c_arg2 = arg2; 14151007Ssklower tpcb->tp_retransargs.c_arg3 = arg3; 14251007Ssklower } 14351007Ssklower callp = tpcb->tp_refcallout + fun; 14451007Ssklower if (Enoisy && callp->c_time) 14551007Ssklower printf("E timer allready set: %d of ref %d\n", fun, tpcb->tp_lref); 14651007Ssklower if (callp->c_time == 0 || callp->c_time > ticks) 14751007Ssklower callp->c_time = ticks; 14836415Ssklower } 14936415Ssklower 15036415Ssklower /* 15136415Ssklower * CALLED FROM: 15236415Ssklower * tp.trans all over 15336415Ssklower * FUNCTION and ARGUMENTS: 15436415Ssklower * Cancel all occurrences of E-timer function (fun) for reference (refp) 15536415Ssklower */ 15636415Ssklower void 15736415Ssklower tp_euntimeout(refp, fun) 15836415Ssklower struct tp_ref *refp; 15936415Ssklower int fun; 16036415Ssklower { 16151007Ssklower register struct tp_pcb *tpcb = refp->tpr_pcb; 16236415Ssklower 16336415Ssklower IFTRACE(D_TIMER) 16436415Ssklower tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0); 16536415Ssklower ENDTRACE 16636415Ssklower 16751007Ssklower if (tpcb) 16851007Ssklower tpcb->tp_refcallout[fun].c_time = 0; 16936415Ssklower } 17036415Ssklower 17136415Ssklower /* 17236415Ssklower * CALLED FROM: 17336415Ssklower * tp.trans, when an incoming ACK causes things to be dropped 17436415Ssklower * from the retransmission queue, and we want their associated 17536415Ssklower * timers to be cancelled. 17651007Ssklower * NOTE: (by sklower) only called with TM_data_retrans. 17736415Ssklower * FUNCTION and ARGUMENTS: 17836415Ssklower * cancel all occurrences of function (fun) where (arg2) < (seq) 17936415Ssklower */ 18036415Ssklower void 18136415Ssklower tp_euntimeout_lss(refp, fun, seq) 18236415Ssklower struct tp_ref *refp; 18336415Ssklower int fun; 18436415Ssklower SeqNum seq; 18536415Ssklower { 18651007Ssklower register struct tp_pcb *tpcb = refp->tpr_pcb; 18736415Ssklower 18836415Ssklower IFTRACE(D_TIMER) 18936415Ssklower tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0); 19036415Ssklower ENDTRACE 19136415Ssklower 19251007Ssklower if (tpcb == 0 || tpcb->tp_refcallout[fun].c_time == 0) 19351007Ssklower return; 19451007Ssklower if (SEQ_LT(tpcb, tpcb->tp_retransargs.c_arg2, seq)) { 19536415Ssklower IncStat(ts_Ecan_act); 19651007Ssklower tpcb->tp_refcallout[fun].c_time = 0; 19736415Ssklower } 19836415Ssklower } 19936415Ssklower 20036415Ssklower /**************** c timers ********************** 20136415Ssklower * 20236415Ssklower * These are not chained together; they sit 20336415Ssklower * in the tp_ref structure. they are the kind that 20436415Ssklower * are typically cancelled so it's faster not to 20536415Ssklower * mess with the chains 20636415Ssklower */ 20736415Ssklower 20836415Ssklower /* 20936415Ssklower * CALLED FROM: 21036415Ssklower * the clock, every 500 ms 21136415Ssklower * FUNCTION and ARGUMENTS: 21236415Ssklower * Look for open references with active timers. 21336415Ssklower * If they exist, call the appropriate timer routines to update 21436415Ssklower * the timers and possibly generate events. 21536415Ssklower * (The E timers are done in other procedures; the C timers are 21636415Ssklower * updated here, and events for them are generated here.) 21736415Ssklower */ 21836415Ssklower ProtoHook 21936415Ssklower tp_slowtimo() 22036415Ssklower { 22151007Ssklower register struct Ccallout *cp, *cpbase; 22251007Ssklower register struct tp_ref *rp; 22351007Ssklower struct tp_pcb *tpcb; 22436415Ssklower struct tp_event E; 22551007Ssklower int s = splnet(), t; 22636415Ssklower 22736415Ssklower /* check only open reference structures */ 22836415Ssklower IncStat(ts_Cticks); 22951007Ssklower /* tp_ref[0] is never used */ 23051007Ssklower for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) { 23151007Ssklower if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN) 23236415Ssklower continue; 23351007Ssklower cpbase = tpcb->tp_refcallout; 23451007Ssklower t = N_CTIMERS; 23536415Ssklower /* check the C-type timers */ 23651007Ssklower for (cp = cpbase + t; (--t, --cp) >= cpbase; ) { 23751007Ssklower if (cp->c_time && --(cp->c_time) <= 0 ) { 23851007Ssklower cp->c_time = 0; 23951007Ssklower E.ev_number = t; 24051007Ssklower if (t == TM_data_retrans) { 24151007Ssklower register struct Ecallarg *p1 = &tpcb->tp_retransargs; 24251007Ssklower E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1; 24351007Ssklower E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2; 24451007Ssklower E.ATTR(TM_data_retrans).e_retrans = p1->c_arg3; 24536415Ssklower } 24651007Ssklower IFDEBUG(D_TIMER) 24751007Ssklower printf("C expired! type 0x%x\n", t); 24851007Ssklower ENDDEBUG 24951007Ssklower IncStat(ts_Cexpired); 25051007Ssklower tp_driver( rp->tpr_pcb, &E); 25151007Ssklower if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { 25251007Ssklower if (tpcb->tp_notdetached) { 25351007Ssklower IFDEBUG(D_CONN) 25451007Ssklower printf("PRU_DETACH: not detached\n"); 25551007Ssklower ENDDEBUG 25651007Ssklower tp_detach(tpcb); 25751007Ssklower } 25851007Ssklower /* XXX wart; where else to do it? */ 25951007Ssklower free((caddr_t)tpcb, M_PCB); 26051007Ssklower } 26136415Ssklower } 26236415Ssklower } 26336415Ssklower } 26436415Ssklower splx(s); 26536415Ssklower return 0; 26636415Ssklower } 26736415Ssklower 268*51024Ssklower int 269*51024Ssklower tp_fasttimo() 270*51024Ssklower { 271*51024Ssklower register struct tp_pcb *t; 272*51024Ssklower int s = splnet(); 273*51024Ssklower struct tp_event E; 274*51024Ssklower 275*51024Ssklower E.ev_number = TM_sendack; 276*51024Ssklower while ((t = tp_ftimeolist) != (struct tp_pcb *)&tp_ftimeolist) { 277*51024Ssklower if (t == 0) { 278*51024Ssklower printf("tp_fasttimeo: should panic"); 279*51024Ssklower tp_ftimeolist = (struct tp_pcb *)&tp_ftimeolist; 280*51024Ssklower } else { 281*51024Ssklower if (t->tp_flags & TPF_DELACK) { 282*51024Ssklower t->tp_flags &= ~TPF_DELACK; 283*51024Ssklower IncStat(ts_Fdelack); 284*51024Ssklower tp_driver(t, &E); 285*51024Ssklower t->tp_refcallout[TM_sendack].c_time = t->tp_keepalive_ticks; 286*51024Ssklower } else 287*51024Ssklower IncStat(ts_Fpruned); 288*51024Ssklower tp_ftimeolist = t->tp_fasttimeo; 289*51024Ssklower t->tp_fasttimeo = 0; 290*51024Ssklower } 291*51024Ssklower } 292*51024Ssklower splx(s); 293*51024Ssklower } 294*51024Ssklower 29536415Ssklower /* 29636415Ssklower * CALLED FROM: 29736415Ssklower * tp.trans, tp_emit() 29836415Ssklower * FUNCTION and ARGUMENTS: 29936415Ssklower * Set a C type timer of type (which) to go off after (ticks) time. 30036415Ssklower */ 30136415Ssklower void 30236415Ssklower tp_ctimeout(refp, which, ticks) 30336415Ssklower register struct tp_ref *refp; 30436415Ssklower int which, ticks; 30536415Ssklower { 30636415Ssklower register struct Ccallout *cp = &(refp->tpr_callout[which]); 30736415Ssklower 30836415Ssklower IFTRACE(D_TIMER) 30936415Ssklower tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", 31051007Ssklower (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time); 31136415Ssklower ENDTRACE 31251007Ssklower if(cp->c_time) 31336415Ssklower IncStat(ts_Ccan_act); 31436415Ssklower IncStat(ts_Cset); 31551007Ssklower if (ticks <= 0) 31651007Ssklower ticks = 1; 31736415Ssklower cp->c_time = ticks; 31836415Ssklower } 31936415Ssklower 32036415Ssklower /* 32136415Ssklower * CALLED FROM: 32236415Ssklower * tp.trans 32336415Ssklower * FUNCTION and ARGUMENTS: 32436415Ssklower * Version of tp_ctimeout that resets the C-type time if the 32536415Ssklower * parameter (ticks) is > the current value of the timer. 32636415Ssklower */ 32736415Ssklower void 32836415Ssklower tp_ctimeout_MIN(refp, which, ticks) 32936415Ssklower register struct tp_ref *refp; 33036415Ssklower int which, ticks; 33136415Ssklower { 33236415Ssklower register struct Ccallout *cp = &(refp->tpr_callout[which]); 33336415Ssklower 33436415Ssklower IFTRACE(D_TIMER) 33536415Ssklower tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", 33651007Ssklower (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time); 33736415Ssklower ENDTRACE 33836415Ssklower IncStat(ts_Cset); 33951007Ssklower if (cp->c_time) { 34036415Ssklower cp->c_time = MIN(ticks, cp->c_time); 34151007Ssklower IncStat(ts_Ccan_act); 34251007Ssklower } else 34336415Ssklower cp->c_time = ticks; 34436415Ssklower } 34536415Ssklower 34636415Ssklower /* 34736415Ssklower * CALLED FROM: 34836415Ssklower * tp.trans 34936415Ssklower * FUNCTION and ARGUMENTS: 35036415Ssklower * Cancel the (which) timer in the ref structure indicated by (refp). 35136415Ssklower */ 35236415Ssklower void 35336415Ssklower tp_cuntimeout(refp, which) 35436415Ssklower int which; 35536415Ssklower register struct tp_ref *refp; 35636415Ssklower { 35736415Ssklower register struct Ccallout *cp; 35836415Ssklower 35936415Ssklower cp = &(refp->tpr_callout[which]); 36036415Ssklower 36136415Ssklower IFDEBUG(D_TIMER) 36251007Ssklower printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_time); 36336415Ssklower ENDDEBUG 36436415Ssklower 36536415Ssklower IFTRACE(D_TIMER) 36636415Ssklower tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, 36751007Ssklower which, cp->c_time, 0); 36836415Ssklower ENDTRACE 36936415Ssklower 37051007Ssklower if (cp->c_time) 37136415Ssklower IncStat(ts_Ccan_act); 37236415Ssklower else 37336415Ssklower IncStat(ts_Ccan_inact); 37451007Ssklower cp->c_time = 0; 37536415Ssklower } 376