support _POSIX_REALTIME_SIGNALS
authorYabin Cui <yabinc@google.com>
Tue, 2 Dec 2014 01:41:04 +0000 (17:41 -0800)
committerYabin Cui <yabinc@google.com>
Tue, 9 Dec 2014 05:52:43 +0000 (21:52 -0800)
Bug: 18489947
Change-Id: I2e834d68bc10ca5fc7ebde047b517a3074179475

17 files changed:
libc/Android.mk
libc/SYSCALLS.TXT
libc/arch-arm/syscalls/__rt_sigqueueinfo.S [new file with mode: 0644]
libc/arch-arm64/syscalls/__rt_sigqueueinfo.S [new file with mode: 0644]
libc/arch-mips/syscalls/__rt_sigqueueinfo.S [new file with mode: 0644]
libc/arch-mips64/syscalls/__rt_sigqueueinfo.S [new file with mode: 0644]
libc/arch-x86/syscalls/__rt_sigqueueinfo.S [new file with mode: 0644]
libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S [new file with mode: 0644]
libc/bionic/sigqueue.cpp [new file with mode: 0644]
libc/bionic/sigtimedwait.cpp [new file with mode: 0644]
libc/bionic/sigwaitinfo.cpp [new file with mode: 0644]
libc/include/machine/posix_limits.h
libc/include/signal.h
tests/ScopedSignalHandler.h
tests/pthread_test.cpp
tests/signal_test.cpp
tests/unistd_test.cpp

index ef1fb9be6e65dc49d244b5bfccc4059b732d9817..90c2e9260340f3cd21daf5b96f988ab05629631b 100644 (file)
@@ -201,8 +201,11 @@ libc_bionic_src_files := \
     bionic/signalfd.cpp \
     bionic/sigpending.cpp \
     bionic/sigprocmask.cpp \
+    bionic/sigqueue.cpp \
     bionic/sigsuspend.cpp \
+    bionic/sigtimedwait.cpp \
     bionic/sigwait.cpp \
+    bionic/sigwaitinfo.cpp \
     bionic/socket.cpp \
     bionic/stat.cpp \
     bionic/statvfs.cpp \
index 39ff37de0e387a64ce4a948961689f5a5e912e48..35558c994fcc224a053f616ac8614eabe3a046b3 100644 (file)
@@ -223,6 +223,7 @@ 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
+int     __rt_sigqueueinfo:rt_sigqueueinfo(pid_t, int, siginfo_t*)  all
 int     __signalfd4:signalfd4(int, const sigset_t*, size_t, int)  all
 
 # sockets
