1*49268Sbostic /*- 2*49268Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*49268Sbostic * All rights reserved. 4*49268Sbostic * 5*49268Sbostic * %sccs.include.redist.c% 6*49268Sbostic * 7*49268Sbostic * @(#)tp_timer.c 7.5 (Berkeley) 05/06/91 8*49268Sbostic */ 9*49268Sbostic 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; 7748752Ssklower int N_TPREF = 100; 7836415Ssklower 7936415Ssklower extern int tp_maxrefopen; /* highest ref # of an open tp connection */ 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_callout, struct Ecallout *, 2 * N_TPREF); 9948752Ssklower GETME(tp_ref, struct tp_ref *, 1 + N_TPREF); 10036415Ssklower 10148752Ssklower TP_callfree = TP_callout + ((2 * N_TPREF) - 1); 10248752Ssklower for (e = TP_callfree; e > TP_callout; e--) 10348752Ssklower e->c_next = e - 1; 10436415Ssklower 10536415Ssklower /* hate to do this but we really don't want zero to be a legit ref */ 10636415Ssklower tp_maxrefopen = 1; 10736415Ssklower tp_ref[0].tpr_state = REF_FROZEN; /* white lie -- no ref timer, don't 10836415Ssklower * want this one to be allocated- ever 10936415Ssklower * unless, of course, you make refs and address instead of an 11036415Ssklower * index - then 0 can be allocated 11136415Ssklower */ 11248752Ssklower #undef GETME 11336415Ssklower } 11436415Ssklower 11536415Ssklower /********************** e timers *************************/ 11636415Ssklower 11736415Ssklower /* 11836415Ssklower * CALLED FROM: 11936415Ssklower * tp_slowtimo() every 1/2 second, for each open reference 12036415Ssklower * FUNCTION and ARGUMENTS: 12136415Ssklower * (refp) indicates a reference structure that is in use. 12236415Ssklower * This ref structure may contain active E-type timers. 12336415Ssklower * Update the timers and if any expire, create an event and 12436415Ssklower * call the driver. 12536415Ssklower */ 12636415Ssklower static void 12736415Ssklower tp_Eclock(refp) 12836415Ssklower struct tp_ref *refp; /* the reference structure */ 12936415Ssklower { 13036415Ssklower register struct Ecallout *p1; /* to drift through the list of callouts */ 13136415Ssklower struct tp_event E; /* event to pass to tp_driver() */ 13236415Ssklower int tp_driver(); /* drives the FSM */ 13336415Ssklower 13436415Ssklower /* 13536415Ssklower * Update real-time timeout queue. 13636415Ssklower * At front of queue are some number of events which are ``due''. 13736415Ssklower * The time to these is <= 0 and if negative represents the 13836415Ssklower * number of ticks which have passed since it was supposed to happen. 13936415Ssklower * The rest of the q elements (times > 0) are events yet to happen, 14036415Ssklower * where the time for each is given as a delta from the previous. 14136415Ssklower * Decrementing just the first of these serves to decrement the time 14236415Ssklower * to all events. 14336415Ssklower * 14436415Ssklower * This version, which calls the driver directly, doesn't pass 14536415Ssklower * along the ticks - may want to add the ticks if there's any use 14636415Ssklower * for them. 14736415Ssklower */ 14836415Ssklower IncStat(ts_Eticks); 14936415Ssklower p1 = refp->tpr_calltodo.c_next; 15036415Ssklower while (p1) { 15136415Ssklower if (--p1->c_time > 0) 15236415Ssklower break; 15336415Ssklower if (p1->c_time == 0) 15436415Ssklower break; 15536415Ssklower p1 = p1->c_next; 15636415Ssklower } 15736415Ssklower 15836415Ssklower for (;;) { 15937469Ssklower struct tp_pcb *tpcb; 16036415Ssklower if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) { 16136415Ssklower break; 16236415Ssklower } 16336415Ssklower refp->tpr_calltodo.c_next = p1->c_next; 16436415Ssklower p1->c_next = TP_callfree; 16536415Ssklower 16636415Ssklower #ifndef lint 16736415Ssklower E.ev_number = p1->c_func; 16836415Ssklower E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1; 16936415Ssklower E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2; 17036415Ssklower E.ATTR(TM_data_retrans).e_retrans = p1->c_arg3; 17136415Ssklower #endif lint 17236415Ssklower IFDEBUG(D_TIMER) 17336415Ssklower printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n", 17436415Ssklower p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb, 17536415Ssklower refp-tp_ref); 17636415Ssklower ENDDEBUG 17736415Ssklower 17836415Ssklower TP_callfree = p1; 17936415Ssklower IncStat(ts_Eexpired); 18037469Ssklower (void) tp_driver( tpcb = refp->tpr_pcb, &E); 18137469Ssklower if (p1->c_func == TM_reference && tpcb->tp_state == TP_CLOSED) 18237469Ssklower free((caddr_t)tpcb, M_PCB); /* XXX wart; where else to do it? */ 18336415Ssklower } 18436415Ssklower } 18536415Ssklower 18636415Ssklower /* 18736415Ssklower * CALLED FROM: 18836415Ssklower * tp.trans all over 18936415Ssklower * FUNCTION and ARGUMENTS: 19036415Ssklower * Set an E type timer. (refp) is the ref structure. 19136415Ssklower * Causes fun(arg1,arg2,arg3) to be called after time t. 19236415Ssklower */ 19336415Ssklower void 19436415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks) 19536415Ssklower struct tp_ref *refp; 19636415Ssklower int fun; /* function to be called */ 19736415Ssklower u_int arg1, arg2; 19836415Ssklower int arg3; 19936415Ssklower register int ticks; 20036415Ssklower { 20136415Ssklower register struct Ecallout *p1, *p2, *pnew; 20236415Ssklower /* p1 and p2 drift through the list of timeout callout structures, 20336415Ssklower * pnew points to the newly created callout structure 20436415Ssklower */ 20536415Ssklower 20636415Ssklower IFDEBUG(D_TIMER) 20736415Ssklower printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb, 20836415Ssklower refp->tpr_pcb->tp_state); 20936415Ssklower ENDDEBUG 21036415Ssklower IFTRACE(D_TIMER) 21136415Ssklower tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref, 21236415Ssklower refp->tpr_state, ticks, tp_stat.ts_Eticks); 21336415Ssklower ENDTRACE 21436415Ssklower 21536415Ssklower IncStat(ts_Eset); 21636415Ssklower if (ticks == 0) 21736415Ssklower ticks = 1; 21836415Ssklower pnew = TP_callfree; 21936415Ssklower if (pnew == (struct Ecallout *)0) 22036415Ssklower panic("tp timeout table overflow"); 22136415Ssklower TP_callfree = pnew->c_next; 22236415Ssklower pnew->c_arg1 = arg1; 22336415Ssklower pnew->c_arg2 = arg2; 22436415Ssklower pnew->c_arg3 = arg3; 22536415Ssklower pnew->c_func = fun; 22636415Ssklower for (p1 = &(refp->tpr_calltodo); 22736415Ssklower (p2 = p1->c_next) && p2->c_time < ticks; p1 = p2) 22836415Ssklower if (p2->c_time > 0) 22936415Ssklower ticks -= p2->c_time; 23036415Ssklower p1->c_next = pnew; 23136415Ssklower pnew->c_next = p2; 23236415Ssklower pnew->c_time = ticks; 23336415Ssklower if (p2) 23436415Ssklower p2->c_time -= ticks; 23536415Ssklower } 23636415Ssklower 23736415Ssklower /* 23836415Ssklower * CALLED FROM: 23936415Ssklower * tp.trans all over 24036415Ssklower * FUNCTION and ARGUMENTS: 24136415Ssklower * Cancel all occurrences of E-timer function (fun) for reference (refp) 24236415Ssklower */ 24336415Ssklower void 24436415Ssklower tp_euntimeout(refp, fun) 24536415Ssklower struct tp_ref *refp; 24636415Ssklower int fun; 24736415Ssklower { 24836415Ssklower register struct Ecallout *p1, *p2; /* ptrs to drift through the list */ 24936415Ssklower 25036415Ssklower IFTRACE(D_TIMER) 25136415Ssklower tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0); 25236415Ssklower ENDTRACE 25336415Ssklower 25436415Ssklower p1 = &refp->tpr_calltodo; 25536415Ssklower while ( (p2 = p1->c_next) != 0) { 25636415Ssklower if (p2->c_func == fun) { 25736415Ssklower if (p2->c_next && p2->c_time > 0) 25836415Ssklower p2->c_next->c_time += p2->c_time; 25936415Ssklower p1->c_next = p2->c_next; 26036415Ssklower p2->c_next = TP_callfree; 26136415Ssklower TP_callfree = p2; 26236415Ssklower IncStat(ts_Ecan_act); 26336415Ssklower continue; 26436415Ssklower } 26536415Ssklower p1 = p2; 26636415Ssklower } 26736415Ssklower } 26836415Ssklower 26936415Ssklower /* 27036415Ssklower * CALLED FROM: 27136415Ssklower * tp.trans, when an incoming ACK causes things to be dropped 27236415Ssklower * from the retransmission queue, and we want their associated 27336415Ssklower * timers to be cancelled. 27436415Ssklower * FUNCTION and ARGUMENTS: 27536415Ssklower * cancel all occurrences of function (fun) where (arg2) < (seq) 27636415Ssklower */ 27736415Ssklower void 27836415Ssklower tp_euntimeout_lss(refp, fun, seq) 27936415Ssklower struct tp_ref *refp; 28036415Ssklower int fun; 28136415Ssklower SeqNum seq; 28236415Ssklower { 28336415Ssklower register struct Ecallout *p1, *p2; 28436415Ssklower 28536415Ssklower IFTRACE(D_TIMER) 28636415Ssklower tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0); 28736415Ssklower ENDTRACE 28836415Ssklower 28936415Ssklower p1 = &refp->tpr_calltodo; 29036415Ssklower while ( (p2 = p1->c_next) != 0) { 29136415Ssklower if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq)) { 29236415Ssklower if (p2->c_next && p2->c_time > 0) 29336415Ssklower p2->c_next->c_time += p2->c_time; 29436415Ssklower p1->c_next = p2->c_next; 29536415Ssklower p2->c_next = TP_callfree; 29636415Ssklower TP_callfree = p2; 29736415Ssklower IncStat(ts_Ecan_act); 29836415Ssklower continue; 29936415Ssklower } 30036415Ssklower p1 = p2; 30136415Ssklower } 30236415Ssklower } 30336415Ssklower 30436415Ssklower /**************** c timers ********************** 30536415Ssklower * 30636415Ssklower * These are not chained together; they sit 30736415Ssklower * in the tp_ref structure. they are the kind that 30836415Ssklower * are typically cancelled so it's faster not to 30936415Ssklower * mess with the chains 31036415Ssklower */ 31136415Ssklower 31236415Ssklower /* 31336415Ssklower * CALLED FROM: 31436415Ssklower * the clock, every 500 ms 31536415Ssklower * FUNCTION and ARGUMENTS: 31636415Ssklower * Look for open references with active timers. 31736415Ssklower * If they exist, call the appropriate timer routines to update 31836415Ssklower * the timers and possibly generate events. 31936415Ssklower * (The E timers are done in other procedures; the C timers are 32036415Ssklower * updated here, and events for them are generated here.) 32136415Ssklower */ 32236415Ssklower ProtoHook 32336415Ssklower tp_slowtimo() 32436415Ssklower { 32536415Ssklower register int r,t; 32636415Ssklower struct Ccallout *cp; 32736415Ssklower struct tp_ref *rp = tp_ref; 32836415Ssklower struct tp_event E; 32936415Ssklower int s = splnet(); 33036415Ssklower 33136415Ssklower /* check only open reference structures */ 33236415Ssklower IncStat(ts_Cticks); 33336415Ssklower rp++; /* tp_ref[0] is never used */ 33436415Ssklower for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) { 33536415Ssklower if (rp->tpr_state < REF_OPEN) 33636415Ssklower continue; 33736415Ssklower 33836415Ssklower /* check the C-type timers */ 33936415Ssklower cp = rp->tpr_callout; 34036415Ssklower for (t=0 ; t < N_CTIMERS; t++,cp++) { 34136415Ssklower if( cp->c_active ) { 34236415Ssklower if( --cp->c_time <= 0 ) { 34336415Ssklower cp->c_active = FALSE; 34436415Ssklower E.ev_number = t; 34536415Ssklower IFDEBUG(D_TIMER) 34636415Ssklower printf("C expired! type 0x%x\n", t); 34736415Ssklower ENDDEBUG 34836415Ssklower IncStat(ts_Cexpired); 34936415Ssklower tp_driver( rp->tpr_pcb, &E); 35036415Ssklower } 35136415Ssklower } 35236415Ssklower } 35336415Ssklower /* now update the list */ 35436415Ssklower tp_Eclock(rp); 35536415Ssklower } 35636415Ssklower splx(s); 35736415Ssklower return 0; 35836415Ssklower } 35936415Ssklower 36036415Ssklower /* 36136415Ssklower * CALLED FROM: 36236415Ssklower * tp.trans, tp_emit() 36336415Ssklower * FUNCTION and ARGUMENTS: 36436415Ssklower * Set a C type timer of type (which) to go off after (ticks) time. 36536415Ssklower */ 36636415Ssklower void 36736415Ssklower tp_ctimeout(refp, which, ticks) 36836415Ssklower register struct tp_ref *refp; 36936415Ssklower int which, ticks; 37036415Ssklower { 37136415Ssklower register struct Ccallout *cp = &(refp->tpr_callout[which]); 37236415Ssklower 37336415Ssklower IFTRACE(D_TIMER) 37436415Ssklower tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", 37536415Ssklower (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active); 37636415Ssklower ENDTRACE 37736415Ssklower if(cp->c_active) 37836415Ssklower IncStat(ts_Ccan_act); 37936415Ssklower IncStat(ts_Cset); 38036415Ssklower cp->c_time = ticks; 38136415Ssklower cp->c_active = TRUE; 38236415Ssklower } 38336415Ssklower 38436415Ssklower /* 38536415Ssklower * CALLED FROM: 38636415Ssklower * tp.trans 38736415Ssklower * FUNCTION and ARGUMENTS: 38836415Ssklower * Version of tp_ctimeout that resets the C-type time if the 38936415Ssklower * parameter (ticks) is > the current value of the timer. 39036415Ssklower */ 39136415Ssklower void 39236415Ssklower tp_ctimeout_MIN(refp, which, ticks) 39336415Ssklower register struct tp_ref *refp; 39436415Ssklower int which, ticks; 39536415Ssklower { 39636415Ssklower register struct Ccallout *cp = &(refp->tpr_callout[which]); 39736415Ssklower 39836415Ssklower IFTRACE(D_TIMER) 39936415Ssklower tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", 40036415Ssklower (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active); 40136415Ssklower ENDTRACE 40236415Ssklower if(cp->c_active) 40336415Ssklower IncStat(ts_Ccan_act); 40436415Ssklower IncStat(ts_Cset); 40536415Ssklower if( cp->c_active ) 40636415Ssklower cp->c_time = MIN(ticks, cp->c_time); 40736415Ssklower else { 40836415Ssklower cp->c_time = ticks; 40936415Ssklower cp->c_active = TRUE; 41036415Ssklower } 41136415Ssklower } 41236415Ssklower 41336415Ssklower /* 41436415Ssklower * CALLED FROM: 41536415Ssklower * tp.trans 41636415Ssklower * FUNCTION and ARGUMENTS: 41736415Ssklower * Cancel the (which) timer in the ref structure indicated by (refp). 41836415Ssklower */ 41936415Ssklower void 42036415Ssklower tp_cuntimeout(refp, which) 42136415Ssklower int which; 42236415Ssklower register struct tp_ref *refp; 42336415Ssklower { 42436415Ssklower register struct Ccallout *cp; 42536415Ssklower 42636415Ssklower cp = &(refp->tpr_callout[which]); 42736415Ssklower 42836415Ssklower IFDEBUG(D_TIMER) 42937469Ssklower printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_active); 43036415Ssklower ENDDEBUG 43136415Ssklower 43236415Ssklower IFTRACE(D_TIMER) 43336415Ssklower tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, 43436415Ssklower which, cp->c_active, 0); 43536415Ssklower ENDTRACE 43636415Ssklower 43736415Ssklower if(cp->c_active) 43836415Ssklower IncStat(ts_Ccan_act); 43936415Ssklower else 44036415Ssklower IncStat(ts_Ccan_inact); 44136415Ssklower cp->c_active = FALSE; 44236415Ssklower } 443