Merge "Add epoll_pwait2()." into main am: 906d7d41e4 am: 484056aaf2

Original change: https://android-review.googlesource.com/c/platform/bionic/+/2656904

Change-Id: I047cea95ca2b28b781e71fdaf1613ac0abd7cdf4
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Elliott Hughes 2023-09-05 23:30:32 +00:00 committed by Automerger Merge Worker
commit 96a6c6abc1
6 changed files with 167 additions and 8 deletions

View file

@ -64,7 +64,7 @@ New libc functions in V (API level 35):
multi-threaded C). multi-threaded C).
* `mbsrtowcs_l` and `wcsrtombs_l` aliases for `mbsrtowcs` and `wcsrtombs`. * `mbsrtowcs_l` and `wcsrtombs_l` aliases for `mbsrtowcs` and `wcsrtombs`.
* New system call wrappers: `__riscv_flush_icache` (`<sys/cachectl.h>`), * New system call wrappers: `__riscv_flush_icache` (`<sys/cachectl.h>`),
`__riscv_hwprobe` (`<sys/hwprobe.h>`). `__riscv_hwprobe` (`<sys/hwprobe.h>`), `epoll_pwait2`/`epoll_pwait2_64` (`<sys/epoll.h>`).
New libc behavior in V (API level 35): New libc behavior in V (API level 35):
* Added `LD_SHOW_AUXV` to the dynamic linker to dump the ELF auxiliary * Added `LD_SHOW_AUXV` to the dynamic linker to dump the ELF auxiliary

View file

@ -322,6 +322,7 @@ ssize_t vmsplice(int, const struct iovec*, size_t, unsigned int) all
int __epoll_create1:epoll_create1(int) all int __epoll_create1:epoll_create1(int) all
int epoll_ctl(int, int op, int, struct epoll_event*) all int epoll_ctl(int, int op, int, struct epoll_event*) all
int __epoll_pwait:epoll_pwait(int, struct epoll_event*, int, int, const sigset64_t*, size_t) all int __epoll_pwait:epoll_pwait(int, struct epoll_event*, int, int, const sigset64_t*, size_t) all
int __epoll_pwait2:epoll_pwait2(int, struct epoll_event*, int, const timespec64*, const sigset64_t*, size_t) all
int __eventfd:eventfd2(unsigned int, int) all int __eventfd:eventfd2(unsigned int, int) all

View file

