From 40d105ccb3e6283566ce54b693b3088f31aa4f26 Mon Sep 17 00:00:00 2001
From: Elliott Hughes <enh@google.com>
Date: Wed, 16 Oct 2013 12:53:58 -0700
Subject: [PATCH] Switch sigpending over to rt_sigpending.

Change-Id: I7b28984796b5fb343cfbcc47e0afc3a84293d417
---
 libc/Android.mk                               |  1 +
 libc/SYSCALLS.TXT                             |  9 ++-
 libc/arch-arm/syscalls.mk                     |  4 +-
 .../{sigpending.S => __rt_sigpending.S}       |  6 +-
 libc/arch-mips/syscalls.mk                    |  6 +-
 .../{sigpending.S => __rt_sigpending.S}       | 10 ++--
 libc/arch-x86/syscalls.mk                     |  6 +-
 .../{sigpending.S => __rt_sigpending.S}       | 11 ++--
 libc/arch-x86_64/syscalls.mk                  |  3 +-
 libc/arch-x86_64/syscalls/__rt_sigpending.S   | 17 ++++++
 libc/bionic/sigpending.cpp                    | 42 ++++++++++++++
 libc/include/signal.h                         | 24 ++++----
 tests/signal_test.cpp                         | 58 +++++++++++++------
 13 files changed, 140 insertions(+), 57 deletions(-)
 rename libc/arch-arm/syscalls/{sigpending.S => __rt_sigpending.S} (76%)
 rename libc/arch-mips/syscalls/{sigpending.S => __rt_sigpending.S} (66%)
 rename libc/arch-x86/syscalls/{sigpending.S => __rt_sigpending.S} (65%)
 create mode 100644 libc/arch-x86_64/syscalls/__rt_sigpending.S
 create mode 100644 libc/bionic/sigpending.cpp

diff --git a/libc/Android.mk b/libc/Android.mk
index 88be78dc2..417d0ab33 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -246,6 +246,7 @@ libc_bionic_src_files := \
     bionic/seteuid.cpp \
     bionic/setlocale.cpp \
     bionic/signalfd.cpp \
+    bionic/sigpending.cpp \
     bionic/sigprocmask.cpp \
     bionic/sigsuspend.cpp \
     bionic/sigwait.cpp \
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 1d6c75f8d..f5712e1bf 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -28,13 +28,12 @@
 void    _exit:exit_group(int)      all
 void    _exit_thread:exit(int)     all
 pid_t   __fork:fork(void)           all
-pid_t   _waitpid:waitpid(pid_t, int*, int, struct rusage*)   mips,x86
-int     __waitid:waitid(int, pid_t, struct siginfo_t*, int, void*)          all
 pid_t   wait4(pid_t pid, int* status, int options, struct rusage* rusage)   all
 
-# NOTE: this system call is never called directly, but we list it there
-#       to have __NR_clone properly defined.
+# NOTE: these stubs are unused.
 pid_t   __sys_clone:clone(int, void*, int*, void*, int*) all
+pid_t   _waitpid:waitpid(pid_t, int*, int, struct rusage*)   mips,x86
+int     __waitid:waitid(int, pid_t, struct siginfo_t*, int, void*)          all
 
 int     execve(const char*, char* const*, char* const*)  all
 
@@ -226,8 +225,8 @@ int           timerfd_gettime(int, struct itimerspec*)   all
 
 # signals
 int     sigaction(int, const struct sigaction*, struct sigaction*)  arm,x86,mips
-int     sigpending(sigset_t*)  arm,x86,mips
 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
 int     __rt_sigsuspend:rt_sigsuspend(const sigset_t*, size_t)  all
 int     __rt_sigtimedwait:rt_sigtimedwait(const sigset_t*, struct siginfo_t*, struct timespec_t*, size_t)  all
diff --git a/libc/arch-arm/syscalls.mk b/libc/arch-arm/syscalls.mk
index dc7e3dfdb..5e5e56bfd 100644
--- a/libc/arch-arm/syscalls.mk
+++ b/libc/arch-arm/syscalls.mk
@@ -3,9 +3,9 @@ syscall_src :=
 syscall_src += arch-arm/syscalls/_exit.S
 syscall_src += arch-arm/syscalls/_exit_thread.S
 syscall_src += arch-arm/syscalls/__fork.S
