aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Support/Unix/Signals.inc
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Support/Unix/Signals.inc')
-rw-r--r--llvm/lib/Support/Unix/Signals.inc21
1 files changed, 18 insertions, 3 deletions
diff --git a/llvm/lib/Support/Unix/Signals.inc b/llvm/lib/Support/Unix/Signals.inc
index a4525a5..6cd38aa 100644
--- a/llvm/lib/Support/Unix/Signals.inc
+++ b/llvm/lib/Support/Unix/Signals.inc
@@ -78,6 +78,10 @@
#include <__le_cwi.h>
#endif
+#if defined(__linux__)
+#include <sys/syscall.h>
+#endif
+
using namespace llvm;
static void SignalHandler(int Sig, siginfo_t *Info, void *);
@@ -413,10 +417,21 @@ static void SignalHandler(int Sig, siginfo_t *Info, void *) {
raise(Sig);
#endif
- // Signal sent from another process, do not assume that continuing the
- // execution would re-raise it.
- if (Info->si_pid != getpid())
+#if defined(__linux__)
+ // Re-raising a signal via `raise` loses the original siginfo. Recent
+ // versions of linux (>= 3.9) support processes sending a signal to itself
+ // with arbitrary signal information using a syscall. If this syscall is
+ // unsupported, errno will be set to EPERM and `raise` will be used instead.
+ int retval =
+ syscall(SYS_rt_tgsigqueueinfo, getpid(), syscall(SYS_gettid), Sig, Info);
+ if (retval != 0 && errno == EPERM)
raise(Sig);
+#else
+ // Signal sent from another userspace process, do not assume that continuing
+ // the execution would re-raise it.
+ if (Info->si_pid != getpid() && Info->si_pid != 0)
+ raise(Sig);
+#endif
}
static void InfoSignalHandler(int Sig) {