From: Lennart Poettering Date: Thu, 25 Feb 2021 11:11:59 +0000 (+0100) Subject: signal-util: add helper pop_pending_signal() X-Git-Tag: v250-rc1~972^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0178ff292b1befb5149c16e62e7ab12b0ef83954;p=thirdparty%2Fsystemd.git signal-util: add helper pop_pending_signal() --- diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index 131fd3ba004..b06b5ce7744 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -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 */ +} diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index 37271d7a68e..36372c19bd8 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -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) diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c index 76ab9b8ad28..05867759025 100644 --- a/src/test/test-signal-util.c +++ b/src/test/test-signal-util.c @@ -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; }