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