]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
signal-util: add helper pop_pending_signal()
authorLennart Poettering <lennart@poettering.net>
Thu, 25 Feb 2021 11:11:59 +0000 (12:11 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 8 Jul 2021 08:33:38 +0000 (10:33 +0200)
src/basic/signal-util.c
src/basic/signal-util.h
src/test/test-signal-util.c

index 131fd3ba0047976b43a9efe7d2e24771594ba0a3..b06b5ce7744d8d444a2561097effdd455cff6398 100644 (file)
@@ -253,3 +253,38 @@ int signal_is_blocked(int sig) {
 
         return r;
 }
+
+int pop_pending_signal_internal(int sig, ...) {
+        sigset_t ss;
+        va_list ap;
+        int r;
+
+        if (sig < 0) /* Empty list? */
+                return -EINVAL;
+
+        if (sigemptyset(&ss) < 0)
+                return -errno;
+
+        /* Add first signal (if the signal is zero, we'll silently skip it, to make it easiert to build
+         * parameter lists where some element are sometimes off, similar to how sigset_add_many_ap() handles
+         * this.) */
+        if (sig > 0 && sigaddset(&ss, sig) < 0)
+                return -errno;
+
+        /* Add all other signals */
+        va_start(ap, sig);
+        r = sigset_add_many_ap(&ss, ap);
+        va_end(ap);
+        if (r < 0)
+                return r;
+
+        r = sigtimedwait(&ss, NULL, &(struct timespec) { 0, 0 });
+        if (r < 0) {
+                if (errno == EAGAIN)
+                        return 0;
+
+                return -errno;
+        }
+
+        return r; /* Returns the signal popped */
+}
index 37271d7a68e4eb4888870d36ab7f0cf6f57ef041..36372c19bd8a989d910764b3330c2509d97b5558 100644 (file)
@@ -62,3 +62,6 @@ static inline const char* signal_to_string_with_check(int n) {
 }
 
 int signal_is_blocked(int sig);
+
+int pop_pending_signal_internal(int sig, ...);
+#define pop_pending_signal(...) pop_pending_signal_internal(__VA_ARGS__, -1)
index 76ab9b8ad289d5c83536924e633b4055e8fa5357..058677590255bb02a2ddaa9abff7d73fd20626ea 100644 (file)
@@ -133,11 +133,50 @@ static void test_ignore_signals(void) {
         assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE) >= 0);
 }
 
+static void test_pop_pending_signal(void) {
+
+        assert_se(signal_is_blocked(SIGUSR1) == 0);
+        assert_se(signal_is_blocked(SIGUSR2) == 0);
+        assert_se(pop_pending_signal(SIGUSR1) == 0);
+        assert_se(pop_pending_signal(SIGUSR2) == 0);
+
+        {
+                BLOCK_SIGNALS(SIGUSR1, SIGUSR2);
+
+                assert_se(signal_is_blocked(SIGUSR1) > 0);
+                assert_se(signal_is_blocked(SIGUSR2) > 0);
+
+                assert_se(pop_pending_signal(SIGUSR1) == 0);
+                assert_se(pop_pending_signal(SIGUSR2) == 0);
+
+                assert_se(raise(SIGUSR1) >= 0);
+
+                assert_se(pop_pending_signal(SIGUSR2) == 0);
+                assert_se(pop_pending_signal(SIGUSR1) == SIGUSR1);
+                assert_se(pop_pending_signal(SIGUSR1) == 0);
+
+                assert_se(raise(SIGUSR1) >= 0);
+                assert_se(raise(SIGUSR2) >= 0);
+
+                assert_cc(SIGUSR1 < SIGUSR2);
+
+                assert_se(pop_pending_signal(SIGUSR1, SIGUSR2) == SIGUSR1);
+                assert_se(pop_pending_signal(SIGUSR1, SIGUSR2) == SIGUSR2);
+                assert_se(pop_pending_signal(SIGUSR1, SIGUSR2) == 0);
+        }
+
+        assert_se(signal_is_blocked(SIGUSR1) == 0);
+        assert_se(signal_is_blocked(SIGUSR2) == 0);
+        assert_se(pop_pending_signal(SIGUSR1) == 0);
+        assert_se(pop_pending_signal(SIGUSR2) == 0);
+}
+
 int main(int argc, char *argv[]) {
         test_rt_signals();
         test_signal_from_string();
         test_block_signals();
         test_ignore_signals();
+        test_pop_pending_signal();
 
         return 0;
 }