-syscall_src += arch-arm/syscalls/__waitid.S
 syscall_src += arch-arm/syscalls/wait4.S
 syscall_src += arch-arm/syscalls/__sys_clone.S
+syscall_src += arch-arm/syscalls/__waitid.S
 syscall_src += arch-arm/syscalls/execve.S
 syscall_src += arch-arm/syscalls/getuid.S
 syscall_src += arch-arm/syscalls/getgid.S
@@ -152,8 +152,8 @@ syscall_src += arch-arm/syscalls/timerfd_create.S
 syscall_src += arch-arm/syscalls/timerfd_settime.S
 syscall_src += arch-arm/syscalls/timerfd_gettime.S
 syscall_src += arch-arm/syscalls/sigaction.S
-syscall_src += arch-arm/syscalls/sigpending.S
 syscall_src += arch-arm/syscalls/__rt_sigaction.S
+syscall_src += arch-arm/syscalls/__rt_sigpending.S
 syscall_src += arch-arm/syscalls/__rt_sigprocmask.S
 syscall_src += arch-arm/syscalls/__rt_sigsuspend.S
 syscall_src += arch-arm/syscalls/__rt_sigtimedwait.S
diff --git a/libc/arch-arm/syscalls/sigpending.S b/libc/arch-arm/syscalls/__rt_sigpending.S
similarity index 76%
rename from libc/arch-arm/syscalls/sigpending.S
rename to libc/arch-arm/syscalls/__rt_sigpending.S
index ba667a027..0e0be3a3d 100644
--- a/libc/arch-arm/syscalls/sigpending.S
+++ b/libc/arch-arm/syscalls/__rt_sigpending.S
@@ -3,13 +3,13 @@
 #include <linux/err.h>
 #include <machine/asm.h>
 
-ENTRY(sigpending)
+ENTRY(__rt_sigpending)
     mov     ip, r7
-    ldr     r7, =__NR_sigpending
+    ldr     r7, =__NR_rt_sigpending
     swi     #0
     mov     r7, ip
     cmn     r0, #(MAX_ERRNO + 1)
     bxls    lr
     neg     r0, r0
     b       __set_errno
-END(sigpending)
+END(__rt_sigpending)
diff --git a/libc/arch-mips/syscalls.mk b/libc/arch-mips/syscalls.mk
index 2704200ea..7d99dad7b 100644
--- a/libc/arch-mips/syscalls.mk
+++ b/libc/arch-mips/syscalls.mk
@@ -3,10 +3,10 @@ syscall_src :=
 syscall_src += arch-mips/syscalls/_exit.S
 syscall_src += arch-mips/syscalls/_exit_thread.S
 syscall_src += arch-mips/syscalls/__fork.S
-syscall_src += arch-mips/syscalls/_waitpid.S
-syscall_src += arch-mips/syscalls/__waitid.S
 syscall_src += arch-mips/syscalls/wait4.S
 syscall_src += arch-mips/syscalls/__sys_clone.S
+syscall_src += arch-mips/syscalls/_waitpid.S
+syscall_src += arch-mips/syscalls/__waitid.S
 syscall_src += arch-mips/syscalls/execve.S
 syscall_src += arch-mips/syscalls/getuid.S
 syscall_src += arch-mips/syscalls/getgid.S
@@ -155,8 +155,8 @@ syscall_src += arch-mips/syscalls/timerfd_create.S
 syscall_src += arch-mips/syscalls/timerfd_settime.S
 syscall_src += arch-mips/syscalls/timerfd_gettime.S
 syscall_src += arch-mips/syscalls/sigaction.S
-syscall_src += arch-mips/syscalls/sigpending.S
 syscall_src += arch-mips/syscalls/__rt_sigaction.S
+syscall_src += arch-mips/syscalls/__rt_sigpending.S
 syscall_src += arch-mips/syscalls/__rt_sigprocmask.S
 syscall_src += arch-mips/syscalls/__rt_sigsuspend.S
 syscall_src += arch-mips/syscalls/__rt_sigtimedwait.S
