support _POSIX_REALTIME_SIGNALS
Bug: 18489947
Change-Id: I2e834d68bc10ca5fc7ebde047b517a3074179475
diff --git a/libc/Android.mk b/libc/Android.mk
index ef1fb9b..90c2e92 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -201,8 +201,11 @@
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 \
diff --git a/libc/SYSCALLS.TXT b/libc/SYSCALLS.TXT
index 39ff37d..35558c9 100644
--- a/libc/SYSCALLS.TXT
+++ b/libc/SYSCALLS.TXT
@@ -223,6 +223,7 @@
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
index 0000000..c823cee
--- /dev/null
+++ b/libc/arch-arm/syscalls/__rt_sigqueueinfo.S
@@ -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
index 0000000..2b23e18
--- /dev/null
+++ b/libc/arch-arm64/syscalls/__rt_sigqueueinfo.S
@@ -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
index 0000000..a978bc4
--- /dev/null
+++ b/libc/arch-mips/syscalls/__rt_sigqueueinfo.S
@@ -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
index 0000000..e97aeba
--- /dev/null
+++ b/libc/arch-mips64/syscalls/__rt_sigqueueinfo.S
@@ -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
index 0000000..4152100
--- /dev/null
+++ b/libc/arch-x86/syscalls/__rt_sigqueueinfo.S
@@ -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
index 0000000..52b6863
--- /dev/null
+++ b/libc/arch-x86_64/syscalls/__rt_sigqueueinfo.S
@@ -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
index 0000000..39c8798
--- /dev/null
+++ b/libc/bionic/sigqueue.cpp
@@ -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
index 0000000..c29f806
--- /dev/null
+++ b/libc/bionic/sigtimedwait.cpp
@@ -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
index 0000000..43e2395
--- /dev/null
+++ b/libc/bionic/sigwaitinfo.cpp
@@ -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);
+}
diff --git a/libc/include/machine/posix_limits.h b/libc/include/machine/posix_limits.h
index e5a299b..073d0df 100644
--- a/libc/include/machine/posix_limits.h
+++ b/libc/include/machine/posix_limits.h
@@ -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 */
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 6d89ef7..867f497 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -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 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_ */
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);