blob: 5957e7d86afca2af9af803a0b88ec0494499cee1 [file] [log] [blame]
/*
* Copyright (c) 2020 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/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
ZTEST_SUITE(test_eventfd, NULL, NULL, NULL, NULL, NULL);
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;
}
ZTEST(test_eventfd, test_eventfd)
{
int fd = eventfd(0, 0);
zassert_true(fd >= 0, "fd == %d", fd);
close(fd);
}
ZTEST(test_eventfd, test_eventfd_read_nonblock)
{
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);
}
ZTEST(test_eventfd, test_eventfd_write_then_read)
{
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);
}
ZTEST(test_eventfd, test_eventfd_poll_timeout)
{
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");
}
ZTEST(test_eventfd, test_eventfd_unset_poll_event_block)
{
int fd;
fd = eventfd(0, 0);
zassert_true(fd >= 0, "fd == %d", fd);
eventfd_poll_unset_common(fd);
close(fd);
}
ZTEST(test_eventfd, test_eventfd_unset_poll_event_nonblock)
{
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");
}
ZTEST(test_eventfd, test_eventfd_set_poll_event_block)
{
int fd;
fd = eventfd(TESTVAL, 0);
zassert_true(fd >= 0, "fd == %d", fd);
eventfd_poll_set_common(fd);
close(fd);
}
ZTEST(test_eventfd, test_eventfd_set_poll_event_nonblock)
{
int fd;
fd = eventfd(TESTVAL, EFD_NONBLOCK);
zassert_true(fd >= 0, "fd == %d", fd);
eventfd_poll_set_common(fd);
close(fd);
}
ZTEST(test_eventfd, test_eventfd_overflow)
{
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);
}
ZTEST(test_eventfd, test_eventfd_zero_shall_not_unblock)
{
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);
}