From c7e9b2331771e5e87c34a8ee3dc6cc41d35b02fe Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 16 Oct 2013 22:27:54 -0700 Subject: [PATCH] Fix sigaction(3) for 64-bit. Also clean up and revert the hacks that were necessary for 64-bit in linker/debugger.cpp until now. Change-Id: I3b0554ca8a49ee1c97cda086ce2c1954ebc11892 --- libc/Android.mk | 8 +- libc/SYSCALLS.TXT | 2 +- libc/arch-arm/syscalls.mk | 2 +- .../syscalls/{sigaction.S => __sigaction.S} | 4 +- libc/arch-mips/syscalls.mk | 2 +- .../syscalls/{sigaction.S => __sigaction.S} | 8 +- libc/arch-x86/syscalls.mk | 2 +- .../syscalls/{sigaction.S => __sigaction.S} | 4 +- libc/arch-x86_64/x86_64.mk | 1 - libc/bionic/sigaction.cpp | 76 +++++++++++++ .../sigaction.c => bionic/sigaddset.cpp} | 30 ++---- libc/bionic/sigdelset.cpp | 40 +++++++ libc/bionic/sigemptyset.cpp | 38 +++++++ libc/bionic/sigfillset.cpp | 38 +++++++ libc/bionic/sigismember.cpp | 39 +++++++ libc/bionic/{signal.c => signal.cpp} | 35 +++--- libc/include/signal.h | 101 +++++++----------- linker/debugger.cpp | 9 -- tests/pthread_test.cpp | 4 +- tests/signal_test.cpp | 41 +++++++ 20 files changed, 358 insertions(+), 126 deletions(-) rename libc/arch-arm/syscalls/{sigaction.S => __sigaction.S} (89%) rename libc/arch-mips/syscalls/{sigaction.S => __sigaction.S} (78%) rename libc/arch-x86/syscalls/{sigaction.S => __sigaction.S} (93%) create mode 100644 libc/bionic/sigaction.cpp rename libc/{arch-x86_64/bionic/sigaction.c => bionic/sigaddset.cpp} (68%) create mode 100644 libc/bionic/sigdelset.cpp create mode 100644 libc/bionic/sigemptyset.cpp create mode 100644 libc/bionic/sigfillset.cpp create mode 100644 libc/bionic/sigismember.cpp rename libc/bionic/{signal.c => signal.cpp} (75%) diff --git a/libc/Android.mk b/libc/Android.mk index 417d0ab33..72b6dc880 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -125,7 +125,6 @@ libc_common_src_files := \ bionic/sigblock.c \ bionic/siginterrupt.c \ bionic/siglist.c \ - bionic/signal.c \ bionic/signame.c \ bionic/sigsetmask.c \ bionic/sleep.c \ @@ -246,6 +245,13 @@ libc_bionic_src_files := \ bionic/seteuid.cpp \ bionic/setlocale.cpp \ bionic/signalfd.cpp \ + bionic/sigaction.cpp \ + bionic/sigaddset.cpp \ + bionic/sigdelset.cpp \ + bionic/sigemptyset.cpp \ + bionic/sigfillset.cpp \ + bionic/sigismember.cpp \ + bionic/signal.cpp \ bionic/sigpending.cpp \ bionic/sigprocmask.cpp \ bionic/sigsuspend.cpp \ diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT index f5712e1bf..e5e3c4df8 100644 --- a/libc/SYSCALLS.TXT +++ b/libc/SYSCALLS.TXT @@ -224,7 +224,7 @@ int timerfd_settime(int, int, const struct itimerspec*, struct itimers int timerfd_gettime(int, struct itimerspec*) all # signals -int sigaction(int, const struct sigaction*, struct sigaction*) arm,x86,mips +int __sigaction:sigaction(int, const struct sigaction*, struct sigaction*) arm,mips,x86 int __rt_sigaction:rt_sigaction(int, const struct sigaction*, struct sigaction*, size_t) all int __rt_sigpending:rt_sigpending(sigset_t*, size_t) all int __rt_sigprocmask:rt_sigprocmask(int, const sigset_t*, sigset_t*, size_t) all diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk index 315d7300d..f9d348b4f 100644 --- a/libc/arch-arm/syscalls.mk +++ b/libc/arch-arm/syscalls.mk @@ -22,6 +22,7 @@ syscall_src += arch-arm/syscalls/__rt_sigsuspend.S syscall_src += arch-arm/syscalls/__rt_sigtimedwait.S syscall_src += arch-arm/syscalls/__sched_getaffinity.S syscall_src += arch-arm/syscalls/__set_tls.S +syscall_src += arch-arm/syscalls/__sigaction.S syscall_src += arch-arm/syscalls/__statfs64.S syscall_src += arch-arm/syscalls/__sys_clone.S syscall_src += arch-arm/syscalls/__syslog.S @@ -178,7 +179,6 @@ syscall_src += arch-arm/syscalls/settimeofday.S syscall_src += arch-arm/syscalls/setuid.S syscall_src += arch-arm/syscalls/setxattr.S syscall_src += arch-arm/syscalls/shutdown.S -syscall_src += arch-arm/syscalls/sigaction.S syscall_src += arch-arm/syscalls/sigaltstack.S syscall_src += arch-arm/syscalls/signalfd4.S syscall_src += arch-arm/syscalls/socket.S diff --git a/libc/arch-arm/syscalls/sigaction.S b/libc/arch-arm/syscalls/__sigaction.S similarity index 89% rename from libc/arch-arm/syscalls/sigaction.S rename to libc/arch-arm/syscalls/__sigaction.S index 65e8840de..23a2b23b3 100644 --- a/libc/arch-arm/syscalls/sigaction.S +++ b/libc/arch-arm/syscalls/__sigaction.S @@ -4,7 +4,7 @@ #include #include -ENTRY(sigaction) +ENTRY(__sigaction) mov ip, r7 ldr r7, =__NR_sigaction swi #0 @@ -13,4 +13,4 @@ ENTRY(sigaction) bxls lr neg r0, r0 b __set_errno -END(sigaction) +END(__sigaction) diff --git a/libc/arch-mips/syscalls.mk b/libc/arch-mips/syscalls.mk index 4e7b65ba7..fc96222e8 100644 --- a/libc/arch-mips/syscalls.mk +++ b/libc/arch-mips/syscalls.mk @@ -22,6 +22,7 @@ syscall_src += arch-mips/syscalls/__rt_sigsuspend.S syscall_src += arch-mips/syscalls/__rt_sigtimedwait.S syscall_src += arch-mips/syscalls/__sched_getaffinity.S syscall_src += arch-mips/syscalls/__set_thread_area.S +syscall_src += arch-mips/syscalls/__sigaction.S syscall_src += arch-mips/syscalls/__statfs64.S syscall_src += arch-mips/syscalls/__sys_clone.S syscall_src += arch-mips/syscalls/__syslog.S @@ -179,7 +180,6 @@ syscall_src += arch-mips/syscalls/settimeofday.S syscall_src += arch-mips/syscalls/setuid.S syscall_src += arch-mips/syscalls/setxattr.S syscall_src += arch-mips/syscalls/shutdown.S -syscall_src += arch-mips/syscalls/sigaction.S syscall_src += arch-mips/syscalls/sigaltstack.S syscall_src += arch-mips/syscalls/signalfd4.S syscall_src += arch-mips/syscalls/socket.S diff --git a/libc/arch-mips/syscalls/sigaction.S b/libc/arch-mips/syscalls/__sigaction.S similarity index 78% rename from libc/arch-mips/syscalls/sigaction.S rename to libc/arch-mips/syscalls/__sigaction.S index d1808c629..cc53ab417 100644 --- a/libc/arch-mips/syscalls/sigaction.S +++ b/libc/arch-mips/syscalls/__sigaction.S @@ -2,11 +2,11 @@ #include .text - .globl sigaction + .globl __sigaction .align 4 - .ent sigaction + .ent __sigaction -sigaction: +__sigaction: .set noreorder .cpload $t9 li $v0, __NR_sigaction @@ -20,4 +20,4 @@ sigaction: j $t9 nop .set reorder - .end sigaction + .end __sigaction diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk index 8683221f8..54949927e 100644 --- a/libc/arch-x86/syscalls.mk +++ b/libc/arch-x86/syscalls.mk @@ -22,6 +22,7 @@ syscall_src += arch-x86/syscalls/__rt_sigsuspend.S syscall_src += arch-x86/syscalls/__rt_sigtimedwait.S syscall_src += arch-x86/syscalls/__sched_getaffinity.S syscall_src += arch-x86/syscalls/__set_thread_area.S +syscall_src += arch-x86/syscalls/__sigaction.S syscall_src += arch-x86/syscalls/__statfs64.S syscall_src += arch-x86/syscalls/__sys_clone.S syscall_src += arch-x86/syscalls/__syslog.S @@ -179,7 +180,6 @@ syscall_src += arch-x86/syscalls/settimeofday.S syscall_src += arch-x86/syscalls/setuid.S syscall_src += arch-x86/syscalls/setxattr.S syscall_src += arch-x86/syscalls/shutdown.S -syscall_src += arch-x86/syscalls/sigaction.S syscall_src += arch-x86/syscalls/sigaltstack.S syscall_src += arch-x86/syscalls/signalfd4.S syscall_src += arch-x86/syscalls/socket.S diff --git a/libc/arch-x86/syscalls/sigaction.S b/libc/arch-x86/syscalls/__sigaction.S similarity index 93% rename from libc/arch-x86/syscalls/sigaction.S rename to libc/arch-x86/syscalls/__sigaction.S index 015f7f952..d1356a671 100644 --- a/libc/arch-x86/syscalls/sigaction.S +++ b/libc/arch-x86/syscalls/__sigaction.S @@ -4,7 +4,7 @@ #include #include -ENTRY(sigaction) +ENTRY(__sigaction) pushl %ebx pushl %ecx pushl %edx @@ -25,4 +25,4 @@ ENTRY(sigaction) popl %ecx popl %ebx ret -END(sigaction) +END(__sigaction) diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk index 13442c7cc..244eb5690 100644 --- a/libc/arch-x86_64/x86_64.mk +++ b/libc/arch-x86_64/x86_64.mk @@ -7,7 +7,6 @@ _LIBC_ARCH_COMMON_SRC_FILES := \ arch-x86_64/bionic/_setjmp.S \ arch-x86_64/bionic/setjmp.S \ arch-x86_64/bionic/__set_tls.c \ - arch-x86_64/bionic/sigaction.c \ arch-x86_64/bionic/sigsetjmp.S \ arch-x86_64/bionic/syscall.S \ diff --git a/libc/bionic/sigaction.cpp b/libc/bionic/sigaction.cpp new file mode 100644 index 000000000..6468b2d46 --- /dev/null +++ b/libc/bionic/sigaction.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#if __LP64__ +extern "C" void __rt_sigreturn(void); +extern "C" int __rt_sigaction(int, const struct __kernel_sigaction*, struct __kernel_sigaction*, size_t); +#else +extern "C" int __sigaction(int, const struct sigaction*, struct sigaction*); +#endif + +int sigaction(int signal, const struct sigaction* bionic_new_action, struct sigaction* bionic_old_action) { +#if __LP64__ + __kernel_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; + 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 = &__rt_sigreturn; + } + } + + __kernel_sigaction kernel_old_action; + int result = __rt_sigaction(signal, + (bionic_new_action != NULL) ? &kernel_new_action : NULL, + (bionic_old_action != NULL) ? &kernel_old_action : NULL, + sizeof(sigset_t)); + + if (bionic_old_action != NULL) { + bionic_old_action->sa_flags = kernel_old_action.sa_flags; + bionic_old_action->sa_handler = kernel_old_action.sa_handler; + bionic_old_action->sa_mask = kernel_old_action.sa_mask; + bionic_old_action->sa_restorer = kernel_old_action.sa_restorer; + + if (bionic_old_action->sa_restorer == &__rt_sigreturn) { + bionic_old_action->sa_flags &= ~SA_RESTORER; + } + } + + return result; +#else + // The 32-bit ABI is broken. struct sigaction includes a too-small sigset_t. + // TODO: if we also had correct struct sigaction definitions available, we could copy in and out. + return __sigaction(signal, bionic_new_action, bionic_old_action); +#endif +} diff --git a/libc/arch-x86_64/bionic/sigaction.c b/libc/bionic/sigaddset.cpp similarity index 68% rename from libc/arch-x86_64/bionic/sigaction.c rename to libc/bionic/sigaddset.cpp index d5622bee0..33ec6f84b 100644 --- a/libc/arch-x86_64/bionic/sigaction.c +++ b/libc/bionic/sigaddset.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 The Android Open Source Project + * Copyright (C) 2008 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,25 +28,13 @@ #include -extern void __rt_sigreturn(void); -extern int __rt_sigaction(int, const struct sigaction*, struct sigaction*, size_t); - -int sigaction(int sig, const struct sigaction* act, struct sigaction* old_act) { - struct sigaction sa; - - if (act != NULL && !(act->sa_flags & SA_RESTORER)) { - sa = *act; - act = &sa; - sa.sa_flags |= SA_RESTORER; - sa.sa_restorer = &__rt_sigreturn; +int sigaddset(sigset_t* set, int signum) { + int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. + unsigned long* local_set = (unsigned long*) set; + if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { + errno = EINVAL; + return -1; } - - int result = __rt_sigaction(sig, act, old_act, sizeof(sigset_t)); - - if (old_act != NULL && (old_act->sa_restorer == &__rt_sigreturn)) { - old_act->sa_flags &= ~SA_RESTORER; - } - - return result; + local_set[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT); + return 0; } - diff --git a/libc/bionic/sigdelset.cpp b/libc/bionic/sigdelset.cpp new file mode 100644 index 000000000..9eea2506a --- /dev/null +++ b/libc/bionic/sigdelset.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +int sigdelset(sigset_t* set, int signum) { + int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. + unsigned long* local_set = (unsigned long*) set; + if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { + errno = EINVAL; + return -1; + } + local_set[bit / LONG_BIT] &= ~(1UL << (bit % LONG_BIT)); + return 0; +} diff --git a/libc/bionic/sigemptyset.cpp b/libc/bionic/sigemptyset.cpp new file mode 100644 index 000000000..299316903 --- /dev/null +++ b/libc/bionic/sigemptyset.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +int sigemptyset(sigset_t* set) { + if (set == NULL) { + errno = EINVAL; + return -1; + } + memset(set, 0, sizeof(sigset_t)); + return 0; +} diff --git a/libc/bionic/sigfillset.cpp b/libc/bionic/sigfillset.cpp new file mode 100644 index 000000000..7b7cbb831 --- /dev/null +++ b/libc/bionic/sigfillset.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +int sigfillset(sigset_t* set) { + if (set == NULL) { + errno = EINVAL; + return -1; + } + memset(set, ~0, sizeof(sigset_t)); + return 0; +} diff --git a/libc/bionic/sigismember.cpp b/libc/bionic/sigismember.cpp new file mode 100644 index 000000000..0dc73acee --- /dev/null +++ b/libc/bionic/sigismember.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +int sigismember(const sigset_t* set, int signum) { + int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. + const unsigned long* local_set = (const unsigned long*) set; + if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { + errno = EINVAL; + return -1; + } + return (int) ((local_set[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1); +} diff --git a/libc/bionic/signal.c b/libc/bionic/signal.cpp similarity index 75% rename from libc/bionic/signal.c rename to libc/bionic/signal.cpp index 949db130a..48b2e723f 100644 --- a/libc/bionic/signal.c +++ b/libc/bionic/signal.cpp @@ -25,33 +25,30 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #include +static sighandler_t _signal(int signum, sighandler_t handler, int flags) { + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_handler = handler; + sa.sa_flags = flags; -static __sighandler_t -_signal(int signum, __sighandler_t handler, int flags) -{ - struct sigaction sa; - __sighandler_t result = SIG_ERR; + if (sigaction(signum, &sa, &sa) == -1) { + return SIG_ERR; + } - sigemptyset( &sa.sa_mask ); - - sa.sa_handler = handler; - sa.sa_flags = flags; - - if ( !sigaction( signum, &sa, &sa ) ) - result = (__sighandler_t) sa.sa_handler; - - return result; + return (sighandler_t) sa.sa_handler; } - -__sighandler_t bsd_signal(int signum, __sighandler_t handler) -{ +sighandler_t bsd_signal(int signum, sighandler_t handler) { return _signal(signum, handler, SA_RESTART); } -__sighandler_t sysv_signal(int signum, __sighandler_t handler) -{ +sighandler_t sysv_signal(int signum, sighandler_t handler) { return _signal(signum, handler, SA_RESETHAND); } + +sighandler_t signal(int signum, sighandler_t handler) { + return bsd_signal(signum, handler); +} diff --git a/libc/include/signal.h b/libc/include/signal.h index e211ef758..5e7416165 100644 --- a/libc/include/signal.h +++ b/libc/include/signal.h @@ -25,6 +25,7 @@ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ + #ifndef _SIGNAL_H_ #define _SIGNAL_H_ @@ -33,7 +34,18 @@ #include /* For LONG_BIT */ #include /* For memset() */ #include -#include + +#if defined(__LP64__) +/* For 64-bit, the kernel's struct sigaction doesn't match the POSIX one, + * so we need to expose our own and translate behind the scenes. */ +# define sigaction __kernel_sigaction +# include +# undef sigaction +#else +/* For 32-bit, we're stuck with the definitions we already shipped, + * even though they contain a sigset_t that's too small. */ +# include +#endif #define __ARCH_SI_UID_T __kernel_uid32_t #include @@ -57,73 +69,37 @@ typedef int sig_atomic_t; extern const char* const sys_siglist[]; extern const char* const sys_signame[]; -static __inline__ int sigismember(const sigset_t* set, int signum) { - int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. - const unsigned long* local_set = (const unsigned long*) set; - if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { - errno = EINVAL; - return -1; - } - return (int) ((local_set[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1); -} +typedef __sighandler_t sig_t; /* BSD compatibility. */ +typedef __sighandler_t sighandler_t; /* glibc compatibility. */ -static __inline__ int sigaddset(sigset_t* set, int signum) { - int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. - unsigned long* local_set = (unsigned long*) set; - if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { - errno = EINVAL; - return -1; - } - local_set[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT); - return 0; -} +#if __LP64__ -static __inline__ int sigdelset(sigset_t* set, int signum) { - int bit = signum - 1; // Signal numbers start at 1, but bit positions start at 0. - unsigned long* local_set = (unsigned long*) set; - if (set == NULL || bit < 0 || bit >= (int) (8*sizeof(sigset_t))) { - errno = EINVAL; - return -1; - } - local_set[bit / LONG_BIT] &= ~(1UL << (bit % LONG_BIT)); - return 0; -} +struct sigaction { + unsigned int sa_flags; + union { + sighandler_t sa_handler; + void (*sa_sigaction)(int, struct siginfo*, void*); + }; + sigset_t sa_mask; + void (*sa_restorer)(void); +}; -static __inline__ int sigemptyset(sigset_t* set) { - if (set == NULL) { - errno = EINVAL; - return -1; - } - memset(set, 0, sizeof *set); - return 0; -} - -static __inline__ int sigfillset(sigset_t* set) { - if (set == NULL) { - errno = EINVAL; - return -1; - } - memset(set, ~0, sizeof *set); - return 0; -} - - -/* compatibility types */ -typedef void (*sig_t)(int); -typedef sig_t sighandler_t; - -/* differentiater between sysv and bsd behaviour 8*/ -extern __sighandler_t sysv_signal(int, __sighandler_t); -extern __sighandler_t bsd_signal(int, __sighandler_t); - -/* the default is bsd */ -static __inline__ __sighandler_t signal(int s, __sighandler_t f) -{ - return bsd_signal(s,f); -} +#endif extern int sigaction(int, const struct sigaction*, struct sigaction*); + +extern sighandler_t signal(int, sighandler_t); +extern sighandler_t bsd_signal(int, sighandler_t); +extern sighandler_t sysv_signal(int, sighandler_t); + extern int siginterrupt(int, int); + +extern int sigaddset(sigset_t*, int); +extern int sigdelset(sigset_t*, int); +extern int sigemptyset(sigset_t*); +extern int sigfillset(sigset_t*); +extern int sigismember(const sigset_t*, int); + extern int sigpending(sigset_t*) __nonnull((1)); extern int sigprocmask(int, const sigset_t*, sigset_t*); extern int sigsuspend(const sigset_t*) __nonnull((1)); @@ -132,6 +108,7 @@ extern int sigwait(const sigset_t*, int*) __nonnull((1, 2)); extern int raise(int); extern int kill(pid_t, int); extern int killpg(int, int); + extern int sigaltstack(const stack_t*, stack_t*); extern void psiginfo(const siginfo_t*, const char*); diff --git a/linker/debugger.cpp b/linker/debugger.cpp index 6ddd35805..c9475228b 100644 --- a/linker/debugger.cpp +++ b/linker/debugger.cpp @@ -176,12 +176,7 @@ static bool have_siginfo(int signum) { * Catches fatal signals so we can ask debuggerd to ptrace us before * we crash. */ -#if __LP64__ // TODO: implement 64-bit sigaction using rt_sigaction. -void debuggerd_signal_handler(int n) { - siginfo_t* info = NULL; -#else void debuggerd_signal_handler(int n, siginfo_t* info, void*) { -#endif /* * It's possible somebody cleared the SA_SIGINFO flag, which would mean * our "info" arg holds an undefined value. @@ -254,11 +249,7 @@ void debuggerd_init() { struct sigaction action; memset(&action, 0, sizeof(action)); sigemptyset(&action.sa_mask); -#if __LP64__ // TODO: implement 64-bit sigaction using rt_sigaction. - action.sa_handler = debuggerd_signal_handler; -#else action.sa_sigaction = debuggerd_signal_handler; -#endif action.sa_flags = SA_RESTART | SA_SIGINFO; // Use the alternate signal stack if available so we can catch stack overflows. diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp index 4a7c155c0..a03232ff4 100644 --- a/tests/pthread_test.cpp +++ b/tests/pthread_test.cpp @@ -284,11 +284,13 @@ static void pthread_kill__in_signal_handler_helper(int signal_number) { TEST(pthread, pthread_kill__in_signal_handler) { struct sigaction action; + struct sigaction original_action; sigemptyset(&action.sa_mask); action.sa_flags = 0; action.sa_handler = pthread_kill__in_signal_handler_helper; - sigaction(SIGALRM, &action, NULL); + ASSERT_EQ(0, sigaction(SIGALRM, &action, &original_action)); ASSERT_EQ(0, pthread_kill(pthread_self(), SIGALRM)); + ASSERT_EQ(0, sigaction(SIGALRM, &original_action, NULL)); } TEST(pthread, pthread_detach__no_such_thread) { diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp index a719fe786..3070747c1 100644 --- a/tests/signal_test.cpp +++ b/tests/signal_test.cpp @@ -210,3 +210,44 @@ TEST(signal, sigsuspend_sigpending) { // Restore the original set. assert(0 == sigprocmask(SIG_SETMASK, &original_set, NULL)); } + +static void EmptySignalHandler(int) {} +static void EmptySignalAction(int, siginfo_t*, void*) {} + +TEST(signal, sigaction) { + // See what's currently set for SIGALRM. + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + ASSERT_EQ(0, sigaction(SIGALRM, NULL, &sa)); + ASSERT_TRUE(sa.sa_handler == NULL); + ASSERT_TRUE(sa.sa_sigaction == NULL); + ASSERT_TRUE(sa.sa_flags == 0); + + // Set a traditional sa_handler signal handler. + memset(&sa, 0, sizeof(sa)); + sigaddset(&sa.sa_mask, SIGALRM); + sa.sa_flags = SA_ONSTACK; + sa.sa_handler = EmptySignalHandler; + ASSERT_EQ(0, sigaction(SIGALRM, &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); + ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler); + ASSERT_TRUE(sa.sa_flags == SA_ONSTACK); + + // Set a new-style sa_sigaction signal handler. + memset(&sa, 0, sizeof(sa)); + sigaddset(&sa.sa_mask, SIGALRM); + sa.sa_flags = SA_ONSTACK | SA_SIGINFO; + sa.sa_sigaction = EmptySignalAction; + ASSERT_EQ(0, sigaction(SIGALRM, &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); + ASSERT_TRUE((void*) sa.sa_sigaction == (void*) sa.sa_handler); + ASSERT_TRUE(sa.sa_flags == (SA_ONSTACK | SA_SIGINFO)); +}