support _POSIX_REALTIME_SIGNALS

Bug: 18489947
Change-Id: I2e834d68bc10ca5fc7ebde047b517a3074179475
diff --git a/tests/ScopedSignalHandler.h b/tests/ScopedSignalHandler.h
index 3ec23b0..3fb60a1 100644
--- a/tests/ScopedSignalHandler.h
+++ b/tests/ScopedSignalHandler.h
@@ -18,17 +18,27 @@
 #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);
   }
diff --git a/tests/pthread_test.cpp b/tests/pthread_test.cpp
index 797468e..f63d1ee 100644
--- a/tests/pthread_test.cpp
+++ b/tests/pthread_test.cpp
@@ -178,17 +178,34 @@
   return arg;
 }
 
-static void* SleepFn(void* arg) {
-  sleep(reinterpret_cast<uintptr_t>(arg));
-  return NULL;
-}
-
-static void* SpinFn(void* arg) {
-  volatile bool* b = reinterpret_cast<volatile bool*>(arg);
-  while (!*b) {
+class SpinFunctionHelper {
+ public:
+  SpinFunctionHelper() {
+    SpinFunctionHelper::spin_flag_ = true;
   }
-  return NULL;
-}
+  ~SpinFunctionHelper() {
+    UnSpin();
+  }
+  auto GetFunction() -> void* (*)(void*) {
+    return SpinFunctionHelper::SpinFn;
+  }
+
+  void UnSpin() {
+    SpinFunctionHelper::spin_flag_ = false;
+  }
+
+ 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_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_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 @@
   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__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_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_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 @@
   // 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;
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 8fd8b72..f8fdc3f 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -16,9 +16,10 @@
 
 #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 @@
   // 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));
+}
diff --git a/tests/unistd_test.cpp b/tests/unistd_test.cpp
index f0aeb09..433c1b5 100644
--- a/tests/unistd_test.cpp
+++ b/tests/unistd_test.cpp
@@ -554,6 +554,7 @@
   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 @@
   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 @@
   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 @@
   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);