diff --git a/libc/include/sys/eventfd.h b/libc/include/sys/eventfd.h index 85f9877ed..1b6ad29ff 100644 --- a/libc/include/sys/eventfd.h +++ b/libc/include/sys/eventfd.h @@ -38,6 +38,8 @@ __BEGIN_DECLS +/** The eventfd() flag to provide semaphore-like semantics for reads. */ +#define EFD_SEMAPHORE (1 << 0) /** The eventfd() flag for a close-on-exec file descriptor. */ #define EFD_CLOEXEC O_CLOEXEC /** The eventfd() flag for a non-blocking file descriptor. */ diff --git a/tests/eventfd_test.cpp b/tests/eventfd_test.cpp index 68d919226..3c303c25e 100644 --- a/tests/eventfd_test.cpp +++ b/tests/eventfd_test.cpp @@ -21,14 +21,16 @@ #include +#include "utils.h" + TEST(eventfd, smoke) { - unsigned int initial_value = 2; - int fd = eventfd(initial_value, O_NONBLOCK); - ASSERT_NE(fd, -1); + constexpr unsigned int kInitialValue = 2; + int fd = eventfd(kInitialValue, EFD_NONBLOCK); + ASSERT_NE(-1, fd); eventfd_t value = 123; ASSERT_EQ(0, eventfd_read(fd, &value)); - ASSERT_EQ(initial_value, value); + ASSERT_EQ(kInitialValue, value); // Reading clears the counter. ASSERT_EQ(-1, eventfd_read(fd, &value)); @@ -44,3 +46,49 @@ TEST(eventfd, smoke) { close(fd); } + +TEST(eventfd, cloexec) { + constexpr unsigned int kInitialValue = 2; + int fd = eventfd(kInitialValue, EFD_CLOEXEC); + ASSERT_NE(-1, fd); + AssertCloseOnExec(fd, true); + + eventfd_t value = 123; + ASSERT_EQ(0, eventfd_read(fd, &value)); + ASSERT_EQ(kInitialValue, value); + + close(fd); + + fd = eventfd(kInitialValue, EFD_NONBLOCK | EFD_CLOEXEC); + ASSERT_NE(-1, fd); + AssertCloseOnExec(fd, true); + + value = 123; + ASSERT_EQ(0, eventfd_read(fd, &value)); + ASSERT_EQ(kInitialValue, value); + + close(fd); +} + +TEST(eventfd, semaphore) { + int fd = eventfd(3, EFD_NONBLOCK | EFD_SEMAPHORE); + ASSERT_NE(-1, fd); + + eventfd_t value = 123; + ASSERT_EQ(0, eventfd_read(fd, &value)); + ASSERT_EQ(1U, value); + + value = 123; + ASSERT_EQ(0, eventfd_read(fd, &value)); + ASSERT_EQ(1U, value); + + value = 123; + ASSERT_EQ(0, eventfd_read(fd, &value)); + ASSERT_EQ(1U, value); + + // The counter is cleared after the initial value decrements to 0. + ASSERT_EQ(-1, eventfd_read(fd, &value)); + ASSERT_EQ(EAGAIN, errno); + + close(fd); +}