summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2022-11-16 18:54:29 +0100
committerYu Watanabe <watanabe.yu+github@gmail.com>2022-11-17 14:38:14 +0100
commit128a11ea9905ee3a9d2c6baeaf65618a21272f97 (patch)
treecc1c7d4a26fff9f9ded817ac0aecb37811ab0ec6
parenthwdb: fix Compaq N14KP6 key toggle touchpad (#25404) (diff)
downloadsystemd-128a11ea9905ee3a9d2c6baeaf65618a21272f97.tar.xz
systemd-128a11ea9905ee3a9d2c6baeaf65618a21272f97.zip
signal-util: add common implementation for propagating a signal
i.e. let's add a common logic to be called from a signal handler to raise the passed signal again. Follow-up for: #25399
-rw-r--r--src/basic/sigbus.c4
-rw-r--r--src/basic/signal-util.c18
-rw-r--r--src/basic/signal-util.h2
-rw-r--r--src/core/crash-handler.c12
4 files changed, 26 insertions, 10 deletions
diff --git a/src/basic/sigbus.c b/src/basic/sigbus.c
index 0dca7be479..7e5a493f6b 100644
--- a/src/basic/sigbus.c
+++ b/src/basic/sigbus.c
@@ -10,6 +10,7 @@
#include "missing_syscall.h"
#include "process-util.h"
#include "sigbus.h"
+#include "signal-util.h"
#define SIGBUS_QUEUE_MAX 64
@@ -102,8 +103,7 @@ static void sigbus_handler(int sn, siginfo_t *si, void *data) {
if (si->si_code != BUS_ADRERR || !si->si_addr) {
assert_se(sigaction(SIGBUS, &old_sigaction, NULL) == 0);
- if (rt_tgsigqueueinfo(getpid_cached(), gettid(), SIGBUS, si) < 0)
- (void) raise(SIGBUS);
+ propagate_signal(sn, si);
return;
}
diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c
index b61c18b2de..7875ca69bb 100644
--- a/src/basic/signal-util.c
+++ b/src/basic/signal-util.c
@@ -5,6 +5,7 @@
#include "errno-util.h"
#include "macro.h"
+#include "missing_syscall.h"
#include "parse-util.h"
#include "signal-util.h"
#include "stdio-util.h"
@@ -282,3 +283,20 @@ int pop_pending_signal_internal(int sig, ...) {
return r; /* Returns the signal popped */
}
+
+void propagate_signal(int sig, siginfo_t *siginfo) {
+ pid_t p;
+
+ /* To be called from a signal handler. Will raise the same signal again, in our process + in our threads.
+ *
+ * Note that we use raw_getpid() instead of getpid_cached(). We might have forked with raw_clone()
+ * earlier (see PID 1), and hence let's go to the raw syscall here. In particular as this is not
+ * performance sensitive code.
+ *
+ * Note that we use kill() rather than raise() as fallback, for similar reasons. */
+
+ p = raw_getpid();
+
+ if (rt_tgsigqueueinfo(p, gettid(), sig, siginfo) < 0)
+ assert_se(kill(p, sig) >= 0);
+}
diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h
index 36372c19bd..ad2ba841c6 100644
--- a/src/basic/signal-util.h
+++ b/src/basic/signal-util.h
@@ -65,3 +65,5 @@ int signal_is_blocked(int sig);
int pop_pending_signal_internal(int sig, ...);
#define pop_pending_signal(...) pop_pending_signal_internal(__VA_ARGS__, -1)
+
+void propagate_signal(int sig, siginfo_t *siginfo);
diff --git a/src/core/crash-handler.c b/src/core/crash-handler.c
index fced3ccf5a..6983f2e2b7 100644
--- a/src/core/crash-handler.c
+++ b/src/core/crash-handler.c
@@ -47,11 +47,10 @@ _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
* memory allocation is not async-signal-safe anyway — see signal-safety(7) for details —, and thus
* is not permissible in signal handlers.) */
- if (getpid_cached() != 1) {
+ if (getpid_cached() != 1)
/* Pass this on immediately, if this is not PID 1 */
- if (rt_tgsigqueueinfo(getpid_cached(), gettid(), sig, siginfo) < 0)
- (void) raise(sig);
- } else if (!arg_dump_core)
+ propagate_signal(sig, siginfo);
+ else if (!arg_dump_core)
log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
else {
sa = (struct sigaction) {
@@ -80,10 +79,7 @@ _noreturn_ static void crash(int sig, siginfo_t *siginfo, void *context) {
(void) chdir("/");
/* Raise the signal again */
- pid = raw_getpid();
- if (rt_tgsigqueueinfo(pid, gettid(), sig, siginfo) < 0)
- (void) kill(pid, sig); /* raise() would kill the parent */
-
+ propagate_signal(sig, siginfo);
assert_not_reached();
_exit(EXIT_EXCEPTION);
} else {