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