V8/usr/sys/chaosld/chtimer.c

#include "ch.h"
#if NCH > 0
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/chaos.h"
#include "../chaosld/types.h"
#include "../chaosld/constants.h"
#include "../chaosld/globals.h"

/*
 * Clock level processing.
 *	ch_timer should be called each clock tick (HZ per second)
 *	at a priority equal to or higher than LOCK.
 *
 * Terminology:
 *    Packet aging:	Retransmitting packets that are not acked within
 *			AGERATE ticks
 *
 *    Probe:		The sending of a SNS packet if not all of the packets
 *			we have sent have been acknowledged
 *
 *    Responding:	Send a SNS every so often to see if the guy is still
 *			alive (after NRESPONDS we declare him dead)
 *
 *    RFC aging:	The retransmission of RFC packets
 *
 * These rates might want to vary with the cost of getting to the host.
 *
 * Since these rates are dependent on a run-time variable
 * (This is a good idea if you think about it long enough),
 * We might want to initialize specific variables at run-time to
 * avoid recalculation if the profile of chclock is disturbing.
 */
#define MINRATE     ORATE          /* Minimum of following rates */

#define AGERATE     (hz)           /* Re-xmit pkt if not rcptd in time */
#define PROBERATE   (hz<<3)        /* Send SNS to get STS for receipts or
                                        to make sure the conn. is alive */
#define ORATE       (hz>>1)        /* Xmit current (stream) output packet
                                        if not touched in this time */
#define TESTRATE    (hz*45)        /* Respond testing rate */
#define NRESPONDS   3              /* Test this many times before timing
                                        out the connection */
#define UPTIME      (NRESPONDS*TESTRATE)     /* Nothing in this time and
                                        the connection is flushed */
#define RFCTIME     (hz*15)        /* Time before giving up on  RFC */

extern int NChopen;


ch_timer()
{
     register struct connection *conn;
     register struct connection **connp;
     register struct packet *pkt;
     chtime inactive;
     int probing;                  /* are we probing this time ? */
     static chtime nextclk = 1;    /* next time to do anything */
     static chtime nextprobe = 1;  /* next time to probe */

     Chtimer = 1;
     ++Chclock;
     if (ch_busy)
          goto leave;
     if (cmp_le(Chclock, nextclk))
          goto leave;
     nextclk += MINRATE;
     if (cmp_gt(Chclock, nextprobe)) {
          probing = 1;
          nextprobe += PROBERATE;
     } else
          probing = 0;
     debug(DNOCLK,goto leave);

     for (connp = &Chconn[0]; connp < &Chconn[NCH]; connp++) {
          if ((conn = *connp) == NOCONN ||
		    (conn->cn_state != CSOPEN && conn->cn_state != CSRFCSENT))
               continue;
          if ((pkt = conn->cn_toutput) != NOPKT &&
		    (inactive = Chclock - pkt->time) >= ORATE &&
		    !chtfull(conn)) {
               conn->cn_toutput = NOPKT;
               (void)chld_write(conn, pkt);
          }
          if (conn->cn_thead != NOPKT)
               chretran(conn, AGERATE);
          if (probing) {
               inactive = Chclock - conn->cn_time;
               if (inactive >= (conn->cn_state == CSOPEN ? UPTIME : RFCTIME)) {
                    debug(DCONN|DABNOR,
                         printf("Conn #%x: Timeout\n", conn->cn_lidx.ci_tidx));
                    close_conn(conn, CSINCT, NOPKT);
               } else if (conn->cn_state == CSOPEN &&
			 (conn->cn_tacked != conn->cn_tlast ||
			  chtfull(conn) || inactive >= TESTRATE)) {
                    debug(DCONN, printf("Conn #%x: Probe: %D\n",
                                  conn->cn_lidx.ci_tidx, inactive));
                    sendsns(conn);
               }
          }
     }

leave:
     if (NChopen == 0)
	  Chtimer = 0;
     else
	  timeout(ch_timer, (caddr_t)0, 1);
}

chretran(conn, age)
struct connection *conn;
{
     register struct packet *pkt, **opkt;
     register struct packet *lastpkt;
     register chtime inactive;
     struct packet *firstpkt = NOPKT;

     ch_busy++;

     for (opkt = &conn->cn_thead; pkt = *opkt;) {
	  inactive = Chclock - pkt->time;
          if (inactive >= age) {
               if (firstpkt == NOPKT) 
                    firstpkt = pkt;
               else
                    lastpkt->next = pkt;
               lastpkt = pkt;
               *opkt = pkt->next;
               pkt->next = NOPKT;
               setack(conn, pkt);
          } else
               opkt = &pkt->next;
     }

     --ch_busy;

     if (firstpkt != NOPKT) {
          debug(DCONN|DABNOR,
               printf("Conn #%x: Rexmit (op:%d, pkn:%d)\n",
                    conn->cn_lidx.ci_tidx, firstpkt->pk_op,
                    firstpkt->pk_pkn));
          senddata(firstpkt);
     }
}

#endif