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