diff --git a/libc/arch-arm/syscalls/__rt_sigqueueinfo.S b/libc/arch-arm/syscalls/__rt_sigqueueinfo.S
new file mode 100644 (file)
index 0000000..c823cee
--- /dev/null
@@ -0,0 +1,14 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(__rt_sigqueueinfo)
+    mov     ip, r7
+    ldr     r7, =__NR_rt_sigqueueinfo
+    swi     #0
+    mov     r7, ip
+    cmn     r0, #(MAX_ERRNO + 1)
+    bxls    lr
+    neg     r0, r0
+    b       __set_errno_internal
+END(__rt_sigqueueinfo)
diff --git a/libc/arch-arm64/syscalls/__rt_sigqueueinfo.S b/libc/arch-arm64/syscalls/__rt_sigqueueinfo.S
new file mode 100644 (file)
index 0000000..2b23e18
--- /dev/null
@@ -0,0 +1,15 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(__rt_sigqueueinfo)
+    mov     x8, __NR_rt_sigqueueinfo
+    svc     #0
+
+    cmn     x0, #(MAX_ERRNO + 1)
+    cneg    x0, x0, hi
+    b.hi    __set_errno_internal
+
+    ret
+END(__rt_sigqueueinfo)
+.hidden __rt_sigqueueinfo
diff --git a/libc/arch-mips/syscalls/__rt_sigqueueinfo.S b/libc/arch-mips/syscalls/__rt_sigqueueinfo.S
new file mode 100644 (file)
index 0000000..a978bc4
--- /dev/null
@@ -0,0 +1,19 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(__rt_sigqueueinfo)
+    .set noreorder
+    .cpload t9
+    li v0, __NR_rt_sigqueueinfo
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    la t9,__set_errno_internal
+    j t9
+    nop
+    .set reorder
+END(__rt_sigqueueinfo)
diff --git a/libc/arch-mips64/syscalls/__rt_sigqueueinfo.S b/libc/arch-mips64/syscalls/__rt_sigqueueinfo.S
new file mode 100644 (file)
index 0000000..e97aeba
--- /dev/null
@@ -0,0 +1,26 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(__rt_sigqueueinfo)
+    .set push
+    .set noreorder
+    li v0, __NR_rt_sigqueueinfo
+    syscall
+    bnez a3, 1f
+    move a0, v0
+    j ra
+    nop
+1:
+    move t0, ra
+    bal     2f
+    nop
+2:
+    .cpsetup ra, t1, 2b
+    LA t9,__set_errno_internal
+    .cpreturn
+    j t9
+    move ra, t0
+    .set pop
+END(__rt_sigqueueinfo)
+.hidden __rt_sigqueueinfo
diff --git a/libc/arch-x86/syscalls/__rt_sigqueueinfo.S b/libc/arch-x86/syscalls/__rt_sigqueueinfo.S
new file mode 100644 (file)
index 0000000..4152100
--- /dev/null
@@ -0,0 +1,31 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(__rt_sigqueueinfo)
+    pushl   %ebx
+    .cfi_def_cfa_offset 8
+    .cfi_rel_offset ebx, 0
+    pushl   %ecx
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset ecx, 0
+    pushl   %edx
+    .cfi_adjust_cfa_offset 4
+    .cfi_rel_offset edx, 0
+    mov     16(%esp), %ebx
+    mov     20(%esp), %ecx
+    mov     24(%esp), %edx
+    movl    $__NR_rt_sigqueueinfo, %eax
+    int     $0x80
+    cmpl    $-MAX_ERRNO, %eax
+    jb      1f
+    negl    %eax
+    pushl   %eax
+    call    __set_errno_internal
+    addl    $4, %esp
+1:
+    popl    %edx
+    popl    %ecx
+    popl    %ebx
+    ret
+END(__rt_sigqueueinfo)
diff --git a/libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S b/libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S
new file mode 100644 (file)
index 0000000..52b6863
--- /dev/null
@@ -0,0 +1,16 @@
+/* Generated by gensyscalls.py. Do not edit. */
+
+#include <private/bionic_asm.h>
+
+ENTRY(__rt_sigqueueinfo)
+    movl    $__NR_rt_sigqueueinfo, %eax
+    syscall
+    cmpq    $-MAX_ERRNO, %rax
+    jb      1f
+    negl    %eax
+    movl    %eax, %edi
+    call    __set_errno_internal
+1:
+    ret
+END(__rt_sigqueueinfo)
+.hidden __rt_sigqueueinfo
diff --git a/libc/bionic/sigqueue.cpp b/libc/bionic/sigqueue.cpp
new file mode 100644 (file)
index 0000000..39c8798
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 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 <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+extern "C" int __rt_sigqueueinfo(pid_t, int, siginfo_t*);
+
+int sigqueue(pid_t pid, int signo, const sigval value) {
+  siginfo_t info;
+  memset(&info, 0, sizeof(siginfo_t));
+  info.si_signo = signo;
+  info.si_code = SI_QUEUE;
+  info.si_pid = getpid();
+  info.si_uid = getuid();
+  info.si_value = value;
+
+  return __rt_sigqueueinfo(pid, signo, &info);
+}
diff --git a/libc/bionic/sigtimedwait.cpp b/libc/bionic/sigtimedwait.cpp
new file mode 100644 (file)
index 0000000..c29f806
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 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_sigtimedwait(const sigset_t*, siginfo_t*, const timespec*, size_t);
+
+int sigtimedwait(const sigset_t* set, siginfo_t* info, const timespec* timeout) {
+  kernel_sigset_t sigset(set);
+  return __rt_sigtimedwait(sigset.get(), info, timeout, sizeof(sigset));
+}
diff --git a/libc/bionic/sigwaitinfo.cpp b/libc/bionic/sigwaitinfo.cpp
new file mode 100644 (file)
index 0000000..43e2395
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 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>
+
+int sigwaitinfo(const sigset_t* set, siginfo_t* info) {
+  return sigtimedwait(set, info, NULL);
+}
index e5a299bc639c2bf62dfe4a548bd7cfb35ddd4260..073d0df357ffdd02166411f96b2e0f077bfd819d 100644 (file)
@@ -69,7 +69,7 @@
 #define _POSIX_PRIORITIZED_IO       -1  /* not implemented */
 #define _POSIX_RAW_SOCKETS          200809L
 #define _POSIX_READER_WRITER_LOCKS  200809L
