]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
eloop: Try and survive a signal storm
authorRoy Marples <roy@marples.name>
Tue, 16 Jun 2020 13:35:49 +0000 (14:35 +0100)
committerRoy Marples <roy@marples.name>
Tue, 16 Jun 2020 13:35:49 +0000 (14:35 +0100)
Shouldn't happen in production, but you never know.

src/eloop.c

index 6579a20c6db5ce9e6bc1ea93acde2813cb3f8d06..e9952f5380777f6287dbb2be961bc669795c0420 100644 (file)
@@ -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 @@ struct eloop {
        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 @@ eloop_q_timeout_add_msec(struct eloop *eloop, int queue, unsigned long when,
                (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_set_cb(struct eloop *eloop,
        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 @@ eloop_signal_mask(struct eloop *eloop, sigset_t *oldset)
        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 @@ eloop_start(struct eloop *eloop, sigset_t *signals)
        int n;
        struct eloop_event *e;
        struct eloop_timeout *t;
-       void (*t0)(void *);
        struct timespec ts, *tsp;
 
        assert(eloop != NULL);
@@ -720,11 +695,9 @@ eloop_start(struct eloop *eloop, sigset_t *signals)
                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;
                }