1*36415Ssklower /*********************************************************** 2*36415Ssklower Copyright IBM Corporation 1987 3*36415Ssklower 4*36415Ssklower All Rights Reserved 5*36415Ssklower 6*36415Ssklower Permission to use, copy, modify, and distribute this software and its 7*36415Ssklower documentation for any purpose and without fee is hereby granted, 8*36415Ssklower provided that the above copyright notice appear in all copies and that 9*36415Ssklower both that copyright notice and this permission notice appear in 10*36415Ssklower supporting documentation, and that the name of IBM not be 11*36415Ssklower used in advertising or publicity pertaining to distribution of the 12*36415Ssklower software without specific, written prior permission. 13*36415Ssklower 14*36415Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 15*36415Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 16*36415Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 17*36415Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 18*36415Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 19*36415Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 20*36415Ssklower SOFTWARE. 21*36415Ssklower 22*36415Ssklower ******************************************************************/ 23*36415Ssklower 24*36415Ssklower /* 25*36415Ssklower * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison 26*36415Ssklower */ 27*36415Ssklower /* 28*36415Ssklower * ARGO TP 29*36415Ssklower * 30*36415Ssklower * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $ 31*36415Ssklower * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $ 32*36415Ssklower * 33*36415Ssklower * Contains all the timer code. 34*36415Ssklower * There are two sources of calls to these routines: 35*36415Ssklower * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time) 36*36415Ssklower * 37*36415Ssklower * Timers come in two flavors - those that generally get 38*36415Ssklower * cancelled (tp_ctimeout, tp_cuntimeout) 39*36415Ssklower * and those that either usually expire (tp_etimeout, 40*36415Ssklower * tp_euntimeout, tp_slowtimo) or may require more than one instance 41*36415Ssklower * of the timer active at a time. 42*36415Ssklower * 43*36415Ssklower * The C timers are stored in the tp_ref structure. Their "going off" 44*36415Ssklower * is manifested by a driver event of the TM_xxx form. 45*36415Ssklower * 46*36415Ssklower * The E timers are handled like the generic kernel callouts. 47*36415Ssklower * Their "going off" is manifested by a function call w/ 3 arguments. 48*36415Ssklower */ 49*36415Ssklower 50*36415Ssklower #ifndef lint 51*36415Ssklower static char *rcsid = "$Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $"; 52*36415Ssklower #endif lint 53*36415Ssklower 54*36415Ssklower #include "param.h" 55*36415Ssklower #include "types.h" 56*36415Ssklower #include "time.h" 57*36415Ssklower 58*36415Ssklower #include "../netiso/tp_param.h" 59*36415Ssklower #include "../netiso/tp_timer.h" 60*36415Ssklower #include "../netiso/tp_stat.h" 61*36415Ssklower #include "../netiso/tp_pcb.h" 62*36415Ssklower #include "../netiso/tp_tpdu.h" 63*36415Ssklower #include "../netiso/argo_debug.h" 64*36415Ssklower #include "../netiso/tp_trace.h" 65*36415Ssklower #include "../netiso/tp_seq.h" 66*36415Ssklower 67*36415Ssklower static struct Ecallout *TP_callfree; 68*36415Ssklower static struct Ecallout TP_callout[N_TPREF*2]; 69*36415Ssklower 70*36415Ssklower extern int tp_maxrefopen; /* highest ref # of an open tp connection */ 71*36415Ssklower 72*36415Ssklower /* 73*36415Ssklower * CALLED FROM: 74*36415Ssklower * at autoconfig time from tp_init() 75*36415Ssklower * a combo of event, state, predicate 76*36415Ssklower * FUNCTION and ARGUMENTS: 77*36415Ssklower * initialize data structures for the timers 78*36415Ssklower */ 79*36415Ssklower void 80*36415Ssklower tp_timerinit() 81*36415Ssklower { 82*36415Ssklower register int i; 83*36415Ssklower /* 84*36415Ssklower * Initialize callouts 85*36415Ssklower */ 86*36415Ssklower TP_callfree = TP_callout; 87*36415Ssklower for (i = 1; i < N_TPREF*2; i++) 88*36415Ssklower TP_callout[i-1].c_next = &TP_callout[i]; 89*36415Ssklower 90*36415Ssklower bzero( (caddr_t)tp_ref, N_TPREF * sizeof(struct tp_ref) ); 91*36415Ssklower 92*36415Ssklower /* hate to do this but we really don't want zero to be a legit ref */ 93*36415Ssklower tp_maxrefopen = 1; 94*36415Ssklower tp_ref[0].tpr_state = REF_FROZEN; /* white lie -- no ref timer, don't 95*36415Ssklower * want this one to be allocated- ever 96*36415Ssklower * unless, of course, you make refs and address instead of an 97*36415Ssklower * index - then 0 can be allocated 98*36415Ssklower */ 99*36415Ssklower 100*36415Ssklower } 101*36415Ssklower 102*36415Ssklower /********************** e timers *************************/ 103*36415Ssklower 104*36415Ssklower /* 105*36415Ssklower * CALLED FROM: 106*36415Ssklower * tp_slowtimo() every 1/2 second, for each open reference 107*36415Ssklower * FUNCTION and ARGUMENTS: 108*36415Ssklower * (refp) indicates a reference structure that is in use. 109*36415Ssklower * This ref structure may contain active E-type timers. 110*36415Ssklower * Update the timers and if any expire, create an event and 111*36415Ssklower * call the driver. 112*36415Ssklower */ 113*36415Ssklower static void 114*36415Ssklower tp_Eclock(refp) 115*36415Ssklower struct tp_ref *refp; /* the reference structure */ 116*36415Ssklower { 117*36415Ssklower register struct Ecallout *p1; /* to drift through the list of callouts */ 118*36415Ssklower struct tp_event E; /* event to pass to tp_driver() */ 119*36415Ssklower int tp_driver(); /* drives the FSM */ 120*36415Ssklower 121*36415Ssklower /* 122*36415Ssklower * Update real-time timeout queue. 123*36415Ssklower * At front of queue are some number of events which are ``due''. 124*36415Ssklower * The time to these is <= 0 and if negative represents the 125*36415Ssklower * number of ticks which have passed since it was supposed to happen. 126*36415Ssklower * The rest of the q elements (times > 0) are events yet to happen, 127*36415Ssklower * where the time for each is given as a delta from the previous. 128*36415Ssklower * Decrementing just the first of these serves to decrement the time 129*36415Ssklower * to all events. 130*36415Ssklower * 131*36415Ssklower * This version, which calls the driver directly, doesn't pass 132*36415Ssklower * along the ticks - may want to add the ticks if there's any use 133*36415Ssklower * for them. 134*36415Ssklower */ 135*36415Ssklower IncStat(ts_Eticks); 136*36415Ssklower p1 = refp->tpr_calltodo.c_next; 137*36415Ssklower while (p1) { 138*36415Ssklower if (--p1->c_time > 0) 139*36415Ssklower break; 140*36415Ssklower if (p1->c_time == 0) 141*36415Ssklower break; 142*36415Ssklower p1 = p1->c_next; 143*36415Ssklower } 144*36415Ssklower 145*36415Ssklower for (;;) { 146*36415Ssklower if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) { 147*36415Ssklower break; 148*36415Ssklower } 149*36415Ssklower refp->tpr_calltodo.c_next = p1->c_next; 150*36415Ssklower p1->c_next = TP_callfree; 151*36415Ssklower 152*36415Ssklower #ifndef lint 153*36415Ssklower E.ev_number = p1->c_func; 154*36415Ssklower E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1; 155*36415Ssklower E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2; 156*36415Ssklower E.ATTR(TM_data_retrans).e_retrans = p1->c_arg3; 157*36415Ssklower #endif lint 158*36415Ssklower IFDEBUG(D_TIMER) 159*36415Ssklower printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n", 160*36415Ssklower p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb, 161*36415Ssklower refp-tp_ref); 162*36415Ssklower ENDDEBUG 163*36415Ssklower 164*36415Ssklower TP_callfree = p1; 165*36415Ssklower IncStat(ts_Eexpired); 166*36415Ssklower (void) tp_driver( refp->tpr_pcb, &E); 167*36415Ssklower } 168*36415Ssklower } 169*36415Ssklower 170*36415Ssklower /* 171*36415Ssklower * CALLED FROM: 172*36415Ssklower * tp.trans all over 173*36415Ssklower * FUNCTION and ARGUMENTS: 174*36415Ssklower * Set an E type timer. (refp) is the ref structure. 175*36415Ssklower * Causes fun(arg1,arg2,arg3) to be called after time t. 176*36415Ssklower */ 177*36415Ssklower void 178*36415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks) 179*36415Ssklower struct tp_ref *refp; 180*36415Ssklower int fun; /* function to be called */ 181*36415Ssklower u_int arg1, arg2; 182*36415Ssklower int arg3; 183*36415Ssklower register int ticks; 184*36415Ssklower { 185*36415Ssklower register struct Ecallout *p1, *p2, *pnew; 186*36415Ssklower /* p1 and p2 drift through the list of timeout callout structures, 187*36415Ssklower * pnew points to the newly created callout structure 188*36415Ssklower */ 189*36415Ssklower 190*36415Ssklower IFDEBUG(D_TIMER) 191*36415Ssklower printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb, 192*36415Ssklower refp->tpr_pcb->tp_state); 193*36415Ssklower ENDDEBUG 194*36415Ssklower IFTRACE(D_TIMER) 195*36415Ssklower tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref, 196*36415Ssklower refp->tpr_state, ticks, tp_stat.ts_Eticks); 197*36415Ssklower ENDTRACE 198*36415Ssklower 199*36415Ssklower IncStat(ts_Eset); 200*36415Ssklower if (ticks == 0) 201*36415Ssklower ticks = 1; 202*36415Ssklower pnew = TP_callfree; 203*36415Ssklower if (pnew == (struct Ecallout *)0) 204*36415Ssklower panic("tp timeout table overflow"); 205*36415Ssklower TP_callfree = pnew->c_next; 206*36415Ssklower pnew->c_arg1 = arg1; 207*36415Ssklower pnew->c_arg2 = arg2; 208*36415Ssklower pnew->c_arg3 = arg3; 209*36415Ssklower pnew->c_func = fun; 210*36415Ssklower for (p1 = &(refp->tpr_calltodo); 211*36415Ssklower (p2 = p1->c_next) && p2->c_time < ticks; p1 = p2) 212*36415Ssklower if (p2->c_time > 0) 213*36415Ssklower ticks -= p2->c_time; 214*36415Ssklower p1->c_next = pnew; 215*36415Ssklower pnew->c_next = p2; 216*36415Ssklower pnew->c_time = ticks; 217*36415Ssklower if (p2) 218*36415Ssklower p2->c_time -= ticks; 219*36415Ssklower } 220*36415Ssklower 221*36415Ssklower /* 222*36415Ssklower * CALLED FROM: 223*36415Ssklower * tp.trans all over 224*36415Ssklower * FUNCTION and ARGUMENTS: 225*36415Ssklower * Cancel all occurrences of E-timer function (fun) for reference (refp) 226*36415Ssklower */ 227*36415Ssklower void 228*36415Ssklower tp_euntimeout(refp, fun) 229*36415Ssklower struct tp_ref *refp; 230*36415Ssklower int fun; 231*36415Ssklower { 232*36415Ssklower register struct Ecallout *p1, *p2; /* ptrs to drift through the list */ 233*36415Ssklower 234*36415Ssklower IFTRACE(D_TIMER) 235*36415Ssklower tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0); 236*36415Ssklower ENDTRACE 237*36415Ssklower 238*36415Ssklower p1 = &refp->tpr_calltodo; 239*36415Ssklower while ( (p2 = p1->c_next) != 0) { 240*36415Ssklower if (p2->c_func == fun) { 241*36415Ssklower if (p2->c_next && p2->c_time > 0) 242*36415Ssklower p2->c_next->c_time += p2->c_time; 243*36415Ssklower p1->c_next = p2->c_next; 244*36415Ssklower p2->c_next = TP_callfree; 245*36415Ssklower TP_callfree = p2; 246*36415Ssklower IncStat(ts_Ecan_act); 247*36415Ssklower continue; 248*36415Ssklower } 249*36415Ssklower p1 = p2; 250*36415Ssklower } 251*36415Ssklower } 252*36415Ssklower 253*36415Ssklower /* 254*36415Ssklower * CALLED FROM: 255*36415Ssklower * tp.trans, when an incoming ACK causes things to be dropped 256*36415Ssklower * from the retransmission queue, and we want their associated 257*36415Ssklower * timers to be cancelled. 258*36415Ssklower * FUNCTION and ARGUMENTS: 259*36415Ssklower * cancel all occurrences of function (fun) where (arg2) < (seq) 260*36415Ssklower */ 261*36415Ssklower void 262*36415Ssklower tp_euntimeout_lss(refp, fun, seq) 263*36415Ssklower struct tp_ref *refp; 264*36415Ssklower int fun; 265*36415Ssklower SeqNum seq; 266*36415Ssklower { 267*36415Ssklower register struct Ecallout *p1, *p2; 268*36415Ssklower 269*36415Ssklower IFTRACE(D_TIMER) 270*36415Ssklower tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0); 271*36415Ssklower ENDTRACE 272*36415Ssklower 273*36415Ssklower p1 = &refp->tpr_calltodo; 274*36415Ssklower while ( (p2 = p1->c_next) != 0) { 275*36415Ssklower if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq)) { 276*36415Ssklower if (p2->c_next && p2->c_time > 0) 277*36415Ssklower p2->c_next->c_time += p2->c_time; 278*36415Ssklower p1->c_next = p2->c_next; 279*36415Ssklower p2->c_next = TP_callfree; 280*36415Ssklower TP_callfree = p2; 281*36415Ssklower IncStat(ts_Ecan_act); 282*36415Ssklower continue; 283*36415Ssklower } 284*36415Ssklower p1 = p2; 285*36415Ssklower } 286*36415Ssklower } 287*36415Ssklower 288*36415Ssklower /**************** c timers ********************** 289*36415Ssklower * 290*36415Ssklower * These are not chained together; they sit 291*36415Ssklower * in the tp_ref structure. they are the kind that 292*36415Ssklower * are typically cancelled so it's faster not to 293*36415Ssklower * mess with the chains 294*36415Ssklower */ 295*36415Ssklower 296*36415Ssklower /* 297*36415Ssklower * CALLED FROM: 298*36415Ssklower * the clock, every 500 ms 299*36415Ssklower * FUNCTION and ARGUMENTS: 300*36415Ssklower * Look for open references with active timers. 301*36415Ssklower * If they exist, call the appropriate timer routines to update 302*36415Ssklower * the timers and possibly generate events. 303*36415Ssklower * (The E timers are done in other procedures; the C timers are 304*36415Ssklower * updated here, and events for them are generated here.) 305*36415Ssklower */ 306*36415Ssklower ProtoHook 307*36415Ssklower tp_slowtimo() 308*36415Ssklower { 309*36415Ssklower register int r,t; 310*36415Ssklower struct Ccallout *cp; 311*36415Ssklower struct tp_ref *rp = tp_ref; 312*36415Ssklower struct tp_event E; 313*36415Ssklower int s = splnet(); 314*36415Ssklower 315*36415Ssklower /* check only open reference structures */ 316*36415Ssklower IncStat(ts_Cticks); 317*36415Ssklower rp++; /* tp_ref[0] is never used */ 318*36415Ssklower for( r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) { 319*36415Ssklower if (rp->tpr_state < REF_OPEN) 320*36415Ssklower continue; 321*36415Ssklower 322*36415Ssklower /* check the C-type timers */ 323*36415Ssklower cp = rp->tpr_callout; 324*36415Ssklower for (t=0 ; t < N_CTIMERS; t++,cp++) { 325*36415Ssklower if( cp->c_active ) { 326*36415Ssklower if( --cp->c_time <= 0 ) { 327*36415Ssklower cp->c_active = FALSE; 328*36415Ssklower E.ev_number = t; 329*36415Ssklower IFDEBUG(D_TIMER) 330*36415Ssklower printf("C expired! type 0x%x\n", t); 331*36415Ssklower ENDDEBUG 332*36415Ssklower IncStat(ts_Cexpired); 333*36415Ssklower tp_driver( rp->tpr_pcb, &E); 334*36415Ssklower } 335*36415Ssklower } 336*36415Ssklower } 337*36415Ssklower /* now update the list */ 338*36415Ssklower tp_Eclock(rp); 339*36415Ssklower } 340*36415Ssklower splx(s); 341*36415Ssklower return 0; 342*36415Ssklower } 343*36415Ssklower 344*36415Ssklower /* 345*36415Ssklower * CALLED FROM: 346*36415Ssklower * tp.trans, tp_emit() 347*36415Ssklower * FUNCTION and ARGUMENTS: 348*36415Ssklower * Set a C type timer of type (which) to go off after (ticks) time. 349*36415Ssklower */ 350*36415Ssklower void 351*36415Ssklower tp_ctimeout(refp, which, ticks) 352*36415Ssklower register struct tp_ref *refp; 353*36415Ssklower int which, ticks; 354*36415Ssklower { 355*36415Ssklower register struct Ccallout *cp = &(refp->tpr_callout[which]); 356*36415Ssklower 357*36415Ssklower IFTRACE(D_TIMER) 358*36415Ssklower tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active", 359*36415Ssklower (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active); 360*36415Ssklower ENDTRACE 361*36415Ssklower if(cp->c_active) 362*36415Ssklower IncStat(ts_Ccan_act); 363*36415Ssklower IncStat(ts_Cset); 364*36415Ssklower cp->c_time = ticks; 365*36415Ssklower cp->c_active = TRUE; 366*36415Ssklower } 367*36415Ssklower 368*36415Ssklower /* 369*36415Ssklower * CALLED FROM: 370*36415Ssklower * tp.trans 371*36415Ssklower * FUNCTION and ARGUMENTS: 372*36415Ssklower * Version of tp_ctimeout that resets the C-type time if the 373*36415Ssklower * parameter (ticks) is > the current value of the timer. 374*36415Ssklower */ 375*36415Ssklower void 376*36415Ssklower tp_ctimeout_MIN(refp, which, ticks) 377*36415Ssklower register struct tp_ref *refp; 378*36415Ssklower int which, ticks; 379*36415Ssklower { 380*36415Ssklower register struct Ccallout *cp = &(refp->tpr_callout[which]); 381*36415Ssklower 382*36415Ssklower IFTRACE(D_TIMER) 383*36415Ssklower tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active", 384*36415Ssklower (int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active); 385*36415Ssklower ENDTRACE 386*36415Ssklower if(cp->c_active) 387*36415Ssklower IncStat(ts_Ccan_act); 388*36415Ssklower IncStat(ts_Cset); 389*36415Ssklower if( cp->c_active ) 390*36415Ssklower cp->c_time = MIN(ticks, cp->c_time); 391*36415Ssklower else { 392*36415Ssklower cp->c_time = ticks; 393*36415Ssklower cp->c_active = TRUE; 394*36415Ssklower } 395*36415Ssklower } 396*36415Ssklower 397*36415Ssklower /* 398*36415Ssklower * CALLED FROM: 399*36415Ssklower * tp.trans 400*36415Ssklower * FUNCTION and ARGUMENTS: 401*36415Ssklower * Cancel the (which) timer in the ref structure indicated by (refp). 402*36415Ssklower */ 403*36415Ssklower void 404*36415Ssklower tp_cuntimeout(refp, which) 405*36415Ssklower int which; 406*36415Ssklower register struct tp_ref *refp; 407*36415Ssklower { 408*36415Ssklower register struct Ccallout *cp; 409*36415Ssklower 410*36415Ssklower cp = &(refp->tpr_callout[which]); 411*36415Ssklower 412*36415Ssklower IFDEBUG(D_TIMER) 413*36415Ssklower printf("tp_cuntimeout(0x%x, %d) active\n", refp, which, cp->c_active); 414*36415Ssklower ENDDEBUG 415*36415Ssklower 416*36415Ssklower IFTRACE(D_TIMER) 417*36415Ssklower tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref, 418*36415Ssklower which, cp->c_active, 0); 419*36415Ssklower ENDTRACE 420*36415Ssklower 421*36415Ssklower if(cp->c_active) 422*36415Ssklower IncStat(ts_Ccan_act); 423*36415Ssklower else 424*36415Ssklower IncStat(ts_Ccan_inact); 425*36415Ssklower cp->c_active = FALSE; 426*36415Ssklower } 427