149268Sbostic /*- 249268Sbostic * Copyright (c) 1991 The Regents of the University of California. 349268Sbostic * All rights reserved. 449268Sbostic * 549268Sbostic * %sccs.include.redist.c% 649268Sbostic * 7*51007Ssklower * @(#)tp_timer.c 7.8 (Berkeley) 09/05/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; 77*51007Ssklower int N_TPREF = 127; 7851006Ssklower struct tp_refinfo tp_refinfo; 7936415Ssklower 8036415Ssklower /* 8136415Ssklower * CALLED FROM: 8236415Ssklower * at autoconfig time from tp_init() 8336415Ssklower * a combo of event, state, predicate 8436415Ssklower * FUNCTION and ARGUMENTS: 8536415Ssklower * initialize data structures for the timers 8636415Ssklower */ 8736415Ssklower void 8836415Ssklower tp_timerinit() 8936415Ssklower { 9048752Ssklower register struct Ecallout *e; 9148752Ssklower register int s; 9248752Ssklower #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\ 9348752Ssklower if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);} 9436415Ssklower /* 9548752Ssklower * Initialize storage 9636415Ssklower */ 9748752Ssklower GETME(tp_ref, struct tp_ref *, 1 + N_TPREF); 9851006Ssklower tp_refinfo.tpr_base = tp_ref; 99*51007Ssklower tp_refinfo.tpr_size = N_TPREF + 1; /* Need to start somewhere */ 10048752Ssklower #undef GETME 10136415Ssklower } 10236415Ssklower 10336415Ssklower /********************** e timers *************************/ 10436415Ssklower 105*51007Ssklower int Enoisy = 1; 10636415Ssklower /* 10736415Ssklower * CALLED FROM: 10836415Ssklower * tp.trans all over 10936415Ssklower * FUNCTION and ARGUMENTS: 11036415Ssklower * Set an E type timer. (refp) is the ref structure. 11136415Ssklower * Causes fun(arg1,arg2,arg3) to be called after time t. 11236415Ssklower */ 11336415Ssklower void 11436415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks) 11536415Ssklower struct tp_ref *refp; 11636415Ssklower int fun; /* function to be called */ 11736415Ssklower u_int arg1, arg2; 11836415Ssklower int arg3; 11936415Ssklower register int ticks; 12036415Ssklower { 12136415Ssklower 122*51007Ssklower register struct tp_pcb *tpcb = refp->tpr_pcb; 123*51007Ssklower register struct Ccallout *callp; 12436415Ssklower IFDEBUG(D_TIMER) 12536415Ssklower printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb, 12636415Ssklower refp->tpr_pcb->tp_state); 12736415Ssklower ENDDEBUG 12836415Ssklower IFTRACE(D_TIMER) 12936415Ssklower tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref, 13036415Ssklower refp->tpr_state, ticks, tp_stat.ts_Eticks); 13136415Ssklower ENDTRACE 132*51007Ssklower if (tpcb == 0) 133*51007Ssklower return; 13436415Ssklower IncStat(ts_Eset); 13536415Ssklower if (ticks == 0) 13636415Ssklower ticks = 1; 137*51007Ssklower if (fun == TM_data_retrans) { 138*51007Ssklower tpcb->tp_retransargs.c_arg1 = arg1; 139*51007Ssklower tpcb->tp_retransargs.c_arg2 = arg2; 140*51007Ssklower tpcb->tp_retransargs.c_arg3 = arg3; 141*51007Ssklower } 142*51007Ssklower callp = tpcb->tp_refcallout + fun; 143*51007Ssklower if (Enoisy && callp->c_time) 144*51007Ssklower printf("E timer allready set: %d of ref %d\n", fun, tpcb->tp_lref); 145*51007Ssklower if (callp->c_time == 0 || callp->c_time > ticks) 146*51007Ssklower callp->c_time = ticks; 14736415Ssklower } 14836415Ssklower 14936415Ssklower /* 15036415Ssklower * CALLED FROM: 15136415Ssklower * tp.trans all over 15236415Ssklower * FUNCTION and ARGUMENTS: 15336415Ssklower * Cancel all occurrences of E-timer function (fun) for reference (refp) 15436415Ssklower */ 15536415Ssklower void 15636415Ssklower tp_euntimeout(refp, fun) 15736415Ssklower struct tp_ref *refp; 15836415Ssklower int fun; 15936415Ssklower { 160*51007Ssklower register struct tp_pcb *tpcb = refp->tpr_pcb; 16136415Ssklower 16236415Ssklower IFTRACE(D_TIMER) 16336415Ssklower tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0); 16436415Ssklower ENDTRACE 16536415Ssklower 166*51007Ssklower if (tpcb) 167*51007Ssklower tpcb->tp_refcallout[fun].c_time = 0; 16836415Ssklower } 16936415Ssklower 17036415Ssklower /* 17136415Ssklower * CALLED FROM: 17236415Ssklower * tp.trans, when an incoming ACK causes things to be dropped 17336415Ssklower * from the retransmission queue, and we want their associated 17436415Ssklower * timers to be cancelled. 175*51007Ssklower * NOTE: (by sklower) only called with TM_data_retrans. 17636415Ssklower * FUNCTION and ARGUMENTS: 17736415Ssklower * cancel all occurrences of function (fun) where (arg2) < (seq) 17836415Ssklower */ 17936415Ssklower void 18036415Ssklower tp_euntimeout_lss(refp, fun, seq) 18136415Ssklower struct tp_ref *refp; 18236415Ssklower int fun; 18336415Ssklower SeqNum seq; 18436415Ssklower { 185*51007Ssklower register struct tp_pcb *tpcb = refp->tpr_pcb; 18636415Ssklower 18736415Ssklower IFTRACE(D_TIMER) 18836415Ssklower tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0); 18936415Ssklower ENDTRACE 19036415Ssklower 191*51007Ssklower if (tpcb == 0 || tpcb->tp_refcallout[fun].c_time == 0) 192*51007Ssklower return; 193*51007Ssklower if (SEQ_LT(tpcb, tpcb->tp_retransargs.c_arg2, seq)) { 19436415Ssklower IncStat(ts_Ecan_act); 195*51007Ssklower tpcb->tp_refcallout[fun].c_time = 0; 19636415Ssklower } 19736415Ssklower } 19836415Ssklower 19936415Ssklower /**************** c timers ********************** 20036415Ssklower * 20136415Ssklower * These are not chained together; they sit 20236415Ssklower * in the tp_ref structure. they are the kind that 20336415Ssklower * are typically cancelled so it's faster not to 20436415Ssklower * mess with the chains 20536415Ssklower */ 20636415Ssklower 20736415Ssklower /* 20836415Ssklower * CALLED FROM: 20936415Ssklower * the clock, every 500 ms 21036415Ssklower * FUNCTION and ARGUMENTS: 21136415Ssklower * Look for open references with active timers. 21236415Ssklower * If they exist, call the appropriate timer routines to update 21336415Ssklower * the timers and possibly generate events. 21436415Ssklower * (The E timers are done in other procedures; the C timers are 21536415Ssklower * updated here, and events for them are generated here.) 21636415Ssklower */ 21736415Ssklower ProtoHook 21836415Ssklower tp_slowtimo() 21936415Ssklower { 220*51007Ssklower register struct Ccallout *cp, *cpbase; 221*51007Ssklower register struct tp_ref *rp; 222*51007Ssklower struct tp_pcb *tpcb; 22336415Ssklower struct tp_event E; 224*51007Ssklower int s = splnet(), t; 22536415Ssklower 22636415Ssklower /* check only open reference structures */ 22736415Ssklower IncStat(ts_Cticks); 228*51007Ssklower /* tp_ref[0] is never used */ 229*51007Ssklower for (rp = tp_ref + tp_refinfo.tpr_maxopen; rp > tp_ref; rp--) { 230*51007Ssklower if ((tpcb = rp->tpr_pcb) == 0 || rp->tpr_state < REF_OPEN) 23136415Ssklower continue; 232*51007Ssklower cpbase = tpcb->tp_refcallout; 233*51007Ssklower t = N_CTIMERS; 23436415Ssklower /* check the C-type timers */ 235*51007Ssklower for (cp = cpbase + t; (--t, --cp) >= cpbase; ) { 236*51007Ssklower if (cp->c_time && --(cp->c_time) <= 0 ) { 237*51007Ssklower cp->c_time = 0; 238*51007Ssklower E.ev_number = t; 239*51007Ssklower if (t == TM_data_retrans) { 240*51007Ssklower register struct Ecallarg *p1 = &tpcb->tp_retransargs; 241*51007Ssklower E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1; 242*51007Ssklower E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2; 243*51007Ssklower E.ATTR(TM_data_retrans).e_retrans = p1->c_arg3; 24436415Ssklower } 245*51007Ssklower IFDEBUG(D_TIMER) 246*51007Ssklower printf("C expired! type 0x%x\n", t); 247*51007Ssklower ENDDEBUG 248*51007Ssklower IncStat(ts_Cexpired); 249*51007Ssklower tp_driver( rp->tpr_pcb, &E); 250*51007Ssklower if (t == TM_reference && tpcb->tp_state == TP_CLOSED) { 251*51007Ssklower if (tpcb->tp_notdetached) { 252*51007Ssklower IFDEBUG(D_CONN) 253*51007Ssklower printf("PRU_DETACH: not detached\n"); 254*51007Ssklower ENDDEBUG 255*51007Ssklower tp_detach(tpcb); 256*51007Ssklower } 257*51007Ssklower /* XXX wart; where else to do it? */ 258*51007Ssklower free((caddr_t)tpcb, M_PCB); 259*51007Ssklower } 26036415Ssklower } 26136415Ssklower } 26236415Ssklower } 26336415Ssklower splx(s); 26436415Ssklower return 0; 26536415Ssklower } 26636415Ssklower 26736415Ssklower /* 26836415Ssklower * CALLED FROM: 26936415Ssklower * tp.trans, tp_emit() 27036415Ssklower * FUNCTION and ARGUMENTS: 27136415Ssklower * Set a C type timer of type (which) to go off after (ticks) time. 27236415Ssklower */ 27336415Ssklower void 27436415Ssklower tp_ctimeout(refp, which, ticks) 27536415Ssklower register struct tp_ref *refp; 27636415Ssklower int which, ticks; 27736415Ssklower { 27836415Ssklower register struct Ccallout *cp = &(refp->tpr_callout[which]); 27936415Ssklower 28036415Ssklower IFTRACE(D_TIMER) 28136415Ssklower tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", 282*51007Ssklower (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time); 28336415Ssklower ENDTRACE 284*51007Ssklower if(cp->c_time) 28536415Ssklower IncStat(ts_Ccan_act); 28636415Ssklower IncStat(ts_Cset); 287*51007Ssklower if (ticks <= 0) 288*51007Ssklower ticks = 1; 28936415Ssklower cp->c_time = ticks; 29036415Ssklower } 29136415Ssklower 29236415Ssklower /* 29336415Ssklower * CALLED FROM: 29436415Ssklower * tp.trans 29536415Ssklower * FUNCTION and ARGUMENTS: 29636415Ssklower * Version of tp_ctimeout that resets the C-type time if the 29736415Ssklower * parameter (ticks) is > the current value of the timer. 29836415Ssklower */ 29936415Ssklower void 30036415Ssklower tp_ctimeout_MIN(refp, which, ticks) 30136415Ssklower register struct tp_ref *refp; 30236415Ssklower int which, ticks; 30336415Ssklower { 30436415Ssklower register struct Ccallout *cp = &(refp->tpr_callout[which]); 30536415Ssklower 30636415Ssklower IFTRACE(D_TIMER) 30736415Ssklower tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", 308*51007Ssklower (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_time); 30936415Ssklower ENDTRACE 31036415Ssklower IncStat(ts_Cset); 311*51007Ssklower if (cp->c_time) { 31236415Ssklower cp->c_time = MIN(ticks, cp->c_time); 313*51007Ssklower IncStat(ts_Ccan_act); 314*51007Ssklower } else 31536415Ssklower cp->c_time = ticks; 31636415Ssklower } 31736415Ssklower 31836415Ssklower /* 31936415Ssklower * CALLED FROM: 32036415Ssklower * tp.trans 32136415Ssklower * FUNCTION and ARGUMENTS: 32236415Ssklower * Cancel the (which) timer in the ref structure indicated by (refp). 32336415Ssklower */ 32436415Ssklower void 32536415Ssklower tp_cuntimeout(refp, which) 32636415Ssklower int which; 32736415Ssklower register struct tp_ref *refp; 32836415Ssklower { 32936415Ssklower register struct Ccallout *cp; 33036415Ssklower 33136415Ssklower cp = &(refp->tpr_callout[which]); 33236415Ssklower 33336415Ssklower IFDEBUG(D_TIMER) 334*51007Ssklower printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_time); 33536415Ssklower ENDDEBUG 33636415Ssklower 33736415Ssklower IFTRACE(D_TIMER) 33836415Ssklower tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, 339*51007Ssklower which, cp->c_time, 0); 34036415Ssklower ENDTRACE 34136415Ssklower 342*51007Ssklower if (cp->c_time) 34336415Ssklower IncStat(ts_Ccan_act); 34436415Ssklower else 34536415Ssklower IncStat(ts_Ccan_inact); 346*51007Ssklower cp->c_time = 0; 34736415Ssklower } 348