diff --git a/libc/arch-mips/syscalls/sigpending.S b/libc/arch-mips/syscalls/__rt_sigpending.S
similarity index 66%
rename from libc/arch-mips/syscalls/sigpending.S
rename to libc/arch-mips/syscalls/__rt_sigpending.S
index 45baa4f64..bd4a96e60 100644
--- a/libc/arch-mips/syscalls/sigpending.S
+++ b/libc/arch-mips/syscalls/__rt_sigpending.S
@@ -1,14 +1,14 @@
 /* autogenerated by gensyscalls.py */
 #include <asm/unistd.h>
     .text
-    .globl sigpending
+    .globl __rt_sigpending
     .align 4
-    .ent sigpending
+    .ent __rt_sigpending
 
-sigpending:
+__rt_sigpending:
     .set noreorder
     .cpload $t9
-    li $v0, __NR_sigpending
+    li $v0, __NR_rt_sigpending
     syscall
     bnez $a3, 1f
     move $a0, $v0
@@ -19,4 +19,4 @@ sigpending:
     j $t9
     nop
     .set reorder
-    .end sigpending
+    .end __rt_sigpending
diff --git a/libc/arch-x86/syscalls.mk b/libc/arch-x86/syscalls.mk
index 10970a6f5..698f6f5a6 100644
--- a/libc/arch-x86/syscalls.mk
+++ b/libc/arch-x86/syscalls.mk
@@ -3,10 +3,10 @@ syscall_src :=
 syscall_src += arch-x86/syscalls/_exit.S
 syscall_src += arch-x86/syscalls/_exit_thread.S
 syscall_src += arch-x86/syscalls/__fork.S
-syscall_src += arch-x86/syscalls/_waitpid.S
-syscall_src += arch-x86/syscalls/__waitid.S
 syscall_src += arch-x86/syscalls/wait4.S
 syscall_src += arch-x86/syscalls/__sys_clone.S
+syscall_src += arch-x86/syscalls/_waitpid.S
+syscall_src += arch-x86/syscalls/__waitid.S
 syscall_src += arch-x86/syscalls/execve.S
 syscall_src += arch-x86/syscalls/getuid.S
 syscall_src += arch-x86/syscalls/getgid.S
@@ -156,8 +156,8 @@ syscall_src += arch-x86/syscalls/timerfd_create.S
 syscall_src += arch-x86/syscalls/timerfd_settime.S
 syscall_src += arch-x86/syscalls/timerfd_gettime.S
 syscall_src += arch-x86/syscalls/sigaction.S
-syscall_src += arch-x86/syscalls/sigpending.S
 syscall_src += arch-x86/syscalls/__rt_sigaction.S
+syscall_src += arch-x86/syscalls/__rt_sigpending.S
 syscall_src += arch-x86/syscalls/__rt_sigprocmask.S
 syscall_src += arch-x86/syscalls/__rt_sigsuspend.S
 syscall_src += arch-x86/syscalls/__rt_sigtimedwait.S
diff --git a/libc/arch-x86/syscalls/sigpending.S b/libc/arch-x86/syscalls/__rt_sigpending.S
similarity index 65%
rename from libc/arch-x86/syscalls/sigpending.S
rename to libc/arch-x86/syscalls/__rt_sigpending.S
index 70c3ec4e3..84634b495 100644
--- a/libc/arch-x86/syscalls/sigpending.S
+++ b/libc/arch-x86/syscalls/__rt_sigpending.S
@@ -3,10 +3,12 @@
 #include <linux/err.h>
 #include <machine/asm.h>
 
-ENTRY(sigpending)
+ENTRY(__rt_sigpending)
     pushl   %ebx
-    mov     8(%esp), %ebx
-    movl    $__NR_sigpending, %eax
+    pushl   %ecx
+    mov     12(%esp), %ebx
+    mov     16(%esp), %ecx
+    movl    $__NR_rt_sigpending, %eax
     int     $0x80
     cmpl    $-MAX_ERRNO, %eax
     jb      1f
@@ -16,6 +18,7 @@ ENTRY(sigpending)
     addl    $4, %esp
     orl     $-1, %eax
 1:
+    popl    %ecx
     popl    %ebx
     ret
