diff --git a/libc/Android.bp b/libc/Android.bp index 61d00cd09..fe65acefa 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -1456,6 +1456,7 @@ cc_library_static { "bionic/pthread_mutex.cpp", "bionic/pthread_once.cpp", "bionic/pthread_rwlock.cpp", + "bionic/pthread_sigqueue.cpp", "bionic/pthread_self.cpp", "bionic/pthread_setname_np.cpp", "bionic/pthread_setschedparam.cpp", diff --git a/libc/bionic/pthread_sigqueue.cpp b/libc/bionic/pthread_sigqueue.cpp new file mode 100644 index 000000000..34bda38c4 --- /dev/null +++ b/libc/bionic/pthread_sigqueue.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 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 +#include +#include +#include +#include + +#include "private/ErrnoRestorer.h" +#include "pthread_internal.h" + +int pthread_sigqueue(pthread_t t, int sig, const union sigval value) { + ErrnoRestorer errno_restorer; + + pid_t tid = pthread_gettid_np(t); + if (tid == -1) return ESRCH; + + siginfo_t siginfo; + siginfo.si_code = SI_QUEUE; + siginfo.si_pid = getpid(); + siginfo.si_uid = getuid(); + siginfo.si_value = value; + + return syscall(__NR_rt_tgsigqueueinfo, getpid(), tid, sig, &siginfo) ? errno : 0; +} diff --git a/libc/include/signal.h b/libc/include/signal.h index 00860d5e6..9d1030ac2 100644 --- a/libc/include/signal.h +++ b/libc/include/signal.h @@ -113,6 +113,10 @@ void psiginfo(const siginfo_t* __info, const char* __msg) __INTRODUCED_IN(17); void psignal(int __signal, const char* __msg) __INTRODUCED_IN(17); int pthread_kill(pthread_t __pthread, int __signal); +#if defined(__USE_GNU) +int pthread_sigqueue(pthread_t __pthread, int __signal, const union sigval __value) __INTRODUCED_IN(__ANDROID_API_Q__); +#endif + int pthread_sigmask(int __how, const sigset_t* __new_set, sigset_t* __old_set); int pthread_sigmask64(int __how, const sigset64_t* __new_set, sigset64_t* __old_set) __INTRODUCED_IN(28); diff --git a/libc/libc.arm.map b/libc/libc.arm.map index f1eec3c6a..8fb07f784 100644 --- a/libc/libc.arm.map +++ b/libc/libc.arm.map @@ -1431,6 +1431,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_tag_value; android_fdsan_get_error_level; android_fdsan_set_error_level; + pthread_sigqueue; timespec_get; } LIBC_P; diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map index 4d538cd64..8c5eb89d4 100644 --- a/libc/libc.arm64.map +++ b/libc/libc.arm64.map @@ -1352,6 +1352,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_tag_value; android_fdsan_get_error_level; android_fdsan_set_error_level; + pthread_sigqueue; timespec_get; } LIBC_P; diff --git a/libc/libc.map.txt b/libc/libc.map.txt index 0f5abc0b9..c5f091076 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1456,6 +1456,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_tag_value; android_fdsan_get_error_level; android_fdsan_set_error_level; + pthread_sigqueue; timespec_get; } LIBC_P; diff --git a/libc/libc.mips.map b/libc/libc.mips.map index f14f73173..fbaf508f6 100644 --- a/libc/libc.mips.map +++ b/libc/libc.mips.map @@ -1415,6 +1415,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_tag_value; android_fdsan_get_error_level; android_fdsan_set_error_level; + pthread_sigqueue; timespec_get; } LIBC_P; diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map index 4d538cd64..8c5eb89d4 100644 --- a/libc/libc.mips64.map +++ b/libc/libc.mips64.map @@ -1352,6 +1352,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_tag_value; android_fdsan_get_error_level; android_fdsan_set_error_level; + pthread_sigqueue; timespec_get; } LIBC_P; diff --git a/libc/libc.x86.map b/libc/libc.x86.map index d44001e68..db86e5511 100644 --- a/libc/libc.x86.map +++ b/libc/libc.x86.map @@ -1413,6 +1413,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_tag_value; android_fdsan_get_error_level; android_fdsan_set_error_level; + pthread_sigqueue; timespec_get; } LIBC_P; diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map index 4d538cd64..8c5eb89d4 100644 --- a/libc/libc.x86_64.map +++ b/libc/libc.x86_64.map @@ -1352,6 +1352,7 @@ LIBC_Q { # introduced=Q android_fdsan_get_tag_value; android_fdsan_get_error_level; android_fdsan_set_error_level; + pthread_sigqueue; timespec_get; } LIBC_P; diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp index cc95ef7b3..52a097bf3 100644 --- a/tests/signal_test.cpp +++ b/tests/signal_test.cpp @@ -597,6 +597,42 @@ TEST(signal, sigqueue) { ASSERT_EQ(1, g_sigqueue_signal_handler_call_count); } +TEST(signal, pthread_sigqueue_self) { + ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler, SA_SIGINFO); + sigval_t sigval; + sigval.sival_int = 1; + errno = 0; + ASSERT_EQ(0, pthread_sigqueue(pthread_self(), SIGALRM, sigval)); + ASSERT_EQ(0, errno); + ASSERT_EQ(1, g_sigqueue_signal_handler_call_count); +} + +TEST(signal, pthread_sigqueue_other) { + ScopedSignalHandler ssh(SIGALRM, SigqueueSignalHandler, SA_SIGINFO); + sigval_t sigval; + sigval.sival_int = 1; + + sigset_t mask; + sigfillset(&mask); + pthread_sigmask(SIG_SETMASK, &mask, nullptr); + pthread_t thread; + int rc = pthread_create(&thread, nullptr, + [](void*) -> void* { + sigset_t mask; + sigemptyset(&mask); + sigsuspend(&mask); + return nullptr; + }, + nullptr); + ASSERT_EQ(0, rc); + + errno = 0; + ASSERT_EQ(0, pthread_sigqueue(thread, SIGALRM, sigval)); + ASSERT_EQ(0, errno); + pthread_join(thread, nullptr); + ASSERT_EQ(1, g_sigqueue_signal_handler_call_count); +} + TEST(signal, sigwaitinfo) { SignalMaskRestorer smr;