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