changeset 5366:1d7408a4160b draft

eloop: Try and survive a signal storm Shouldn't happen in production, but you never know.
author Roy Marples <roy@marples.name>
date Tue, 16 Jun 2020 14:35:49 +0100
parents 57b9f2292dfb
children fce20bebb28a
files src/eloop.c
diffstat 1 files changed, 14 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/src/eloop.c	Tue Jun 16 11:58:16 2020 +0000
+++ b/src/eloop.c	Tue Jun 16 14:35:49 2020 +0100
@@ -92,6 +92,8 @@
 #include <stdio.h>
 #endif
 
+#define ELOOP_NSIGNALS		5 /* Allow a backlog of signals */
+
 /*
  * time_t is a signed integer of an unspecified size.
  * To adjust for time_t wrapping, we need to work the maximum signed
@@ -133,8 +135,6 @@
 	TAILQ_HEAD (timeout_head, eloop_timeout) timeouts;
 	struct timeout_head free_timeouts;
 
-	void (*timeout0)(void *);
-	void *timeout0_arg;
 	const int *signals;
 	size_t signals_len;
 	void (*signal_cb)(int, void *);
@@ -517,17 +517,6 @@
 		(unsigned int)seconds, (unsigned int)nseconds, callback, arg);
 }
 
-static int
-eloop_timeout_add_now(struct eloop *eloop,
-    void (*callback)(void *), void *arg)
-{
-
-	assert(eloop->timeout0 == NULL);
-	eloop->timeout0 = callback;
-	eloop->timeout0_arg = arg;
-	return 0;
-}
-
 int
 eloop_q_timeout_delete(struct eloop *eloop, int queue,
     void (*callback)(void *), void *arg)
@@ -582,32 +571,20 @@
 	eloop->signal_cb_ctx = signal_cb_ctx;
 }
 
-struct eloop_siginfo {
-	int sig;
-	struct eloop *eloop;
-};
-static struct eloop_siginfo _eloop_siginfo;
-static struct eloop *_eloop;
-
-static void
-eloop_signal1(void *arg)
-{
-	struct eloop_siginfo *si = arg;
-
-	si->eloop->signal_cb(si->sig, si->eloop->signal_cb_ctx);
-}
+static volatile int _eloop_sig[ELOOP_NSIGNALS];
+static volatile size_t _eloop_nsig;
 
 static void
 eloop_signal3(int sig, __unused siginfo_t *siginfo, __unused void *arg)
 {
 
-	/* So that we can operate safely under a signal we instruct
-	 * eloop to pass a copy of the siginfo structure to handle_signal1
-	 * as the very first thing to do. */
-	_eloop_siginfo.eloop = _eloop;
-	_eloop_siginfo.sig = sig;
-	eloop_timeout_add_now(_eloop_siginfo.eloop,
-	    eloop_signal1, &_eloop_siginfo);
+	if (_eloop_nsig == __arraycount(_eloop_sig)) {
+		fprintf(stderr, "%s: signal storm, discarding signal %d",
+		    __func__, sig);
+		return;
+	}
+
+	_eloop_sig[_eloop_nsig++] = sig;
 }
 
 int
@@ -628,7 +605,6 @@
 	if (sigprocmask(SIG_SETMASK, &newset, oldset) == -1)
 		return -1;
 
-	_eloop = eloop;
 	sigemptyset(&sa.sa_mask);
 
 	for (i = 0; i < eloop->signals_len; i++) {
@@ -711,7 +687,6 @@
 	int n;
 	struct eloop_event *e;
 	struct eloop_timeout *t;
-	void (*t0)(void *);
 	struct timespec ts, *tsp;
 
 	assert(eloop != NULL);
@@ -720,11 +695,9 @@
 		if (eloop->exitnow)
 			break;
 
-		/* Run all timeouts first. */
-		if (eloop->timeout0) {
-			t0 = eloop->timeout0;
-			eloop->timeout0 = NULL;
-			t0(eloop->timeout0_arg);
+		if (_eloop_nsig != 0 && eloop->signal_cb != NULL) {
+			n = _eloop_sig[--_eloop_nsig];
+			eloop->signal_cb(n, eloop->signal_cb_ctx);
 			continue;
 		}