Commit 483fb149 authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'kill-timers'

This patch-set rewrites the timers into much simpler timeouts.  Code
is smaller, binary is smaller, we have less arch-dependent functions
and so on.  Meanwhile I noticed and fixed some buglets that got
unexposed or unnoticed.
parents 805b7a8b 415e530e
......@@ -320,6 +320,14 @@ static int posix_open_ch(struct pp_instance *ppi, char *ifname, int chtype)
return -1;
}
/* forcibly disable loopback */
temp = 0;
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
&temp, sizeof(int)) < 0) {
pp_diag_error_str2(ppi, "IP_MULTICAST_LOOP", strerror(errno));
return -1;
}
/* make timestamps available through recvmsg() */
if (setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
&temp, sizeof(int)) < 0) {
......
......@@ -313,22 +313,42 @@ static inline void pp_timeout_set(struct pp_instance *ppi, int index,
ppi->timeouts[index] = pp_calc_timeout(millisec);
}
extern void pp_timeout_rand(struct pp_instance *ppi, int index, int logval);
static inline void pp_timeout_clr(struct pp_instance *ppi, int index)
{
ppi->timeouts[index] = 0;
}
extern void pp_timeout_log(struct pp_instance *ppi, int index);
static inline int pp_timeout(struct pp_instance *ppi, int index)
{
return ppi->timeouts[index] &&
int ret = ppi->timeouts[index] &&
time_after_eq(pp_calc_timeout(0), ppi->timeouts[index]);
if (ret && pp_verbose_time)
pp_timeout_log(ppi, index);
return ret;
}
static inline int pp_timeout_z(struct pp_instance *ppi, int index)
{
int ret = pp_timeout(ppi, index);
if (ret)
pp_timeout_clr(ppi, index);
return ret;
}
/* This functions are generic, not architecture-specific */
extern void pp_timeout_set(struct pp_instance *ppi, int index, int millisec);
extern void pp_timeout_clr(struct pp_instance *ppi, int index);
extern int pp_timeout(struct pp_instance *ppi, int index); /* 1 == timeout */
/* called several times, only sets a timeout, so inline it here */
static inline void pp_timeout_restart_annrec(struct pp_instance *ppi)
{
/* This timeout is a number of the announce interval lapses */
pp_timeout_set(ppi, PP_TO_ANN_RECEIPT,
((DSPOR(ppi)->announceReceiptTimeout) <<
DSPOR(ppi)->logAnnounceInterval) * 1000);
}
/* The channel for an instance must be created and possibly destroyed. */
......
......@@ -166,7 +166,12 @@ int pp_parse_cmdline(struct pp_instance *ppi, int argc, char **argv)
break;
case 'n':
a = argv[++i];
/* Page 237 says 0 to 4 (1s .. 16s) */
OPTS(ppi)->announce_intvl = atoi(a);
if (OPTS(ppi)->announce_intvl < 0)
OPTS(ppi)->announce_intvl = 0;
if (OPTS(ppi)->announce_intvl > 4)
OPTS(ppi)->announce_intvl = 4;
break;
case 'm':
a = argv[++i];
......
......@@ -17,17 +17,17 @@ int wr_calibrated(struct pp_instance *ppi, unsigned char *pkt, int plen)
WR_DSPOR(ppi)->wrStateTimeout);
}
if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
if (WR_DSPOR(ppi)->wrMode == WR_MASTER)
ppi->next_state = PPS_MASTER;
else
ppi->next_state = PPS_LISTENING;
WR_DSPOR(ppi)->wrPortState = WRS_IDLE;
goto state_updated;
goto out;
}
if (plen == 0)
goto ret;
goto out;
if (ppi->msg_tmp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, pkt, &wrsig_msg,
......@@ -41,11 +41,7 @@ int wr_calibrated(struct pp_instance *ppi, unsigned char *pkt, int plen)
ppi->next_state = WRS_WR_LINK_ON;
}
state_updated:
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_EXT_0);
ret:
out:
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
return 0;
}
......@@ -22,13 +22,13 @@ int wr_calibration(struct pp_instance *ppi, unsigned char *pkt, int plen)
WR_DSPOR(ppi)->wrPortState = WRS_CALIBRATION_2;
}
if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
if (WR_DSPOR(ppi)->wrMode == WR_MASTER)
ppi->next_state = PPS_MASTER;
else
ppi->next_state = PPS_LISTENING;
WR_DSPOR(ppi)->wrPortState = WRS_IDLE;
goto state_updated;
goto out;
}
switch (WR_DSPOR(ppi)->wrPortState) {
......@@ -125,10 +125,7 @@ int wr_calibration(struct pp_instance *ppi, unsigned char *pkt, int plen)
break;
}
state_updated:
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_EXT_0);
out:
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
return e;
......
......@@ -21,15 +21,15 @@ int wr_locked(struct pp_instance *ppi, unsigned char *pkt, int plen)
e = msg_issue_wrsig(ppi, LOCKED);
}
if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
ppi->next_state = PPS_LISTENING;
WR_DSPOR(ppi)->wrMode = NON_WR;
WR_DSPOR(ppi)->wrPortState = WRS_IDLE;
goto state_updated;
goto out;
}
if (plen == 0)
goto no_incoming_msg;
goto out;
if (ppi->msg_tmp_header.messageType == PPM_SIGNALING) {
......@@ -40,14 +40,9 @@ int wr_locked(struct pp_instance *ppi, unsigned char *pkt, int plen)
ppi->next_state = WRS_RESP_CALIB_REQ;
}
no_incoming_msg:
out:
if (e != 0)
ppi->next_state = PPS_FAULTY;
state_updated:
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_EXT_0);
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
return e;
......
......@@ -19,14 +19,14 @@ int wr_m_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
pp_timeout_set(ppi, PP_TO_EXT_0, WR_M_LOCK_TIMEOUT_MS);
}
if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
ppi->next_state = PPS_MASTER;
WR_DSPOR(ppi)->wrPortState = WRS_IDLE;
goto state_updated;
goto out;
}
if (plen == 0)
goto no_incoming_msg;
goto out;
if (ppi->msg_tmp_header.messageType == PPM_SIGNALING) {
......@@ -37,14 +37,9 @@ int wr_m_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
ppi->next_state = WRS_CALIBRATION;
}
no_incoming_msg:
out:
if (e != 0)
ppi->next_state = PPS_FAULTY;
state_updated:
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_EXT_0);
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
return e;
......
......@@ -23,15 +23,15 @@ int wr_present(struct pp_instance *ppi, unsigned char *pkt, int plen)
e = msg_issue_wrsig(ppi, SLAVE_PRESENT);
}
if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
ppi->next_state = PPS_LISTENING;
WR_DSPOR(ppi)->wrMode = NON_WR;
WR_DSPOR(ppi)->wrPortState = WRS_IDLE;
goto state_updated;
goto out;
}
if (plen == 0)
goto no_incoming_msg;
goto out;
if (ppi->msg_tmp_header.messageType == PPM_SIGNALING) {
......@@ -42,17 +42,14 @@ int wr_present(struct pp_instance *ppi, unsigned char *pkt, int plen)
ppi->next_state = WRS_S_LOCK;
}
no_incoming_msg:
out:
if (e == 0)
st_com_execute_slave(ppi, 0);
else
ppi->next_state = PPS_FAULTY;
state_updated:
if (ppi->next_state != ppi->state) {
pp_timeout_clr(ppi, PP_TO_EXT_0);
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_ANN_RECEIPT);
}
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
......
......@@ -23,17 +23,17 @@ int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen)
}
if ((WR_DSPOR(ppi)->otherNodeCalSendPattern) &&
(pp_timeout(ppi, PP_TO_EXT_0))) {
(pp_timeout_z(ppi, PP_TO_EXT_0))) {
if (WR_DSPOR(ppi)->wrMode == WR_MASTER)
ppi->next_state = PPS_MASTER;
else
ppi->next_state = PPS_LISTENING;
WR_DSPOR(ppi)->wrPortState = WRS_IDLE;
goto state_updated;
goto out;
}
if (plen == 0)
goto state_updated;
goto out;
if (ppi->msg_tmp_header.messageType == PPM_SIGNALING) {
......@@ -51,11 +51,7 @@ int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen)
}
}
state_updated:
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_EXT_0);
out:
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
return e;
}
......@@ -17,11 +17,11 @@ int wr_s_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
pp_timeout_set(ppi, PP_TO_EXT_0, WR_S_LOCK_TIMEOUT_MS);
}
if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
ppi->next_state = PPS_FAULTY;
WR_DSPOR(ppi)->wrPortState = WRS_IDLE;
WR_DSPOR(ppi)->wrMode = NON_WR;
goto state_updated;
goto out;
}
if (wr_locking_poll(ppi) == WR_SPLL_READY) {
......@@ -29,11 +29,7 @@ int wr_s_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
wr_locking_disable(ppi);
}
state_updated:
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_EXT_0);
out:
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
return e;
}
......@@ -23,6 +23,7 @@ OBJ-libstd := $D/fsm-table.o \
$D/arith.o \
$D/servo.o \
$D/hooks.o \
$D/timeout.o \
$D/open-close.o
$(TARGET).o: $(LIBSTD)
......
......@@ -18,8 +18,7 @@ int st_com_execute_slave(struct pp_instance *ppi, int check_delayreq)
if (ret < 0)
return ret;
if (pp_timeout(ppi, PP_TO_ANN_RECEIPT)) {
PP_VPRINTF("event ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES\n");
if (pp_timeout_z(ppi, PP_TO_ANN_RECEIPT)) {
ppi->number_foreign_records = 0;
ppi->foreign_record_i = 0;
if (!DSDEF(ppi)->slaveOnly &&
......@@ -28,17 +27,14 @@ int st_com_execute_slave(struct pp_instance *ppi, int check_delayreq)
ppi->next_state = PPS_MASTER;
} else {
ppi->next_state = PPS_LISTENING;
st_com_restart_annrec_timer(ppi);
pp_timeout_restart_annrec(ppi);
}
}
if (!check_delayreq)
return 0;
if (pp_timeout(ppi, PP_TO_DELAYREQ)) {
pp_timeout_clr(ppi, PP_TO_DELAYREQ);
PP_VPRINTF("event DELAYREQ_INTERVAL_TIMEOUT_EXPIRES\n");
if (pp_timeout_z(ppi, PP_TO_DELAYREQ)) {
ret = msg_issue_delay_req(ppi);
ppi->delay_req_send_time = ppi->last_snt_time;
......@@ -51,18 +47,7 @@ int st_com_execute_slave(struct pp_instance *ppi, int check_delayreq)
return ret;
}
void st_com_restart_annrec_timer(struct pp_instance *ppi)
{
/* 0 <= logAnnounceInterval <= 4, see pag. 237 of spec */
if (DSPOR(ppi)->logAnnounceInterval < 0)
PP_PRINTF("Error: logAnnounceInterval < 0");
pp_timeout_set(ppi, PP_TO_ANN_RECEIPT,
((DSPOR(ppi)->announceReceiptTimeout) <<
DSPOR(ppi)->logAnnounceInterval) * 1000);
}
/* Called by listening, master, passive, slave */
int st_com_check_record_update(struct pp_instance *ppi)
{
if (ppi->record_update) {
......@@ -165,7 +150,7 @@ int st_com_slave_handle_announce(struct pp_instance *ppi, unsigned char *buf,
}
/*Reset Timer handling Announce receipt timeout*/
st_com_restart_annrec_timer(ppi);
pp_timeout_restart_annrec(ppi);
if (pp_hooks.handle_announce)
pp_hooks.handle_announce(ppi);
......
......@@ -18,7 +18,7 @@ int pp_listening(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) {
DSPOR(ppi)->portState = PPS_LISTENING;
st_com_restart_annrec_timer(ppi);
pp_timeout_restart_annrec(ppi);
}
if (st_com_check_record_update(ppi))
......
......@@ -19,10 +19,9 @@ int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) {
DSPOR(ppi)->portState = PPS_MASTER;
pp_timeout_set(ppi, PP_TO_SYNC,
(1 << DSPOR(ppi)->logSyncInterval) * 1000);
pp_timeout_set(ppi, PP_TO_ANN_INTERVAL,
(1 << DSPOR(ppi)->logAnnounceInterval) * 1000);
pp_timeout_rand(ppi, PP_TO_SYNC, DSPOR(ppi)->logSyncInterval);
pp_timeout_rand(ppi, PP_TO_ANN_INTERVAL,
DSPOR(ppi)->logAnnounceInterval);
/* Send an announce immediately, when becomes master */
if (msg_issue_announce(ppi) < 0)
......@@ -32,8 +31,7 @@ int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (st_com_check_record_update(ppi))
goto state_updated;
if (pp_timeout(ppi, PP_TO_SYNC)) {
PP_VPRINTF("event SYNC_INTERVAL_TIMEOUT_EXPIRES\n");
if (pp_timeout_z(ppi, PP_TO_SYNC)) {
if (msg_issue_sync(ppi) < 0)
goto out;
......@@ -42,12 +40,18 @@ int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
&OPTS(ppi)->outbound_latency);
if (msg_issue_followup(ppi, time_snt))
goto out;
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_SYNC, DSPOR(ppi)->logSyncInterval);
}
if (pp_timeout(ppi, PP_TO_ANN_INTERVAL)) {
PP_VPRINTF("event ANNOUNCE_INTERVAL_TIMEOUT_EXPIRES\n");
if (pp_timeout_z(ppi, PP_TO_ANN_INTERVAL)) {
if (msg_issue_announce(ppi) < 0)
goto out;
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_ANN_INTERVAL,
DSPOR(ppi)->logAnnounceInterval);
}
if (plen == 0)
......
......@@ -13,7 +13,7 @@ int pp_passive(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) {
DSPOR(ppi)->portState = PPS_PASSIVE;
st_com_restart_annrec_timer(ppi);
pp_timeout_restart_annrec(ppi);
}
if (st_com_check_record_update(ppi))
......
......@@ -28,10 +28,10 @@ int pp_slave(struct pp_instance *ppi, unsigned char *pkt, int plen)
ppi->waiting_for_follow = FALSE;
st_com_restart_annrec_timer(ppi);
pp_timeout_restart_annrec(ppi);
pp_timeout_set(ppi, PP_TO_DELAYREQ,
(1 << DSPOR(ppi)->logMinDelayReqInterval) * 1000);
pp_timeout_rand(ppi, PP_TO_DELAYREQ,
DSPOR(ppi)->logMinDelayReqInterval);
}
if (st_com_check_record_update(ppi))
......
/*
* Alessandro Rubini for CERN, 2013 -- GNU LGPL v2.1 or later
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include <ppsi/diag-macros.h>
#define N(n) [n] = #n
static char *timeout_names[__PP_TO_ARRAY_SIZE] __attribute__((used)) = {
N(PP_TO_DELAYREQ),
N(PP_TO_SYNC),
N(PP_TO_ANN_RECEIPT),
N(PP_TO_ANN_INTERVAL),
N(PP_TO_EXT_0),
N(PP_TO_EXT_1),
N(PP_TO_EXT_2),
N(PP_TO_EXT_3),
};
/*
* Log means messages
*/
void pp_timeout_log(struct pp_instance *ppi, int index)
{
PP_VPRINTF("timeout expire event: %s\n", timeout_names[index]);
}
/*
* And "rand" means logarithm...
*
* Randomize a timeout. We are required to fit between 70% and 130%
* of the value for 90% of the time, at least. But making it "almost
* exact" is bad in a big network. So randomize between 80% and 120%:
* constant part is 80% and variable is 40%.
*/
void pp_timeout_rand(struct pp_instance *ppi, int index, int logval)
{
static uint32_t seed;
uint32_t rval;
int millisec;
if (!seed) {
uint32_t *p;
/* use the least 32 bits of the mac address as seed */
p = (void *)(DSDEF(ppi)->clockIdentity)
+ sizeof(ClockIdentity) - 4;
seed = *p;
}
/* From uclibc: they make 11 + 10 + 10 bits, we stop at 21 */
seed *= 1103515245;
seed += 12345;
rval = (unsigned int) (seed / 65536) % 2048;
seed *= 1103515245;
seed += 12345;
rval <<= 10;
rval ^= (unsigned int) (seed / 65536) % 1024;
millisec = (1 << logval) * 400; /* This is 40% of the nominal value */
millisec = (millisec * 2) + rval % millisec;
pp_timeout_set(ppi, index, millisec);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment