Fix sigaction(3) for 64-bit.

Also clean up <signal.h> and revert the hacks that were necessary
for 64-bit in linker/debugger.cpp until now.

Change-Id: I3b0554ca8a49ee1c97cda086ce2c1954ebc11892
diff --git a/libc/Android.mk b/libc/Android.mk
index 417d0ab..72b6dc8 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -125,7 +125,6 @@
 	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 @@
     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 f5712e1..e5e3c4d 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -224,7 +224,7 @@
 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 315d730..f9d348b 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -22,6 +22,7 @@
 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/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 65e8840..23a2b23 100644
--- a/libc/arch-arm/syscalls/sigaction.S
+++ b/libc/arch-arm/syscalls/__sigaction.S
@@ -4,7 +4,7 @@
 #include <linux/err.h>
 #include <machine/asm.h>
 
-ENTRY(sigaction)
+ENTRY(__sigaction)
     mov     ip, r7
     ldr     r7, =__NR_sigaction
     swi     #0
@@ -13,4 +13,4 @@
     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 4e7b65b..fc96222 100644
--- a/libc/arch-mips/syscalls.mk
+++ b/libc/arch-mips/syscalls.mk
@@ -22,6 +22,7 @@
 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/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 d1808c6..cc53ab4 100644
--- a/libc/arch-mips/syscalls/sigaction.S
+++ b/libc/arch-mips/syscalls/__sigaction.S
@@ -2,11 +2,11 @@
 
 #include <asm/unistd.h>
     .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 @@
     j $t9
     nop
     .set reorder
-    .end sigaction
+    .end __sigaction
diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk
index 8683221..5494992 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -22,6 +22,7 @@
 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/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 015f7f9..d1356a6 100644
--- a/libc/arch-x86/syscalls/sigaction.S
+++ b/libc/arch-x86/syscalls/__sigaction.S
@@ -4,7 +4,7 @@
 #include <linux/err.h>
 #include <machine/asm.h>
 
-ENTRY(sigaction)
+ENTRY(__sigaction)
     pushl   %ebx
     pushl   %ecx
     pushl   %edx
@@ -25,4 +25,4 @@
     popl    %ecx
     popl    %ebx
     ret
-END(sigaction)
+END(__sigaction)
diff --git a/libc/arch-x86_64/bionic/sigaction.c b/libc/arch-x86_64/bionic/sigaction.c
deleted file mode 100644
index d5622be..0000000
--- a/libc/arch-x86_64/bionic/sigaction.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 <signal.h>
-
-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 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;
-}
-
diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk
index 13442c7..244eb56 100644
--- a/libc/arch-x86_64/x86_64.mk
+++ b/libc/arch-x86_64/x86_64.mk
@@ -7,7 +7,6 @@
     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 0000000..6468b2d
--- /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 <signal.h>
+
+#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/bionic/signal.c b/libc/bionic/sigaddset.cpp
similarity index 70%
copy from libc/bionic/signal.c
copy to libc/bionic/sigaddset.cpp
index 949db13..33ec6f8 100644
--- a/libc/bionic/signal.c
+++ b/libc/bionic/sigaddset.cpp
@@ -25,33 +25,16 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #include <signal.h>
 
-
-static __sighandler_t
-_signal(int  signum, __sighandler_t  handler, int  flags)
-{
-    struct sigaction  sa;
-    __sighandler_t    result = 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;
-}
-
-
-__sighandler_t bsd_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESTART);
-}
-
-__sighandler_t sysv_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESETHAND);
+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;
 }
diff --git a/libc/bionic/signal.c b/libc/bionic/sigdelset.cpp
similarity index 70%
copy from libc/bionic/signal.c
copy to libc/bionic/sigdelset.cpp
index 949db13..9eea250 100644
--- a/libc/bionic/signal.c
+++ b/libc/bionic/sigdelset.cpp
@@ -25,33 +25,16 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #include <signal.h>
 
-
-static __sighandler_t
-_signal(int  signum, __sighandler_t  handler, int  flags)
-{
-    struct sigaction  sa;
-    __sighandler_t    result = 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;
-}
-
-
-__sighandler_t bsd_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESTART);
-}
-
-__sighandler_t sysv_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESETHAND);
+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/signal.c b/libc/bionic/sigemptyset.cpp
similarity index 70%
copy from libc/bionic/signal.c
copy to libc/bionic/sigemptyset.cpp
index 949db13..2993169 100644
--- a/libc/bionic/signal.c
+++ b/libc/bionic/sigemptyset.cpp
@@ -25,33 +25,14 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #include <signal.h>
 
-
-static __sighandler_t
-_signal(int  signum, __sighandler_t  handler, int  flags)
-{
-    struct sigaction  sa;
-    __sighandler_t    result = 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;
-}
-
-
-__sighandler_t bsd_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESTART);
-}
-
-__sighandler_t sysv_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESETHAND);
+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/signal.c b/libc/bionic/sigfillset.cpp
similarity index 70%
copy from libc/bionic/signal.c
copy to libc/bionic/sigfillset.cpp
index 949db13..7b7cbb8 100644
--- a/libc/bionic/signal.c
+++ b/libc/bionic/sigfillset.cpp
@@ -25,33 +25,14 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #include <signal.h>
 
-
-static __sighandler_t
-_signal(int  signum, __sighandler_t  handler, int  flags)
-{
-    struct sigaction  sa;
-    __sighandler_t    result = 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;
-}
-
-
-__sighandler_t bsd_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESTART);
-}
-
-__sighandler_t sysv_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESETHAND);
+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/signal.c b/libc/bionic/sigismember.cpp
similarity index 70%
copy from libc/bionic/signal.c
copy to libc/bionic/sigismember.cpp
index 949db13..0dc73ac 100644
--- a/libc/bionic/signal.c
+++ b/libc/bionic/sigismember.cpp
@@ -25,33 +25,15 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  */
+
 #include <signal.h>
 
-
-static __sighandler_t
-_signal(int  signum, __sighandler_t  handler, int  flags)
-{
-    struct sigaction  sa;
-    __sighandler_t    result = 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;
-}
-
-
-__sighandler_t bsd_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESTART);
-}
-
-__sighandler_t sysv_signal(int signum, __sighandler_t handler)
-{
-  return _signal(signum, handler, SA_RESETHAND);
+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 949db13..48b2e72 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 <signal.h>
 
+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 e211ef7..5e74161 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 <limits.h>		/* For LONG_BIT */
 #include <string.h>		/* For memset() */
 #include <sys/types.h>
-#include <asm/signal.h>
+
+#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 <asm/signal.h>
+#  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 <asm/signal.h>
+#endif
 
 #define __ARCH_SI_UID_T __kernel_uid32_t
 #include <asm/siginfo.h>
@@ -57,73 +69,37 @@
 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 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*);