-#define _POSIX_REALTIME_SIGNALS     -1 /* for now, this is not supported */
+#define _POSIX_REALTIME_SIGNALS     200809L
 #define _POSIX_REGEXP               1
 #define _POSIX_RE_DUP_MAX           255
 #define _POSIX_SAVED_IDS            1  /* saved user ids is a Linux feature */
index 6d89ef7d0f054e15f16f3c208d596ae0c2341117..867f497489baceb8555ee00f1aa9e1006cdabf6e 100644 (file)
@@ -32,6 +32,7 @@
 #include <asm/sigcontext.h>
 #include <errno.h>
 #include <limits.h>
+#include <linux/time.h>
 #include <machine/pthread_types.h>
 #include <string.h>
 #include <sys/cdefs.h>
@@ -133,6 +134,10 @@ extern void psignal(int, const char*);
 extern int pthread_kill(pthread_t, int);
 extern int pthread_sigmask(int, const sigset_t*, sigset_t*);
 
+extern int sigqueue(pid_t, int, const union sigval);
+extern int sigtimedwait(const sigset_t*, siginfo_t*, const struct timespec*);
+extern int sigwaitinfo(const sigset_t*, siginfo_t*);
+
 __END_DECLS
 
 #endif /* _SIGNAL_H_ */
index 3ec23b0d8b21bbc10c9eda016ac84ce57edf288b..3fb60a16404f37ff7bc2a9ad9ae0d8bf5931c270 100644 (file)
 #define _BIONIC_TESTS_SCOPED_SIGNAL_HANDLER_H
 
 #include <signal.h>