-END(sigpending)
+END(__rt_sigpending)
diff --git a/libc/arch-x86_64/syscalls.mk b/libc/arch-x86_64/syscalls.mk
index 6b72ca0b1..611bb35dd 100644
--- a/libc/arch-x86_64/syscalls.mk
+++ b/libc/arch-x86_64/syscalls.mk
@@ -3,9 +3,9 @@ syscall_src :=
 syscall_src += arch-x86_64/syscalls/_exit.S
 syscall_src += arch-x86_64/syscalls/_exit_thread.S
 syscall_src += arch-x86_64/syscalls/__fork.S
-syscall_src += arch-x86_64/syscalls/__waitid.S
 syscall_src += arch-x86_64/syscalls/wait4.S
 syscall_src += arch-x86_64/syscalls/__sys_clone.S
+syscall_src += arch-x86_64/syscalls/__waitid.S
 syscall_src += arch-x86_64/syscalls/execve.S
 syscall_src += arch-x86_64/syscalls/getuid.S
 syscall_src += arch-x86_64/syscalls/getgid.S
@@ -150,6 +150,7 @@ syscall_src += arch-x86_64/syscalls/timerfd_create.S
 syscall_src += arch-x86_64/syscalls/timerfd_settime.S
 syscall_src += arch-x86_64/syscalls/timerfd_gettime.S
 syscall_src += arch-x86_64/syscalls/__rt_sigaction.S
+syscall_src += arch-x86_64/syscalls/__rt_sigpending.S
 syscall_src += arch-x86_64/syscalls/__rt_sigprocmask.S
 syscall_src += arch-x86_64/syscalls/__rt_sigsuspend.S
 syscall_src += arch-x86_64/syscalls/__rt_sigtimedwait.S
diff --git a/libc/arch-x86_64/syscalls/__rt_sigpending.S b/libc/arch-x86_64/syscalls/__rt_sigpending.S
new file mode 100644
index 000000000..ecf197162
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/__rt_sigpending.S
@@ -0,0 +1,17 @@
+/* autogenerated by gensyscalls.py */
+#include <asm/unistd.h>
+#include <linux/err.h>
+#include <machine/asm.h>
+
+ENTRY(__rt_sigpending)
+    movl    $__NR_rt_sigpending, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno
+    orq     $-1, %rax
+1:
+    ret
+END(__rt_sigpending)
diff --git a/libc/bionic/sigpending.cpp b/libc/bionic/sigpending.cpp
new file mode 100644
index 000000000..b6e503c56
--- /dev/null
+++ b/libc/bionic/sigpending.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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>
+
+#include "private/kernel_sigset_t.h"
+
+extern "C" int __rt_sigpending(const kernel_sigset_t*, size_t);
+
+int sigpending(sigset_t* bionic_set) {
+  kernel_sigset_t set;
+  int result = __rt_sigpending(&set, sizeof(set));
+  if (result != -1) {
+    *bionic_set = set.bionic;
+  }
+  return result;
+}
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 15d2d3a68..e211ef758 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -122,24 +122,20 @@ static __inline__ __sighandler_t signal(int s, __sighandler_t f)
     return bsd_signal(s,f);
 }
 
-/* the syscall itself */
-extern __sighandler_t __signal(int, __sighandler_t, int);
-
-extern int sigprocmask(int, const sigset_t *, sigset_t *);
-extern int sigaction(int, const struct sigaction *, struct sigaction *);
-
-extern int sigpending(sigset_t *);
-extern int sigsuspend(const sigset_t *);
-extern int sigwait(const sigset_t *set, int *sig);
-extern int siginterrupt(int  sig, int  flag);
+extern int sigaction(int, const struct sigaction*, struct sigaction*);
+extern int siginterrupt(int, 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));
+extern int sigwait(const sigset_t*, int*) __nonnull((1, 2));
 
 extern int raise(int);
 extern int kill(pid_t, int);
-extern int killpg(int pgrp, int sig);
-extern int sigaltstack(const stack_t *ss, stack_t *oss);
+extern int killpg(int, int);
+extern int sigaltstack(const stack_t*, stack_t*);
 
-extern void psiginfo(const siginfo_t* si, const char* message);
-extern void psignal(int signal_number, const char* message);
+extern void psiginfo(const siginfo_t*, const char*);
+extern void psignal(int, const char*);
 
 __END_DECLS
 
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 70e9017cd..a719fe786 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -19,6 +19,28 @@
 #include <errno.h>
 #include <signal.h>
 
