Merge "Add struct sigaction64
and sigaction64
."
This commit is contained in:
commit
ed95f37bc8
19 changed files with 173 additions and 126 deletions
|
@ -59,6 +59,9 @@ to double check:
|
|||
|
||||
In the 64-bit ABI, `off_t` is always 64-bit.
|
||||
|
||||
For source compatibility, the names containing `64` are also available
|
||||
in the 64-bit ABI even though they're identical to the non-`64` names.
|
||||
|
||||
|
||||
## `sigset_t` is too small for real-time signals
|
||||
|
||||
|
@ -68,8 +71,15 @@ code. Android P (API level 28) adds `sigset64_t` and a corresponding function
|
|||
for every function that takes a `sigset_t` (so `sigprocmask64` takes a
|
||||
`sigset64_t` where `sigprocmask` takes a `sigset_t`).
|
||||
|
||||
On 32-bit Android, `struct sigaction` is also too small because it contains
|
||||
a `sigset_t`. We also offer a `struct sigaction64` and `sigaction64` function
|
||||
to work around this.
|
||||
|
||||
In the 64-bit ABI, `sigset_t` is the correct size for every architecture.
|
||||
|
||||
For source compatibility, the names containing `64` are also available
|
||||
in the 64-bit ABI even though they're identical to the non-`64` names.
|
||||
|
||||
|
||||
## `time_t` is 32-bit
|
||||
|
||||
|
|
|
@ -49,11 +49,12 @@ New libc functions in P:
|
|||
* `iconv`/`iconv_close`/`iconv_open` (adding <iconv.h>)
|
||||
* `pthread_attr_getinheritsched`/`pthread_attr_setinheritsched`/`pthread_setschedprio`
|
||||
* `pthread_mutexattr_getprotocol`/`pthread_mutexattr_setprotocol` (mutex priority inheritance)
|
||||
* <signal.h> support for `sigaction64_t` and `sigset64_t` allowing LP32 access to real-time signals
|
||||
* <spawn.h>
|
||||
* `swab`
|
||||
* `syncfs`
|
||||
* `%C` and `%S` support in the printf family (previously only the wprintf family supported these).
|
||||
* `%mc`/`%ms`/`%m[` support in the scanf family.
|
||||
* `%C` and `%S` support in the printf family (previously only the wprintf family supported these)
|
||||
* `%mc`/`%ms`/`%m[` support in the scanf family
|
||||
|
||||
New libc functions in O:
|
||||
* `sendto` FORTIFY support
|
||||
|
|
|
@ -67,13 +67,10 @@ void abort() {
|
|||
sigprocmask64(SIG_SETMASK, &mask, nullptr);
|
||||
inline_tgkill(pid, tid, SIGABRT);
|
||||
|
||||
// If SIGABRT ignored, or caught and the handler returns,
|
||||
// If SIGABRT is ignored or it's caught and the handler returns,
|
||||
// remove the SIGABRT signal handler and raise SIGABRT again.
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGABRT, &sa, &sa);
|
||||
struct sigaction64 sa = { .sa_handler = SIG_DFL, .sa_flags = SA_RESTART };
|
||||
sigaction64(SIGABRT, &sa, nullptr);
|
||||
|
||||
sigprocmask64(SIG_SETMASK, &mask, nullptr);
|
||||
inline_tgkill(pid, tid, SIGABRT);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
extern "C" void __restore_rt(void);
|
||||
extern "C" void __restore(void);
|
||||
|
@ -75,28 +76,49 @@ int sigaction(int signal, const struct sigaction* bionic_new_action, struct siga
|
|||
return result;
|
||||
}
|
||||
|
||||
__strong_alias(sigaction64, sigaction);
|
||||
|
||||
#else
|
||||
|
||||
extern "C" int __rt_sigaction(int, const struct sigaction64*, struct sigaction64*, size_t);
|
||||
extern "C" int __sigaction(int, const struct sigaction*, struct sigaction*);
|
||||
|
||||
int sigaction(int signal, const struct sigaction* bionic_new_action, struct sigaction* bionic_old_action) {
|
||||
int sigaction(int signal, const struct sigaction* bionic_new, struct sigaction* bionic_old) {
|
||||
// The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t,
|
||||
// so we have to use sigaction(2) rather than rt_sigaction(2).
|
||||
struct sigaction kernel_new_action;
|
||||
if (bionic_new_action != NULL) {
|
||||
kernel_new_action.sa_flags = bionic_new_action->sa_flags;
|
||||
kernel_new_action.sa_handler = bionic_new_action->sa_handler;
|
||||
kernel_new_action.sa_mask = bionic_new_action->sa_mask;
|
||||
#if defined(SA_RESTORER)
|
||||
kernel_new_action.sa_restorer = bionic_new_action->sa_restorer;
|
||||
|
||||
if (!(kernel_new_action.sa_flags & SA_RESTORER)) {
|
||||
kernel_new_action.sa_flags |= SA_RESTORER;
|
||||
kernel_new_action.sa_restorer = (kernel_new_action.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
|
||||
}
|
||||
#endif
|
||||
// so we have to translate to struct sigaction64 first.
|
||||
struct sigaction64 kernel_new;
|
||||
if (bionic_new) {
|
||||
kernel_new = {};
|
||||
kernel_new.sa_flags = bionic_new->sa_flags;
|
||||
kernel_new.sa_handler = bionic_new->sa_handler;
|
||||
memcpy(&kernel_new.sa_mask, &bionic_new->sa_mask, sizeof(bionic_new->sa_mask));
|
||||
}
|
||||
return __sigaction(signal, (bionic_new_action != NULL) ? &kernel_new_action : NULL, bionic_old_action);
|
||||
|
||||
struct sigaction64 kernel_old;
|
||||
int result = sigaction64(signal, bionic_new ? &kernel_new : nullptr, &kernel_old);
|
||||
if (bionic_old) {
|
||||
*bionic_old = {};
|
||||
bionic_old->sa_flags = kernel_old.sa_flags;
|
||||
bionic_old->sa_handler = kernel_old.sa_handler;
|
||||
memcpy(&bionic_old->sa_mask, &kernel_old.sa_mask, sizeof(bionic_old->sa_mask));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int sigaction64(int signal, const struct sigaction64* bionic_new, struct sigaction64* bionic_old) {
|
||||
struct sigaction64 kernel_new;
|
||||
if (bionic_new) {
|
||||
kernel_new = *bionic_new;
|
||||
if (!(kernel_new.sa_flags & SA_RESTORER)) {
|
||||
kernel_new.sa_flags |= SA_RESTORER;
|
||||
kernel_new.sa_restorer = (kernel_new.sa_flags & SA_SIGINFO) ? &__restore_rt : &__restore;
|
||||
}
|
||||
}
|
||||
|
||||
return __rt_sigaction(signal,
|
||||
bionic_new ? &kernel_new : nullptr,
|
||||
bionic_old,
|
||||
sizeof(kernel_new.sa_mask));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -147,22 +147,19 @@ int sighold(int sig) {
|
|||
}
|
||||
|
||||
int sigignore(int sig) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
if (sigemptyset(&sa.sa_mask) == -1) return -1;
|
||||
sa.sa_handler = SIG_IGN;
|
||||
return sigaction(sig, &sa, nullptr);
|
||||
struct sigaction64 sa = { .sa_handler = SIG_IGN };
|
||||
return sigaction64(sig, &sa, nullptr);
|
||||
}
|
||||
|
||||
int siginterrupt(int sig, int flag) {
|
||||
struct sigaction act;
|
||||
sigaction(sig, nullptr, &act);
|
||||
struct sigaction64 act;
|
||||
sigaction64(sig, nullptr, &act);
|
||||
if (flag) {
|
||||
act.sa_flags &= ~SA_RESTART;
|
||||
} else {
|
||||
act.sa_flags |= SA_RESTART;
|
||||
}
|
||||
return sigaction(sig, &act, nullptr);
|
||||
return sigaction64(sig, &act, nullptr);
|
||||
}
|
||||
|
||||
template <typename SigSetT>
|
||||
|
@ -185,16 +182,8 @@ int sigismember64(const sigset64_t* set, int sig) {
|
|||
}
|
||||
|
||||
__LIBC_HIDDEN__ sighandler_t _signal(int sig, sighandler_t handler, int flags) {
|
||||
struct sigaction sa;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_handler = handler;
|
||||
sa.sa_flags = flags;
|
||||
|
||||
if (sigaction(sig, &sa, &sa) == -1) {
|
||||
return SIG_ERR;
|
||||
}
|
||||
|
||||
return sa.sa_handler;
|
||||
struct sigaction64 sa = { .sa_handler = handler, .sa_flags = flags };
|
||||
return (sigaction64(sig, &sa, &sa) == -1) ? SIG_ERR : sa.sa_handler;
|
||||
}
|
||||
|
||||
sighandler_t signal(int sig, sighandler_t handler) {
|
||||
|
@ -262,15 +251,11 @@ int sigrelse(int sig) {
|
|||
}
|
||||
|
||||
sighandler_t sigset(int sig, sighandler_t disp) {
|
||||
struct sigaction new_sa;
|
||||
if (disp != SIG_HOLD) {
|
||||
memset(&new_sa, 0, sizeof(new_sa));
|
||||
new_sa.sa_handler = disp;
|
||||
sigemptyset(&new_sa.sa_mask);
|
||||
}
|
||||
struct sigaction64 new_sa;
|
||||
if (disp != SIG_HOLD) new_sa = { .sa_handler = disp };
|
||||
|
||||
struct sigaction old_sa;
|
||||
if (sigaction(sig, (disp == SIG_HOLD) ? nullptr : &new_sa, &old_sa) == -1) {
|
||||
struct sigaction64 old_sa;
|
||||
if (sigaction64(sig, (disp == SIG_HOLD) ? nullptr : &new_sa, &old_sa) == -1) {
|
||||
return SIG_ERR;
|
||||
}
|
||||
|
||||
|
|
|
@ -98,17 +98,17 @@ static void ApplyAttrs(short flags, const posix_spawnattr_t* attr) {
|
|||
// POSIX: "Signals set to be caught by the calling process shall be
|
||||
// set to the default action in the child process."
|
||||
bool use_sigdefault = ((flags & POSIX_SPAWN_SETSIGDEF) != 0);
|
||||
const struct sigaction default_sa = { .sa_handler = SIG_DFL };
|
||||
const struct sigaction64 default_sa = { .sa_handler = SIG_DFL };
|
||||
for (int s = 1; s < _NSIG; ++s) {
|
||||
bool reset = false;
|
||||
if (use_sigdefault && sigismember64(&(*attr)->sigdefault.sigset64, s)) {
|
||||
reset = true;
|
||||
} else {
|
||||
struct sigaction current;
|
||||
if (sigaction(s, nullptr, ¤t) == -1) _exit(127);
|
||||
struct sigaction64 current;
|
||||
if (sigaction64(s, nullptr, ¤t) == -1) _exit(127);
|
||||
reset = (current.sa_handler != SIG_IGN && current.sa_handler != SIG_DFL);
|
||||
}
|
||||
if (reset && sigaction(s, &default_sa, nullptr) == -1) _exit(127);
|
||||
if (reset && sigaction64(s, &default_sa, nullptr) == -1) _exit(127);
|
||||
}
|
||||
|
||||
if ((flags & POSIX_SPAWN_SETPGROUP) != 0 && setpgid(0, (*attr)->pgroup) == -1) _exit(127);
|
||||
|
|
|
@ -40,7 +40,8 @@
|
|||
/* For 64-bit (and mips), the kernel's struct sigaction doesn't match the
|
||||
* POSIX one, so we need to expose our own and translate behind the scenes.
|
||||
* For 32-bit, we're stuck with the definitions we already shipped,
|
||||
* even though they contain a sigset_t that's too small. */
|
||||
* even though they contain a sigset_t that's too small. See sigaction64.
|
||||
*/
|
||||
#define sigaction __kernel_sigaction
|
||||
#include <linux/signal.h>
|
||||
#undef sigaction
|
||||
|
@ -89,43 +90,65 @@ typedef struct { unsigned long __bits[_KERNEL__NSIG/LONG_BIT]; } sigset64_t;
|
|||
|
||||
#if defined(__LP64__)
|
||||
|
||||
#define __SIGACTION_BODY \
|
||||
int sa_flags; \
|
||||
union { \
|
||||
sighandler_t sa_handler; \
|
||||
void (*sa_sigaction)(int, struct siginfo*, void*); \
|
||||
}; \
|
||||
sigset_t sa_mask; \
|
||||
void (*sa_restorer)(void); \
|
||||
|
||||
struct sigaction { __SIGACTION_BODY };
|
||||
struct sigaction64 { __SIGACTION_BODY };
|
||||
|
||||
#undef __SIGACTION_BODY
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
#define __SIGACTION_BODY \
|
||||
int sa_flags; \
|
||||
union { \
|
||||
sighandler_t sa_handler; \
|
||||
void (*sa_sigaction)(int, struct siginfo*, void*); \
|
||||
}; \
|
||||
sigset_t sa_mask; \
|
||||
|
||||
struct sigaction { __SIGACTION_BODY };
|
||||
struct sigaction64 { __SIGACTION_BODY };
|
||||
|
||||
#undef __SIGACTION_BODY
|
||||
|
||||
#else
|
||||
|
||||
#undef sa_handler
|
||||
#undef sa_sigaction
|
||||
|
||||
struct sigaction {
|
||||
int sa_flags;
|
||||
union {
|
||||
sighandler_t sa_handler;
|
||||
void (*sa_sigaction)(int, struct siginfo*, void*);
|
||||
};
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
void (*sa_restorer)(void);
|
||||
};
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
struct sigaction {
|
||||
int sa_flags;
|
||||
/* This matches the kernel's internal structure. */
|
||||
struct sigaction64 {
|
||||
union {
|
||||
sighandler_t sa_handler;
|
||||
void (*sa_sigaction) (int, struct siginfo*, void*);
|
||||
void (*sa_sigaction)(int, struct siginfo*, void*);
|
||||
};
|
||||
sigset_t sa_mask;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
struct sigaction {
|
||||
union {
|
||||
sighandler_t _sa_handler;
|
||||
void (*_sa_sigaction)(int, struct siginfo*, void*);
|
||||
} _u;
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
void (*sa_restorer)(void);
|
||||
sigset64_t sa_mask;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// TODO: sigaction contains a sigset_t that's too small on LP32.
|
||||
int sigaction(int __signal, const struct sigaction* __new_action, struct sigaction* __old_action);
|
||||
int sigaction64(int __signal, const struct sigaction64* __new_action, struct sigaction64* __old_action) __INTRODUCED_IN(28);
|
||||
|
||||
int siginterrupt(int __signal, int __flag);
|
||||
|
||||
|
@ -191,4 +214,4 @@ __END_DECLS
|
|||
|
||||
#include <android/legacy_signal_inlines.h>
|
||||
|
||||
#endif /* _SIGNAL_H_ */
|
||||
#endif
|
||||
|
|
|
@ -1386,6 +1386,7 @@ LIBC_P { # introduced=P
|
|||
sethostent;
|
||||
setnetent;
|
||||
setprotoent;
|
||||
sigaction64;
|
||||
sigaddset64;
|
||||
sigdelset64;
|
||||
sigemptyset64;
|
||||
|
|
|
@ -1306,6 +1306,7 @@ LIBC_P { # introduced=P
|
|||
sethostent;
|
||||
setnetent;
|
||||
setprotoent;
|
||||
sigaction64;
|
||||
sigaddset64;
|
||||
sigdelset64;
|
||||
sigemptyset64;
|
||||
|
|
|
@ -1411,6 +1411,7 @@ LIBC_P { # introduced=P
|
|||
sethostent;
|
||||
setnetent;
|
||||
setprotoent;
|
||||
sigaction64;
|
||||
sigaddset64;
|
||||
sigdelset64;
|
||||
sigemptyset64;
|
||||
|
|
|
@ -1370,6 +1370,7 @@ LIBC_P { # introduced=P
|
|||
sethostent;
|
||||
setnetent;
|
||||
setprotoent;
|
||||
sigaction64;
|
||||
sigaddset64;
|
||||
sigdelset64;
|
||||
sigemptyset64;
|
||||
|
|
|
@ -1306,6 +1306,7 @@ LIBC_P { # introduced=P
|
|||
sethostent;
|
||||
setnetent;
|
||||
setprotoent;
|
||||
sigaction64;
|
||||
sigaddset64;
|
||||
sigdelset64;
|
||||
sigemptyset64;
|
||||
|
|
|
@ -1368,6 +1368,7 @@ LIBC_P { # introduced=P
|
|||
sethostent;
|
||||
setnetent;
|
||||
setprotoent;
|
||||
sigaction64;
|
||||
sigaddset64;
|
||||
sigdelset64;
|
||||
sigemptyset64;
|
||||
|
|
|
@ -1306,6 +1306,7 @@ LIBC_P { # introduced=P
|
|||
sethostent;
|
||||
setnetent;
|
||||
setprotoent;
|
||||
sigaction64;
|
||||
sigaddset64;
|
||||
sigdelset64;
|
||||
sigemptyset64;
|
||||
|
|
|
@ -59,13 +59,10 @@ BacktraceData::BacktraceData(DebugData* debug_data, const Config& config, size_t
|
|||
bool BacktraceData::Initialize(const Config& config) {
|
||||
enabled_ = config.backtrace_enabled();
|
||||
if (config.backtrace_enable_on_signal()) {
|
||||
struct sigaction enable_act;
|
||||
memset(&enable_act, 0, sizeof(enable_act));
|
||||
|
||||
struct sigaction64 enable_act = {};
|
||||
enable_act.sa_sigaction = ToggleBacktraceEnable;
|
||||
enable_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
|
||||
sigemptyset(&enable_act.sa_mask);
|
||||
if (sigaction(config.backtrace_signal(), &enable_act, nullptr) != 0) {
|
||||
if (sigaction64(config.backtrace_signal(), &enable_act, nullptr) != 0) {
|
||||
error_log("Unable to set up backtrace signal enable function: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
@ -73,13 +70,10 @@ bool BacktraceData::Initialize(const Config& config) {
|
|||
config.backtrace_signal(), getpid());
|
||||
}
|
||||
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(act));
|
||||
|
||||
struct sigaction64 act = {};
|
||||
act.sa_sigaction = EnableDump;
|
||||
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
|
||||
sigemptyset(&act.sa_mask);
|
||||
if (sigaction(config.backtrace_dump_signal(), &act, nullptr) != 0) {
|
||||
if (sigaction64(config.backtrace_dump_signal(), &act, nullptr) != 0) {
|
||||
error_log("Unable to set up backtrace dump signal function: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -179,13 +179,10 @@ RecordData::RecordData() {
|
|||
}
|
||||
|
||||
bool RecordData::Initialize(const Config& config) {
|
||||
struct sigaction dump_act;
|
||||
memset(&dump_act, 0, sizeof(dump_act));
|
||||
|
||||
struct sigaction64 dump_act = {};
|
||||
dump_act.sa_sigaction = RecordDump;
|
||||
dump_act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
|
||||
sigemptyset(&dump_act.sa_mask);
|
||||
if (sigaction(config.record_allocs_signal(), &dump_act, nullptr) != 0) {
|
||||
if (sigaction64(config.record_allocs_signal(), &dump_act, nullptr) != 0) {
|
||||
error_log("Unable to set up record dump signal function: %s", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -21,25 +21,28 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#if !defined(__BIONIC__)
|
||||
#define sigaction64 sigaction
|
||||
#endif
|
||||
|
||||
class BionicDeathTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
// Suppress debuggerd stack traces. Too slow.
|
||||
for (int signo : { SIGABRT, SIGBUS, SIGSEGV, SIGSYS }) {
|
||||
struct sigaction action = {};
|
||||
action.sa_handler = SIG_DFL;
|
||||
sigaction(signo, &action, &previous_);
|
||||
struct sigaction64 action = { .sa_handler = SIG_DFL };
|
||||
sigaction64(signo, &action, &previous_);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
for (int signo : { SIGABRT, SIGBUS, SIGSEGV, SIGSYS }) {
|
||||
sigaction(signo, &previous_, nullptr);
|
||||
sigaction64(signo, &previous_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
struct sigaction previous_;
|
||||
struct sigaction64 previous_;
|
||||
};
|
||||
|
||||
#endif // BIONIC_TESTS_BIONIC_DEATH_TEST_H_
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#define posix_spawnattr_setsigdefault64 posix_spawnattr_setsigdefault
|
||||
#define posix_spawnattr_setsigmask64 posix_spawnattr_setsigmask
|
||||
#define pthread_sigmask64 pthread_sigmask
|
||||
#define sigaction64 sigaction
|
||||
#define sigaddset64 sigaddset
|
||||
#define sigdelset64 sigdelset
|
||||
#define sigemptyset64 sigemptyset
|
||||
|
@ -47,7 +48,7 @@ class ScopedSignalHandler {
|
|||
memset(&action_, 0, sizeof(action_));
|
||||
action_.sa_flags = sa_flags;
|
||||
action_.sa_handler = handler;
|
||||
sigaction(signal_number_, &action_, &old_action_);
|
||||
sigaction64(signal_number_, &action_, &old_action_);
|
||||
}
|
||||
|
||||
ScopedSignalHandler(int signal_number, void (*action)(int, siginfo_t*, void*),
|
||||
|
@ -56,20 +57,20 @@ class ScopedSignalHandler {
|
|||
memset(&action_, 0, sizeof(action_));
|
||||
action_.sa_flags = sa_flags;
|
||||
action_.sa_sigaction = action;
|
||||
sigaction(signal_number_, &action_, &old_action_);
|
||||
sigaction64(signal_number_, &action_, &old_action_);
|
||||
}
|
||||
|
||||
ScopedSignalHandler(int signal_number) : signal_number_(signal_number) {
|
||||
sigaction(signal_number, nullptr, &old_action_);
|
||||
sigaction64(signal_number, nullptr, &old_action_);
|
||||
}
|
||||
|
||||
~ScopedSignalHandler() {
|
||||
sigaction(signal_number_, &old_action_, NULL);
|
||||
sigaction64(signal_number_, &old_action_, NULL);
|
||||
}
|
||||
|
||||
private:
|
||||
struct sigaction action_;
|
||||
struct sigaction old_action_;
|
||||
struct sigaction64 action_;
|
||||
struct sigaction64 old_action_;
|
||||
const int signal_number_;
|
||||
};
|
||||
|
||||
|
|
|
@ -269,55 +269,63 @@ TEST(signal, sigsuspend64_sigpending64) {
|
|||
ASSERT_EQ(1, g_sigsuspend64_signal_handler_call_count);
|
||||
}
|
||||
|
||||
static void EmptySignalHandler(int) {}
|
||||
static void EmptySignalAction(int, siginfo_t*, void*) {}
|
||||
|
||||
TEST(signal, sigaction) {
|
||||
template <typename SigActionT, typename SigSetT>
|
||||
static void TestSigAction(int (sigaction_fn)(int, const SigActionT*, SigActionT*),
|
||||
int (sigaddset_fn)(SigSetT*, int),
|
||||
int sig) {
|
||||
// Both bionic and glibc set SA_RESTORER when talking to the kernel on arm,
|
||||
// arm64, x86, and x86-64. The version of glibc we're using also doesn't
|
||||
// define SA_RESTORER, but luckily it's the same value everywhere, and mips
|
||||
// doesn't use the bit for anything.
|
||||
static const unsigned sa_restorer = 0x4000000;
|
||||
|
||||
// See what's currently set for SIGALRM.
|
||||
struct sigaction original_sa;
|
||||
memset(&original_sa, 0, sizeof(original_sa));
|
||||
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &original_sa));
|
||||
// See what's currently set for this signal.
|
||||
SigActionT original_sa = {};
|
||||
ASSERT_EQ(0, sigaction_fn(sig, NULL, &original_sa));
|
||||
ASSERT_TRUE(original_sa.sa_handler == NULL);
|
||||
ASSERT_TRUE(original_sa.sa_sigaction == NULL);
|
||||
ASSERT_EQ(0U, original_sa.sa_flags & ~sa_restorer);
|
||||
|
||||
// Set a traditional sa_handler signal handler.
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigaddset(&sa.sa_mask, SIGALRM);
|
||||
auto no_op_signal_handler = [](int) {};
|
||||
SigActionT sa = {};
|
||||
sigaddset_fn(&sa.sa_mask, sig);
|
||||
sa.sa_flags = SA_ONSTACK;
|
||||
sa.sa_handler = EmptySignalHandler;
|
||||
ASSERT_EQ(0, sigaction(SIGALRM, &sa, NULL));
|
||||
sa.sa_handler = no_op_signal_handler;
|
||||
ASSERT_EQ(0, sigaction_fn(sig, &sa, NULL));
|
||||
|
||||
// Check that we can read it back.
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa));
|
||||
ASSERT_TRUE(sa.sa_handler == EmptySignalHandler);
|
||||
sa = {};
|
||||
ASSERT_EQ(0, sigaction_fn(sig, NULL, &sa));
|
||||
ASSERT_TRUE(sa.sa_handler == no_op_signal_handler);
|
||||
ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
|
||||
ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK), sa.sa_flags & ~sa_restorer);
|
||||
|
||||
// Set a new-style sa_sigaction signal handler.
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sigaddset(&sa.sa_mask, SIGALRM);
|
||||
auto no_op_sigaction = [](int, siginfo_t*, void*) {};
|
||||
sa = {};
|
||||
sigaddset_fn(&sa.sa_mask, sig);
|
||||
sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
|
||||
sa.sa_sigaction = EmptySignalAction;
|
||||
ASSERT_EQ(0, sigaction(SIGALRM, &sa, NULL));
|
||||
sa.sa_sigaction = no_op_sigaction;
|
||||
ASSERT_EQ(0, sigaction_fn(sig, &sa, NULL));
|
||||
|
||||
// Check that we can read it back.
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa));
|
||||
ASSERT_TRUE(sa.sa_sigaction == EmptySignalAction);
|
||||
sa = {};
|
||||
ASSERT_EQ(0, sigaction_fn(sig, NULL, &sa));
|
||||
ASSERT_TRUE(sa.sa_sigaction == no_op_sigaction);
|
||||
ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler);
|
||||
ASSERT_EQ(static_cast<unsigned>(SA_ONSTACK | SA_SIGINFO), sa.sa_flags & ~sa_restorer);
|
||||
|
||||
// Put everything back how it was.
|
||||
ASSERT_EQ(0, sigaction(SIGALRM, &original_sa, NULL));
|
||||
ASSERT_EQ(0, sigaction_fn(sig, &original_sa, NULL));
|
||||
}
|
||||
|
||||
TEST(signal, sigaction) {
|
||||
TestSigAction(sigaction, sigaddset, SIGALRM);
|
||||
}
|
||||
|
||||
TEST(signal, sigaction64_SIGRTMIN) {
|
||||
TestSigAction(sigaction64, sigaddset64, SIGRTMIN);
|
||||
}
|
||||
|
||||
TEST(signal, sys_signame) {
|
||||
|
@ -495,8 +503,7 @@ TEST(signal, rt_tgsigqueueinfo) {
|
|||
"* https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=66dd34ad31e5963d72a700ec3f2449291d322921\n";
|
||||
static siginfo received;
|
||||
|
||||
struct sigaction handler;
|
||||
memset(&handler, 0, sizeof(handler));
|
||||
struct sigaction handler = {};
|
||||
handler.sa_sigaction = [](int, siginfo_t* siginfo, void*) { received = *siginfo; };
|
||||
handler.sa_flags = SA_SIGINFO;
|
||||
|
||||
|
|
Loading…
Reference in a new issue