From 0dbdd9c2cd761363bf05e2681f2f81b484038835 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Fri, 1 Feb 2013 05:19:12 +0100 Subject: [PATCH] Stop handling file descriptor events after a port reset. If the port resets itself after detecting a fault, then the polling events for that port are no longer valid. This patch fixes a latent bug that would appear if a fault and another event were to happen simultaneously. Signed-off-by: Richard Cochran --- clock.c | 6 +++--- port.c | 7 ++++--- port.h | 4 +++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/clock.c b/clock.c index 5523297..e9449dc 100644 --- a/clock.c +++ b/clock.c @@ -692,7 +692,7 @@ struct PortIdentity clock_parent_identity(struct clock *c) int clock_poll(struct clock *c) { - int cnt, i, j, k, lost = 0, sde = 0; + int cnt, err, i, j, k, lost = 0, sde = 0; enum fsm_event event; cnt = poll(c->pollfd, ARRAY_SIZE(c->pollfd), -1); @@ -710,7 +710,7 @@ int clock_poll(struct clock *c) for (i = 0; i < c->nports; i++) { /* Let the ports handle their events. */ - for (j = 0; j < N_POLLFD; j++) { + for (j = err = 0; j < N_POLLFD && !err; j++) { k = N_CLOCK_PFD * i + j; if (c->pollfd[k].revents & (POLLIN|POLLPRI)) { event = port_event(c->port[i], j); @@ -718,7 +718,7 @@ int clock_poll(struct clock *c) sde = 1; if (EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES == event) lost = 1; - port_dispatch(c->port[i], event, 0); + err = port_dispatch(c->port[i], event, 0); /* Clear any fault after a little while. */ if (PS_FAULTY == port_state(c->port[i])) { clock_fault_timeout(c, i, 1); diff --git a/port.c b/port.c index c521c18..681a4dd 100644 --- a/port.c +++ b/port.c @@ -1406,7 +1406,7 @@ struct foreign_clock *port_compute_best(struct port *p) return p->best; } -void port_dispatch(struct port *p, enum fsm_event event, int mdiff) +int port_dispatch(struct port *p, enum fsm_event event, int mdiff) { enum port_state next; @@ -1432,11 +1432,11 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff) next = port_initialize(p) ? PS_FAULTY : PS_LISTENING; port_show_transition(p, next, event); p->state = next; - return; + return 1; } if (next == p->state) - return; + return 0; port_show_transition(p, next, event); @@ -1493,6 +1493,7 @@ void port_dispatch(struct port *p, enum fsm_event event, int mdiff) }; } p->state = next; + return 0; } enum fsm_event port_event(struct port *p, int fd_index) diff --git a/port.h b/port.h index d98f610..74a08f7 100644 --- a/port.h +++ b/port.h @@ -68,8 +68,10 @@ struct foreign_clock *port_compute_best(struct port *port); * @param port A pointer previously obtained via port_open(). * @param event One of the @a fsm_event codes. * @param mdiff Whether a new master has been selected. + * @return Zero if the port's file descriptor array is still valid, + * and non-zero if it has become invalid. */ -void port_dispatch(struct port *p, enum fsm_event event, int mdiff); +int port_dispatch(struct port *p, enum fsm_event event, int mdiff); /** * Generates state machine events based on activity on a port's file