summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_vty.c12
-rw-r--r--lib/sigevent.c27
-rw-r--r--lib/sigevent.h9
-rw-r--r--lib/thread.c119
-rw-r--r--lib/thread.h3
5 files changed, 147 insertions, 23 deletions
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 60aee515b2..ee7b851943 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -4429,7 +4429,7 @@ ALIAS_HIDDEN(neighbor_set_peer_group, neighbor_set_peer_group_hidden_cmd,
DEFUN (no_neighbor_set_peer_group,
no_neighbor_set_peer_group_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group [PGNAME]",
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
@@ -4438,21 +4438,13 @@ DEFUN (no_neighbor_set_peer_group,
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_peer = 2;
- int idx_word = 4;
int ret;
struct peer *peer;
- struct peer_group *group;
peer = peer_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- group = peer_group_lookup(bgp, argv[idx_word]->arg);
- if (!group) {
- vty_out(vty, "%% Configure the peer-group first\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
if (CHECK_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE))
bgp_zebra_terminate_radv(peer->bgp, peer);
@@ -4463,7 +4455,7 @@ DEFUN (no_neighbor_set_peer_group,
}
ALIAS_HIDDEN(no_neighbor_set_peer_group, no_neighbor_set_peer_group_hidden_cmd,
- "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> peer-group [PGNAME]",
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Member of the peer-group\n"
"Peer-group name\n")
diff --git a/lib/sigevent.c b/lib/sigevent.c
index 64404d338f..135f0187b4 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -63,6 +63,33 @@ static void quagga_signal_handler(int signo)
sigmaster.caught = 1;
}
+/*
+ * Check whether any signals have been received and are pending. This is done
+ * with the application's key signals blocked. The complete set of signals
+ * is returned in 'setp', so the caller can restore them when appropriate.
+ * If there are pending signals, returns 'true', 'false' otherwise.
+ */
+bool frr_sigevent_check(sigset_t *setp)
+{
+ sigset_t blocked;
+ int i;
+ bool ret;
+
+ sigemptyset(setp);
+ sigemptyset(&blocked);
+
+ /* Set up mask of application's signals */
+ for (i = 0; i < sigmaster.sigc; i++)
+ sigaddset(&blocked, sigmaster.signals[i].signal);
+
+ pthread_sigmask(SIG_BLOCK, &blocked, setp);
+
+ /* Now that the application's signals are blocked, test. */
+ ret = (sigmaster.caught != 0);
+
+ return ret;
+}
+
/* check if signals have been caught and run appropriate handlers */
int quagga_sigevent_process(void)
{
diff --git a/lib/sigevent.h b/lib/sigevent.h
index a0ad88fcaa..4a39b22889 100644
--- a/lib/sigevent.h
+++ b/lib/sigevent.h
@@ -48,6 +48,15 @@ struct quagga_signal_t {
extern void signal_init(struct thread_master *m, int sigc,
struct quagga_signal_t *signals);
+
+/*
+ * Check whether any signals have been received and are pending. This is done
+ * with the application's key signals blocked. The complete set of signals
+ * is returned in 'setp', so the caller can restore them when appropriate.
+ * If there are pending signals, returns 'true', 'false' otherwise.
+ */
+bool frr_sigevent_check(sigset_t *setp);
+
/* check whether there are signals to handle, process any found */
extern int quagga_sigevent_process(void);
diff --git a/lib/thread.c b/lib/thread.c
index 19e4827283..8d840359e4 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -723,9 +723,13 @@ static void thread_free(struct thread_master *master, struct thread *thread)
XFREE(MTYPE_THREAD, thread);
}
-static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
- nfds_t count, const struct timeval *timer_wait)
+static int fd_poll(struct thread_master *m, const struct timeval *timer_wait,
+ bool *eintr_p)
{
+ sigset_t origsigs;
+ unsigned char trash[64];
+ nfds_t count = m->handler.copycount;
+
/*
* If timer_wait is null here, that means poll() should block
* indefinitely, unless the thread_master has overridden it by setting
@@ -756,15 +760,58 @@ static int fd_poll(struct thread_master *m, struct pollfd *pfds, nfds_t pfdsize,
rcu_assert_read_unlocked();
/* add poll pipe poker */
- assert(count + 1 < pfdsize);
- pfds[count].fd = m->io_pipe[0];
- pfds[count].events = POLLIN;
- pfds[count].revents = 0x00;
+ assert(count + 1 < m->handler.pfdsize);
+ m->handler.copy[count].fd = m->io_pipe[0];
+ m->handler.copy[count].events = POLLIN;
+ m->handler.copy[count].revents = 0x00;
+
+ /* We need to deal with a signal-handling race here: we
+ * don't want to miss a crucial signal, such as SIGTERM or SIGINT,
+ * that may arrive just before we enter poll(). We will block the
+ * key signals, then check whether any have arrived - if so, we return
+ * before calling poll(). If not, we'll re-enable the signals
+ * in the ppoll() call.
+ */
- num = poll(pfds, count + 1, timeout);
+ sigemptyset(&origsigs);
+ if (m->handle_signals) {
+ /* Main pthread that handles the app signals */
+ if (frr_sigevent_check(&origsigs)) {
+ /* Signal to process - restore signal mask and return */
+ pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
+ num = -1;
+ *eintr_p = true;
+ goto done;
+ }
+ } else {
+ /* Don't make any changes for the non-main pthreads */
+ pthread_sigmask(SIG_SETMASK, NULL, &origsigs);
+ }
- unsigned char trash[64];
- if (num > 0 && pfds[count].revents != 0 && num--)
+#if defined(HAVE_PPOLL)
+ struct timespec ts, *tsp;
+
+ if (timeout >= 0) {
+ ts.tv_sec = timeout / 1000;
+ ts.tv_nsec = (timeout % 1000) * 1000000;
+ tsp = &ts;
+ } else
+ tsp = NULL;
+
+ num = ppoll(m->handler.copy, count + 1, tsp, &origsigs);
+ pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
+#else
+ /* Not ideal - there is a race after we restore the signal mask */
+ pthread_sigmask(SIG_SETMASK, &origsigs, NULL);
+ num = poll(m->handler.copy, count + 1, timeout);
+#endif
+
+done:
+
+ if (num < 0 && errno == EINTR)
+ *eintr_p = true;
+
+ if (num > 0 && m->handler.copy[count].revents != 0 && num--)
while (read(m->io_pipe[0], &trash, sizeof(trash)) > 0)
;
@@ -1391,7 +1438,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
struct timeval zerotime = {0, 0};
struct timeval tv;
struct timeval *tw = NULL;
-
+ bool eintr_p = false;
int num = 0;
do {
@@ -1463,14 +1510,14 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch)
pthread_mutex_unlock(&m->mtx);
{
- num = fd_poll(m, m->handler.copy, m->handler.pfdsize,
- m->handler.copycount, tw);
+ eintr_p = false;
+ num = fd_poll(m, tw, &eintr_p);
}
pthread_mutex_lock(&m->mtx);
/* Handle any errors received in poll() */
if (num < 0) {
- if (errno == EINTR) {
+ if (eintr_p) {
pthread_mutex_unlock(&m->mtx);
/* loop around to signal handler */
continue;
@@ -1656,3 +1703,49 @@ void funcname_thread_execute(struct thread_master *m,
/* Give back or free thread. */
thread_add_unuse(m, thread);
}
+
+/* Debug signal mask - if 'sigs' is NULL, use current effective mask. */
+void debug_signals(const sigset_t *sigs)
+{
+ int i, found;
+ sigset_t tmpsigs;
+ char buf[300];
+
+ /*
+ * We're only looking at the non-realtime signals here, so we need
+ * some limit value. Platform differences mean at some point we just
+ * need to pick a reasonable value.
+ */
+#if defined SIGRTMIN
+# define LAST_SIGNAL SIGRTMIN
+#else
+# define LAST_SIGNAL 32
+#endif
+
+
+ if (sigs == NULL) {
+ sigemptyset(&tmpsigs);
+ pthread_sigmask(SIG_BLOCK, NULL, &tmpsigs);
+ sigs = &tmpsigs;
+ }
+
+ found = 0;
+ buf[0] = '\0';
+
+ for (i = 0; i < LAST_SIGNAL; i++) {
+ char tmp[20];
+
+ if (sigismember(sigs, i) > 0) {
+ if (found > 0)
+ strlcat(buf, ",", sizeof(buf));
+ snprintf(tmp, sizeof(tmp), "%d", i);
+ strlcat(buf, tmp, sizeof(buf));
+ found++;
+ }
+ }
+
+ if (found == 0)
+ snprintf(buf, sizeof(buf), "<none>");
+
+ zlog_debug("%s: %s", __func__, buf);
+}
diff --git a/lib/thread.h b/lib/thread.h
index c22b2105cd..55ddac4059 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -233,6 +233,9 @@ extern pthread_key_t thread_current;
extern char *thread_timer_to_hhmmss(char *buf, int buf_size,
struct thread *t_timer);
+/* Debug signal mask */
+void debug_signals(const sigset_t *sigs);
+
#ifdef __cplusplus
}
#endif