+#include <string.h>
 
 class ScopedSignalHandler {
  public:
   ScopedSignalHandler(int signal_number, void (*handler)(int), int sa_flags = 0)
       : signal_number_(signal_number) {
-    sigemptyset(&action_.sa_mask);
+    memset(&action_, 0, sizeof(action_));
     action_.sa_flags = sa_flags;
     action_.sa_handler = handler;
     sigaction(signal_number_, &action_, &old_action_);
   }
 
+  ScopedSignalHandler(int signal_number, void (*action)(int, siginfo_t*, void*),
+                      int sa_flags = SA_SIGINFO)
+      : signal_number_(signal_number) {
+    memset(&action_, 0, sizeof(action_));
+    action_.sa_flags = sa_flags;
+    action_.sa_sigaction = action;
+    sigaction(signal_number_, &action_, &old_action_);
+  }
+
   ~ScopedSignalHandler() {
     sigaction(signal_number_, &old_action_, NULL);
   }
index 797468efe430b050c6083b03e8366f3572714bda..f63d1ee93e79a7eac2e1ed5bee48a190836be465 100644 (file)
@@ -178,17 +178,34 @@ static void* IdFn(void* arg) {
   return arg;
 }
 
-static void* SleepFn(void* arg) {
-  sleep(reinterpret_cast<uintptr_t>(arg));
-  return NULL;
-}
+class SpinFunctionHelper {
+ public:
+  SpinFunctionHelper() {
+    SpinFunctionHelper::spin_flag_ = true;
+  }
+  ~SpinFunctionHelper() {
+    UnSpin();
+  }
+  auto GetFunction() -> void* (*)(void*) {
+    return SpinFunctionHelper::SpinFn;
+  }
 
-static void* SpinFn(void* arg) {
-  volatile bool* b = reinterpret_cast<volatile bool*>(arg);
-  while (!*b) {
+  void UnSpin() {
+    SpinFunctionHelper::spin_flag_ = false;
   }
-  return NULL;
-}
+
+ private:
+  static void* SpinFn(void*) {
+    while (spin_flag_) {}
+    return NULL;
+  }
+  static volatile bool spin_flag_;
+};
+
+// It doesn't matter if spin_flag_ is used in several tests,
+// because it is always set to false after each test. Each thread
+// loops on spin_flag_ can find it becomes false at some time.
+volatile bool SpinFunctionHelper::spin_flag_ = false;
 
 static void* JoinFn(void* arg) {
   return reinterpret_cast<void*>(pthread_join(reinterpret_cast<pthread_t>(arg), NULL));
@@ -229,8 +246,10 @@ TEST(pthread, pthread_create_EAGAIN) {
 }
 
 TEST(pthread, pthread_no_join_after_detach) {
+  SpinFunctionHelper spinhelper;
+
   pthread_t t1;
-  ASSERT_EQ(0, pthread_create(&t1, NULL, SleepFn, reinterpret_cast<void*>(5)));
+  ASSERT_EQ(0, pthread_create(&t1, NULL, spinhelper.GetFunction(), NULL));
 
   // After a pthread_detach...
   ASSERT_EQ(0, pthread_detach(t1));
@@ -241,10 +260,10 @@ TEST(pthread, pthread_no_join_after_detach) {
 }
 
 TEST(pthread, pthread_no_op_detach_after_join) {
-  bool done = false;
+  SpinFunctionHelper spinhelper;
 
   pthread_t t1;
-  ASSERT_EQ(0, pthread_create(&t1, NULL, SpinFn, &done));
+  ASSERT_EQ(0, pthread_create(&t1, NULL, spinhelper.GetFunction(), NULL));
 
   // If thread 2 is already waiting to join thread 1...
   pthread_t t2;
@@ -256,7 +275,7 @@ TEST(pthread, pthread_no_op_detach_after_join) {
   ASSERT_EQ(0, pthread_detach(t1));
   AssertDetached(t1, false);
 
-  done = true;
+  spinhelper.UnSpin();
 
   // ...but t2's join on t1 still goes ahead (which we can tell because our join on t2 finishes).
   void* join_result;
@@ -369,8 +388,10 @@ TEST(pthread, pthread_setname_np__self) {
 }
 
 TEST(pthread, pthread_setname_np__other) {
+  SpinFunctionHelper spinhelper;
+
   pthread_t t1;
-  ASSERT_EQ(0, pthread_create(&t1, NULL, SleepFn, reinterpret_cast<void*>(5)));
+  ASSERT_EQ(0, pthread_create(&t1, NULL, spinhelper.GetFunction(), NULL));
   ASSERT_EQ(0, pthread_setname_np(t1, "short 2"));
 }
 
@@ -451,8 +472,10 @@ TEST(pthread, pthread_detach__leak) {
 }
 
 TEST(pthread, pthread_getcpuclockid__clock_gettime) {
+  SpinFunctionHelper spinhelper;
+
   pthread_t t;
-  ASSERT_EQ(0, pthread_create(&t, NULL, SleepFn, reinterpret_cast<void*>(5)));
+  ASSERT_EQ(0, pthread_create(&t, NULL, spinhelper.GetFunction(), NULL));
 
   clockid_t c;
   ASSERT_EQ(0, pthread_getcpuclockid(t, &c));
@@ -501,10 +524,10 @@ TEST(pthread, pthread_kill__no_such_thread) {
 }
 
 TEST(pthread, pthread_join__multijoin) {
-  bool done = false;
+  SpinFunctionHelper spinhelper;
 
   pthread_t t1;
-  ASSERT_EQ(0, pthread_create(&t1, NULL, SpinFn, &done));
+  ASSERT_EQ(0, pthread_create(&t1, NULL, spinhelper.GetFunction(), NULL));
 
   pthread_t t2;
   ASSERT_EQ(0, pthread_create(&t2, NULL, JoinFn, reinterpret_cast<void*>(t1)));
@@ -514,7 +537,7 @@ TEST(pthread, pthread_join__multijoin) {
   // Multiple joins to the same thread should fail.
   ASSERT_EQ(EINVAL, pthread_join(t1, NULL));
 
-  done = true;
+  spinhelper.UnSpin();
 
   // ...but t2's join on t1 still goes ahead (which we can tell because our join on t2 finishes).
   void* join_result;
index 8fd8b72f7128dce4f6675c91385086e13e22cd0d..f8fdc3f99b2342fc6eb374d412df11cc5274fa65 100644 (file)
 
 #include <signal.h>
 
-#include <errno.h>
 #include <gtest/gtest.h>
 
+#include <errno.h>
+
 #include "ScopedSignalHandler.h"
 
 static size_t SIGNAL_MIN() {
@@ -276,3 +277,101 @@ TEST(signal, limits) {
   // We don't currently reserve any at the top.
   ASSERT_EQ(SIGRTMAX, __SIGRTMAX);
 }
+
+static int g_sigqueue_signal_handler_call_count = 0;
+
+static void SigqueueSignalHandler(int signum, siginfo_t* info, void*) {
+  ASSERT_EQ(SIGALRM, signum);
+  ASSERT_EQ(SIGALRM, info->si_signo);
+  ASSERT_EQ(SI_QUEUE, info->si_code);
+  ASSERT_EQ(1, info->si_value.sival_int);
+  ++g_sigqueue_signal_handler_call_count;
+}
+
+TEST(signal, sigqueue) {
+  ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler, SA_SIGINFO);
+  sigval_t sigval;
+  sigval.sival_int = 1;
+  errno = 0;
+  ASSERT_EQ(0, sigqueue(getpid(), SIGALRM, sigval));
+  ASSERT_EQ(0, errno);
+  ASSERT_EQ(1, g_sigqueue_signal_handler_call_count);
+}
+
+TEST(signal, sigwaitinfo) {
+  // Block SIGALRM.
+  sigset_t just_SIGALRM;
+  sigemptyset(&just_SIGALRM);
+  sigaddset(&just_SIGALRM, SIGALRM);
+  sigset_t original_set;
+  ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, &original_set));
+
+  // Raise SIGALRM.
+  sigval_t sigval;
+  sigval.sival_int = 1;
+  ASSERT_EQ(0, sigqueue(getpid(), SIGALRM, sigval));
+
+  // Get pending SIGALRM.
+  siginfo_t info;
+  errno = 0;
+  ASSERT_EQ(SIGALRM, sigwaitinfo(&just_SIGALRM, &info));
+  ASSERT_EQ(0, errno);
+  ASSERT_EQ(SIGALRM, info.si_signo);
+  ASSERT_EQ(1, info.si_value.sival_int);
+
+  ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_set, NULL));
+}
+
+TEST(signal, sigtimedwait) {
+  // Block SIGALRM.
+  sigset_t just_SIGALRM;
+  sigemptyset(&just_SIGALRM);
+  sigaddset(&just_SIGALRM, SIGALRM);
+  sigset_t original_set;
+  ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, &original_set));
+
+  // Raise SIGALRM.
+  sigval_t sigval;
+  sigval.sival_int = 1;
+  ASSERT_EQ(0, sigqueue(getpid(), SIGALRM, sigval));
+
+  // Get pending SIGALRM.
+  siginfo_t info;
+  struct timespec timeout;
+  timeout.tv_sec = 2;
+  timeout.tv_nsec = 0;
+  errno = 0;
+  ASSERT_EQ(SIGALRM, sigtimedwait(&just_SIGALRM, &info, &timeout));
+  ASSERT_EQ(0, errno);
+
+  ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_set, NULL));
+}
+
+static int64_t NanoTime() {
+  struct timespec t;
+  t.tv_sec = t.tv_nsec = 0;
+  clock_gettime(CLOCK_MONOTONIC, &t);
+  return static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
+}
+
+TEST(signal, sigtimedwait_timeout) {
+  // Block SIGALRM.
+  sigset_t just_SIGALRM;
+  sigemptyset(&just_SIGALRM);
+  sigaddset(&just_SIGALRM, SIGALRM);
+  sigset_t original_set;
+  ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, &original_set));
+
+  // Wait timeout.
+  int64_t start_time = NanoTime();
+  siginfo_t info;
+  struct timespec timeout;
+  timeout.tv_sec = 0;
+  timeout.tv_nsec = 1000000;
+  errno = 0;
+  ASSERT_EQ(-1, sigtimedwait(&just_SIGALRM, &info, &timeout));
+  ASSERT_EQ(EAGAIN, errno);
+  ASSERT_GE(NanoTime() - start_time, 1000000);
+
+  ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_set, NULL));
+}
index f0aeb09c95eba1b3ed8d6a0037bb3c509d54183b..433c1b501694af0fd683519ef2999dcfab616c06 100644 (file)
@@ -554,6 +554,7 @@ TEST(unistd, _POSIX_macros_smoke) {
   EXPECT_EQ(_POSIX_VERSION, _POSIX_PRIORITY_SCHEDULING);
   EXPECT_EQ(_POSIX_VERSION, _POSIX_RAW_SOCKETS);
   EXPECT_EQ(_POSIX_VERSION, _POSIX_READER_WRITER_LOCKS);
+  EXPECT_EQ(_POSIX_VERSION, _POSIX_REALTIME_SIGNALS);
   EXPECT_GT(_POSIX_REGEXP, 0);
   EXPECT_GT(_POSIX_RE_DUP_MAX, 0);
   EXPECT_GT(_POSIX_SAVED_IDS, 0);
@@ -617,7 +618,6 @@ TEST(unistd, _POSIX_macros_smoke) {
   EXPECT_EQ(-1, _POSIX_CPUTIME);
   EXPECT_EQ(-1, _POSIX_MESSAGE_PASSING);
   EXPECT_EQ(-1, _POSIX_PRIORITIZED_IO);
-  EXPECT_EQ(-1, _POSIX_REALTIME_SIGNALS);
   EXPECT_EQ(-1, _POSIX_SHARED_MEMORY_OBJECTS);
   EXPECT_EQ(-1, _POSIX_SPAWN);
   EXPECT_EQ(-1, _POSIX_SPIN_LOCKS);
@@ -702,6 +702,7 @@ TEST(unistd, sysconf) {
   VERIFY_SYSCONF_POSIX_VERSION(_SC_MEMLOCK_RANGE);
   VERIFY_SYSCONF_POSIX_VERSION(_SC_MEMORY_PROTECTION);
   VERIFY_SYSCONF_POSIX_VERSION(_SC_PRIORITY_SCHEDULING);
+  VERIFY_SYSCONF_POSIX_VERSION(_SC_REALTIME_SIGNALS);
   VERIFY_SYSCONF_POSIX_VERSION(_SC_SEMAPHORES);
   VERIFY_SYSCONF_POSIX_VERSION(_SC_SYNCHRONIZED_IO);
   VERIFY_SYSCONF_POSIX_VERSION(_SC_TIMERS);
@@ -778,7 +779,6 @@ TEST(unistd, sysconf) {
   VERIFY_SYSCONF_NOT_SUPPORT(_SC_CPUTIME);
   VERIFY_SYSCONF_NOT_SUPPORT(_SC_MESSAGE_PASSING);
   VERIFY_SYSCONF_NOT_SUPPORT(_SC_PRIORITIZED_IO);
-  VERIFY_SYSCONF_NOT_SUPPORT(_SC_REALTIME_SIGNALS);
   VERIFY_SYSCONF_NOT_SUPPORT(_SC_SHARED_MEMORY_OBJECTS);
   VERIFY_SYSCONF_NOT_SUPPORT(_SC_SPAWN);
   VERIFY_SYSCONF_NOT_SUPPORT(_SC_SPIN_LOCKS);