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