| /* |
| * Copyright (c) 2020 Tobias Svehagen |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <ztest.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <zephyr/net/socket.h> |
| #include <poll.h> |
| #include <sys/eventfd.h> |
| |
| #define TESTVAL 10 |
| |
| static int is_blocked(int fd, short *event) |
| { |
| struct pollfd pfd; |
| int ret; |
| |
| pfd.fd = fd; |
| pfd.events = *event; |
| |
| ret = poll(&pfd, 1, 0); |
| zassert_true(ret >= 0, "poll failed %d", ret); |
| |
| *event = pfd.revents; |
| |
| return ret == 0; |
| } |
| |
| static void test_eventfd(void) |
| { |
| int fd = eventfd(0, 0); |
| |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| close(fd); |
| } |
| |
| static void test_eventfd_read_nonblock(void) |
| { |
| eventfd_t val = 0; |
| int fd, ret; |
| |
| fd = eventfd(0, EFD_NONBLOCK); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| ret = eventfd_read(fd, &val); |
| zassert_true(ret == -1, "read unset ret %d", ret); |
| zassert_true(errno == EAGAIN, "errno %d", errno); |
| |
| ret = eventfd_write(fd, TESTVAL); |
| zassert_true(ret == 0, "write ret %d", ret); |
| |
| ret = eventfd_read(fd, &val); |
| zassert_true(ret == 0, "read set ret %d", ret); |
| zassert_true(val == TESTVAL, "red set val %d", val); |
| |
| ret = eventfd_read(fd, &val); |
| zassert_true(ret == -1, "read subsequent ret %d val %d", ret, val); |
| zassert_true(errno == EAGAIN, "errno %d", errno); |
| |
| close(fd); |
| } |
| |
| static void test_eventfd_write_then_read(void) |
| { |
| eventfd_t val; |
| int fd, ret; |
| |
| fd = eventfd(0, 0); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| ret = eventfd_write(fd, 3); |
| zassert_true(ret == 0, "write ret %d", ret); |
| |
| ret = eventfd_write(fd, 2); |
| zassert_true(ret == 0, "write ret %d", ret); |
| |
| ret = eventfd_read(fd, &val); |
| zassert_true(ret == 0, "read ret %d", ret); |
| zassert_true(val == 5, "val == %d", val); |
| |
| close(fd); |
| |
| /* Test EFD_SEMAPHORE */ |
| |
| fd = eventfd(0, EFD_SEMAPHORE); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| ret = eventfd_write(fd, 3); |
| zassert_true(ret == 0, "write ret %d", ret); |
| |
| ret = eventfd_write(fd, 2); |
| zassert_true(ret == 0, "write ret %d", ret); |
| |
| ret = eventfd_read(fd, &val); |
| zassert_true(ret == 0, "read ret %d", ret); |
| zassert_true(val == 1, "val == %d", val); |
| |
| close(fd); |
| } |
| |
| static void test_eventfd_poll_timeout(void) |
| { |
| struct pollfd pfd; |
| int fd, ret; |
| |
| fd = eventfd(0, 0); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| pfd.fd = fd; |
| pfd.events = POLLIN; |
| |
| ret = poll(&pfd, 1, 500); |
| zassert_true(ret == 0, "poll ret %d", ret); |
| |
| close(fd); |
| } |
| |
| static void eventfd_poll_unset_common(int fd) |
| { |
| eventfd_t val = 0; |
| short event; |
| int ret; |
| |
| event = POLLIN; |
| ret = is_blocked(fd, &event); |
| zassert_equal(ret, 1, "eventfd not blocked with initval == 0"); |
| |
| ret = eventfd_write(fd, TESTVAL); |
| zassert_equal(ret, 0, "write ret %d", ret); |
| |
| event = POLLIN; |
| ret = is_blocked(fd, &event); |
| zassert_equal(ret, 0, "eventfd blocked after write"); |
| zassert_equal(event, POLLIN, "POLLIN not set"); |
| |
| ret = eventfd_write(fd, TESTVAL); |
| zassert_equal(ret, 0, "write ret %d", ret); |
| |
| ret = eventfd_read(fd, &val); |
| zassert_equal(ret, 0, "read ret %d", ret); |
| zassert_equal(val, 2*TESTVAL, "val == %d, expected %d", val, TESTVAL); |
| |
| /* eventfd shall block on subsequent reads */ |
| |
| event = POLLIN; |
| ret = is_blocked(fd, &event); |
| zassert_equal(ret, 1, "eventfd not blocked after read"); |
| } |
| |
| static void test_eventfd_unset_poll_event_block(void) |
| { |
| int fd; |
| |
| fd = eventfd(0, 0); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| eventfd_poll_unset_common(fd); |
| |
| close(fd); |
| } |
| |
| static void test_eventfd_unset_poll_event_nonblock(void) |
| { |
| int fd; |
| |
| fd = eventfd(0, EFD_NONBLOCK); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| eventfd_poll_unset_common(fd); |
| |
| close(fd); |
| } |
| |
| static void eventfd_poll_set_common(int fd) |
| { |
| eventfd_t val = 0; |
| short event; |
| int ret; |
| |
| event = POLLIN; |
| ret = is_blocked(fd, &event); |
| zassert_equal(ret, 0, "eventfd is blocked with initval != 0"); |
| |
| ret = eventfd_read(fd, &val); |
| zassert_equal(ret, 0, "read ret %d", ret); |
| zassert_equal(val, TESTVAL, "val == %d", val); |
| |
| event = POLLIN; |
| ret = is_blocked(fd, &event); |
| zassert_equal(ret, 1, "eventfd is not blocked after read"); |
| } |
| |
| static void test_eventfd_set_poll_event_block(void) |
| { |
| int fd; |
| |
| fd = eventfd(TESTVAL, 0); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| eventfd_poll_set_common(fd); |
| |
| close(fd); |
| } |
| |
| static void test_eventfd_set_poll_event_nonblock(void) |
| { |
| int fd; |
| |
| fd = eventfd(TESTVAL, EFD_NONBLOCK); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| eventfd_poll_set_common(fd); |
| |
| close(fd); |
| } |
| |
| static void test_eventfd_overflow(void) |
| { |
| short event; |
| int fd, ret; |
| |
| fd = eventfd(0, EFD_NONBLOCK); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| event = POLLOUT; |
| ret = is_blocked(fd, &event); |
| zassert_equal(ret, 0, "eventfd write blocked with initval == 0"); |
| |
| ret = eventfd_write(fd, UINT64_MAX); |
| zassert_equal(ret, -1, "fd == %d", fd); |
| zassert_equal(errno, EINVAL, "did not get EINVAL"); |
| |
| ret = eventfd_write(fd, UINT64_MAX-1); |
| zassert_equal(ret, 0, "fd == %d", fd); |
| |
| event = POLLOUT; |
| ret = is_blocked(fd, &event); |
| zassert_equal(ret, 1, "eventfd write not blocked with cnt == UINT64_MAX-1"); |
| |
| ret = eventfd_write(fd, 1); |
| zassert_equal(ret, -1, "fd == %d", fd); |
| zassert_equal(errno, EAGAIN, "did not get EINVAL"); |
| |
| close(fd); |
| } |
| |
| static void test_eventfd_zero_shall_not_unblock(void) |
| { |
| short event; |
| int fd, ret; |
| |
| fd = eventfd(0, 0); |
| zassert_true(fd >= 0, "fd == %d", fd); |
| |
| ret = eventfd_write(fd, 0); |
| zassert_equal(ret, 0, "fd == %d", fd); |
| |
| event = POLLIN; |
| ret = is_blocked(fd, &event); |
| zassert_equal(ret, 1, "eventfd unblocked by zero"); |
| |
| close(fd); |
| } |
| |
| void test_main(void) |
| { |
| ztest_test_suite(test_eventfd, |
| ztest_unit_test(test_eventfd), |
| ztest_unit_test(test_eventfd_read_nonblock), |
| ztest_unit_test(test_eventfd_write_then_read), |
| ztest_unit_test(test_eventfd_poll_timeout), |
| ztest_unit_test(test_eventfd_unset_poll_event_block), |
| ztest_unit_test(test_eventfd_unset_poll_event_nonblock), |
| ztest_unit_test(test_eventfd_set_poll_event_block), |
| ztest_unit_test(test_eventfd_set_poll_event_nonblock), |
| ztest_unit_test(test_eventfd_overflow), |
| ztest_unit_test(test_eventfd_zero_shall_not_unblock) |
| ); |
| ztest_run_test_suite(test_eventfd); |
| } |