home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / netiso / tp_timer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-06  |  13.2 KB  |  469 lines

  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. }
  469.