+static size_t SIGNAL_MIN() {
+  return 1; // Signals start at 1 (SIGHUP), not 0.
+}
+
+static size_t SIGNAL_MAX() {
+  size_t result = SIGRTMAX;
+
+#if defined(__BIONIC__) && !defined(__mips__) && !defined(__LP64__)
+  // 32-bit bionic's sigset_t is too small for ARM and x86: 32 bits instead of 64.
+  // This means you can't refer to any of the real-time signals.
+  // See http://b/3038348 and http://b/5828899.
+  result = 32;
+#else
+  // Otherwise, C libraries should be perfectly capable of using their largest signal.
+  if (sizeof(sigset_t) * 8 < static_cast<size_t>(SIGRTMAX)) {
+    abort();
+  }
+#endif
+
+  return result;
+}
+
 template <typename Fn>
 static void TestSigSet1(Fn fn) {
   // NULL sigset_t*.
@@ -45,19 +67,6 @@ static void TestSigSet2(Fn fn) {
   sigset_t set;
   sigemptyset(&set);
 
-  int min_signal = SIGHUP;
-  int max_signal = SIGRTMAX;
-
-#if defined(__BIONIC__) && !defined(__mips__)
-  // bionic's sigset_t is too small for ARM and x86: 32 bits instead of 64.
-  // This means you can't refer to any of the real-time signals.
-  // See http://b/3038348 and http://b/5828899.
-  max_signal = 32;
-#else
-  // Other C libraries (or bionic for MIPS) are perfectly capable of using their largest signal.
-  ASSERT_GE(sizeof(sigset_t) * 8, static_cast<size_t>(SIGRTMAX));
-#endif
-
   // Bad signal number: too small.
   errno = 0;
   ASSERT_EQ(-1, fn(&set, 0));
@@ -65,14 +74,14 @@ static void TestSigSet2(Fn fn) {
 
   // Bad signal number: too high.
   errno = 0;
-  ASSERT_EQ(-1, fn(&set, max_signal + 1));
+  ASSERT_EQ(-1, fn(&set, SIGNAL_MAX() + 1));
   ASSERT_EQ(EINVAL, errno);
 
   // Good signal numbers, low and high ends of range.
   errno = 0;
-  ASSERT_EQ(0, fn(&set, min_signal));
+  ASSERT_EQ(0, fn(&set, SIGNAL_MIN()));
   ASSERT_EQ(0, errno);
-  ASSERT_EQ(0, fn(&set, max_signal));
+  ASSERT_EQ(0, fn(&set, SIGNAL_MAX()));
   ASSERT_EQ(0, errno);
 }
 
@@ -160,7 +169,7 @@ static void SigSuspendTestHelper(int) {
   ++gSigSuspendTestHelperCallCount;
 }
 
-TEST(signal, sigsuspend) {
+TEST(signal, sigsuspend_sigpending) {
   ScopedSignalHandler ssh(SIGALRM, SigSuspendTestHelper);
 
   // Block SIGALRM.
@@ -170,10 +179,25 @@ TEST(signal, sigsuspend) {
   sigset_t original_set;
   ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, &original_set));
 
+  // There should be no pending signals.
+  sigset_t pending;
+  sigemptyset(&pending);
+  ASSERT_EQ(0, sigpending(&pending));
+  for (size_t i = SIGNAL_MIN(); i <= SIGNAL_MAX(); ++i) {
+    EXPECT_FALSE(sigismember(&pending, i)) << i;
+  }
+
   // Raise SIGALRM and check our signal handler wasn't called.
   raise(SIGALRM);
   ASSERT_EQ(0, gSigSuspendTestHelperCallCount);
 
+  // We should now have a pending SIGALRM but nothing else.
+  sigemptyset(&pending);
+  ASSERT_EQ(0, sigpending(&pending));
+  for (size_t i = SIGNAL_MIN(); i <= SIGNAL_MAX(); ++i) {
+    EXPECT_EQ((i == SIGALRM), sigismember(&pending, i));
+  }
+
   // Use sigsuspend to block everything except SIGALRM...
   sigset_t not_SIGALRM;
   sigfillset(&not_SIGALRM);