@ -34,6 +34,8 @@
extern "C" int __epoll_create1(int flags); extern "C" int __epoll_create1(int flags);
extern "C" int __epoll_pwait(int, epoll_event*, int, int, const sigset64_t*, size_t); extern "C" int __epoll_pwait(int, epoll_event*, int, int, const sigset64_t*, size_t);
extern "C" int __epoll_pwait2(int, epoll_event*, int, const __kernel_timespec*, const sigset64_t*,
size_t);
int epoll_create(int size) { int epoll_create(int size) {
if (size <= 0) { if (size <= 0) {
@ -56,6 +58,31 @@ int epoll_pwait64(int fd, epoll_event* events, int max_events, int timeout, cons
return __epoll_pwait(fd, events, max_events, timeout, ss, sizeof(*ss)); return __epoll_pwait(fd, events, max_events, timeout, ss, sizeof(*ss));
} }
int epoll_pwait2(int fd, epoll_event* events, int max_events, const timespec* timeout,
const sigset_t* ss) {
SigSetConverter set{ss};
return epoll_pwait2_64(fd, events, max_events, timeout, set.ptr);
}
int epoll_pwait2_64(int fd, epoll_event* events, int max_events, const timespec* timeout,
const sigset64_t* ss) {
// epoll_pwait2() is our first syscall that assumes a 64-bit time_t even for
// 32-bit processes, so for ILP32 we need to convert.
// TODO: factor this out into a TimeSpecConverter as/when we get more syscalls like this.
#if __LP64__
const __kernel_timespec* kts_ptr = reinterpret_cast<const __kernel_timespec*>(timeout);
#else
__kernel_timespec kts;
const __kernel_timespec* kts_ptr = nullptr;
if (timeout) {
kts.tv_sec = timeout->tv_sec;
kts.tv_nsec = timeout->tv_nsec;
kts_ptr = &kts;
}
#endif
return __epoll_pwait2(fd, events, max_events, kts_ptr, ss, sizeof(*ss));
}
int epoll_wait(int fd, struct epoll_event* events, int max_events, int timeout) { int epoll_wait(int fd, struct epoll_event* events, int max_events, int timeout) {
return epoll_pwait64(fd, events, max_events, timeout, nullptr); return epoll_pwait64(fd, events, max_events, timeout, nullptr);
} }

View file

@ -26,8 +26,12 @@
* SUCH DAMAGE. * SUCH DAMAGE.
*/ */
#ifndef _SYS_EPOLL_H_ #pragma once
#define _SYS_EPOLL_H_
/**
* @file sys/epoll.h
* @brief I/O event file descriptors.
*/
#include <sys/cdefs.h> #include <sys/cdefs.h>
#include <sys/types.h> #include <sys/types.h>
@ -37,14 +41,67 @@
__BEGIN_DECLS __BEGIN_DECLS
/**
* [epoll_create(2)](http://man7.org/linux/man-pages/man2/epoll_create.2.html)
* creates a new [epoll](http://man7.org/linux/man-pages/man7/epoll.7.html)
* file descriptor.
*
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*/
int epoll_create(int __size); int epoll_create(int __size);
/**
* [epoll_create1(2)](http://man7.org/linux/man-pages/man2/epoll_create1.2.html)
* creates a new [epoll](http://man7.org/linux/man-pages/man7/epoll.7.html)
* file descriptor with the given flags.
*
* Returns a new file descriptor on success and returns -1 and sets `errno` on
* failure.
*/
int epoll_create1(int __flags); int epoll_create1(int __flags);
/**
* [epoll_ctl(2)](http://man7.org/linux/man-pages/man2/epoll_ctl.2.html)
* adds/modifies/removes file descriptors from the given epoll file descriptor.
*
* Returns 0 on success and returns -1 and sets `errno` on failure.
*/
int epoll_ctl(int __epoll_fd, int __op, int __fd, struct epoll_event* __BIONIC_COMPLICATED_NULLNESS __event); int epoll_ctl(int __epoll_fd, int __op, int __fd, struct epoll_event* __BIONIC_COMPLICATED_NULLNESS __event);
/**
* [epoll_wait(2)](http://man7.org/linux/man-pages/man2/epoll_wait.2.html)
* waits for an event on the given epoll file descriptor.
*
* Returns the number of ready file descriptors on success, 0 on timeout,
* or -1 and sets `errno` on failure.
*/
int epoll_wait(int __epoll_fd, struct epoll_event* _Nonnull __events, int __event_count, int __timeout_ms); int epoll_wait(int __epoll_fd, struct epoll_event* _Nonnull __events, int __event_count, int __timeout_ms);
/**
* Like epoll_wait() but atomically applying the given signal mask.
*/
int epoll_pwait(int __epoll_fd, struct epoll_event* _Nonnull __events, int __event_count, int __timeout_ms, const sigset_t* _Nullable __mask); int epoll_pwait(int __epoll_fd, struct epoll_event* _Nonnull __events, int __event_count, int __timeout_ms, const sigset_t* _Nullable __mask);
/**
* Like epoll_pwait() but using a 64-bit signal mask even on 32-bit systems.
*
* Available since API level 28.
*/
int epoll_pwait64(int __epoll_fd, struct epoll_event* _Nonnull __events, int __event_count, int __timeout_ms, const sigset64_t* _Nullable __mask) __INTRODUCED_IN(28); int epoll_pwait64(int __epoll_fd, struct epoll_event* _Nonnull __events, int __event_count, int __timeout_ms, const sigset64_t* _Nullable __mask) __INTRODUCED_IN(28);
__END_DECLS /**
* Like epoll_pwait() but with a `struct timespec` timeout, for nanosecond resolution.
*
* Available since API level 35.
*/
int epoll_pwait2(int __epoll_fd, struct epoll_event* _Nonnull __events, int __event_count, const struct timespec* _Nullable __timeout, const sigset_t* _Nullable __mask) __INTRODUCED_IN(35);
#endif /**
* Like epoll_pwait2() but using a 64-bit signal mask even on 32-bit systems.
*
* Available since API level 35.
*/
int epoll_pwait2_64(int __epoll_fd, struct epoll_event* _Nonnull __events, int __event_count, const struct timespec* _Nullable __timeout, const sigset64_t* _Nullable __mask) __INTRODUCED_IN(35);
__END_DECLS

View file

@ -1586,6 +1586,8 @@ LIBC_U { # introduced=UpsideDownCake
LIBC_V { # introduced=VanillaIceCream LIBC_V { # introduced=VanillaIceCream
global: global:
epoll_pwait2;
epoll_pwait2_64;
localtime_rz; localtime_rz;
mbsrtowcs_l; mbsrtowcs_l;
mktime_z; mktime_z;

View file

@ -24,29 +24,101 @@
#include "utils.h" #include "utils.h"
TEST(sys_epoll, smoke) { TEST(sys_epoll, epoll_wait) {
int epoll_fd = epoll_create(1); int epoll_fd = epoll_create(1);
ASSERT_NE(-1, epoll_fd) << strerror(errno); ASSERT_NE(-1, epoll_fd);
epoll_event events[1];
// Regular epoll_wait. // Regular epoll_wait.
epoll_event events[1] = {};
ASSERT_EQ(0, epoll_wait(epoll_fd, events, 1, 1)); ASSERT_EQ(0, epoll_wait(epoll_fd, events, 1, 1));
}
TEST(sys_epoll, epoll_pwait_no_sigset) {
int epoll_fd = epoll_create(1);
ASSERT_NE(-1, epoll_fd);
// epoll_pwait without a sigset (which is equivalent to epoll_wait). // epoll_pwait without a sigset (which is equivalent to epoll_wait).
epoll_event events[1] = {};
ASSERT_EQ(0, epoll_pwait(epoll_fd, events, 1, 1, nullptr)); ASSERT_EQ(0, epoll_pwait(epoll_fd, events, 1, 1, nullptr));
}
TEST(sys_epoll, epoll_pwait64_no_sigset) {
#if defined(__BIONIC__) #if defined(__BIONIC__)
int epoll_fd = epoll_create(1);
ASSERT_NE(-1, epoll_fd);
// epoll_pwait64 without a sigset (which is equivalent to epoll_wait). // epoll_pwait64 without a sigset (which is equivalent to epoll_wait).
epoll_event events[1] = {};
ASSERT_EQ(0, epoll_pwait64(epoll_fd, events, 1, 1, nullptr)); ASSERT_EQ(0, epoll_pwait64(epoll_fd, events, 1, 1, nullptr));
#else
GTEST_SKIP() << "epoll_pwait64 is bionic-only";
#endif #endif
}
TEST(sys_epoll, epoll_pwait2_no_sigset) {
#if defined(__BIONIC__)
int epoll_fd = epoll_create(1);
ASSERT_NE(-1, epoll_fd);
// epoll_pwait2 without a sigset (which is equivalent to epoll_wait).
epoll_event events[1] = {};
timespec ts = {.tv_nsec = 500};
int rc = epoll_pwait2(epoll_fd, events, 1, &ts, nullptr);
if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2 in this kernel";
ASSERT_EQ(0, rc) << strerror(errno);
#else
GTEST_SKIP() << "epoll_pwait2 is only in glibc 2.35+";
#endif
}
TEST(sys_epoll, epoll_pwait_with_sigset) {
int epoll_fd = epoll_create(1);
ASSERT_NE(-1, epoll_fd);
// epoll_pwait with a sigset. // epoll_pwait with a sigset.
epoll_event events[1] = {};
sigset_t ss; sigset_t ss;
sigemptyset(&ss); sigemptyset(&ss);
sigaddset(&ss, SIGPIPE); sigaddset(&ss, SIGPIPE);
ASSERT_EQ(0, epoll_pwait(epoll_fd, events, 1, 1, &ss)); ASSERT_EQ(0, epoll_pwait(epoll_fd, events, 1, 1, &ss));
} }
TEST(sys_epoll, epoll_pwait2_with_sigset) {
int epoll_fd = epoll_create(1);
ASSERT_NE(-1, epoll_fd);
#if defined(__BIONIC__)
epoll_event events[1] = {};
timespec ts = {.tv_nsec = 500};
sigset_t ss2;
sigemptyset(&ss2);
sigaddset(&ss2, SIGPIPE);
int rc = epoll_pwait2(epoll_fd, events, 1, &ts, &ss2);
if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2 in this kernel";
ASSERT_EQ(0, rc) << strerror(errno);
#else
GTEST_SKIP() << "epoll_pwait2 is only in glibc 2.35+";
#endif
}
TEST(sys_epoll, epoll_pwait2_64_with_sigset) {
int epoll_fd = epoll_create(1);
ASSERT_NE(-1, epoll_fd);
#if defined(__BIONIC__)
epoll_event events[1] = {};
timespec ts = {.tv_nsec = 500};
sigset64_t ss2;
sigemptyset64(&ss2);
sigaddset64(&ss2, SIGPIPE);
int rc = epoll_pwait2_64(epoll_fd, events, 1, &ts, &ss2);
if (rc == -1 && errno == ENOSYS) GTEST_SKIP() << "no epoll_pwait2 in this kernel";
ASSERT_EQ(0, rc) << strerror(errno);
#else
GTEST_SKIP() << "epoll_pwait2_64 is bionic-only";
#endif
}
TEST(sys_epoll, epoll_create_invalid_size) { TEST(sys_epoll, epoll_create_invalid_size) {
errno = 0; errno = 0;
ASSERT_EQ(-1, epoll_create(0)); ASSERT_EQ(-1, epoll_create(0));