From: Willem de Bruijn <will...@google.com>

Add initial code coverage for select, pselect, poll and ppoll.

Open a socketpair and wait for a read event.
1. run with data waiting
2. run to timeout, if a (short) timeout is specified.

Also optionally pass sigset to pselect and ppoll, to exercise
all datapaths. Build with -m32, -mx32 and -m64 to cover all the
various compat and 32/64-bit time syscall implementations.

Signed-off-by: Willem de Bruijn <will...@google.com>
---
 .../testing/selftests/filesystems/.gitignore  |   1 +
 tools/testing/selftests/filesystems/Makefile  |   2 +-
 .../selftests/filesystems/selectpoll.c        | 207 ++++++++++++++++++
 3 files changed, 209 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/filesystems/selectpoll.c

diff --git a/tools/testing/selftests/filesystems/.gitignore 
b/tools/testing/selftests/filesystems/.gitignore
index f0c0ff20d6cf..d4a2e50475ea 100644
--- a/tools/testing/selftests/filesystems/.gitignore
+++ b/tools/testing/selftests/filesystems/.gitignore
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 dnotify_test
 devpts_pts
+selectpoll
diff --git a/tools/testing/selftests/filesystems/Makefile 
b/tools/testing/selftests/filesystems/Makefile
index 129880fb42d3..8de184865fa4 100644
--- a/tools/testing/selftests/filesystems/Makefile
+++ b/tools/testing/selftests/filesystems/Makefile
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 
 CFLAGS += -I../../../../usr/include/
-TEST_GEN_PROGS := devpts_pts
+TEST_GEN_PROGS := devpts_pts selectpoll
 TEST_GEN_PROGS_EXTENDED := dnotify_test
 
 include ../lib.mk
diff --git a/tools/testing/selftests/filesystems/selectpoll.c 
b/tools/testing/selftests/filesystems/selectpoll.c
new file mode 100644
index 000000000000..315da0786a6c
--- /dev/null
+++ b/tools/testing/selftests/filesystems/selectpoll.c
@@ -0,0 +1,207 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <asm/unistd.h>
+#include <poll.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include "../kselftest_harness.h"
+
+const unsigned long timeout_us = 5UL * 1000;
+const unsigned long timeout_ns = timeout_us * 1000;
+
+/* (p)select: basic invocation, optionally with data waiting */
+
+FIXTURE(select_basic)
+{
+       fd_set readfds;
+       int sfd[2];
+};
+
+FIXTURE_SETUP(select_basic)
+{
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, self->sfd), 0);
+
+       FD_ZERO(&self->readfds);
+       FD_SET(self->sfd[0], &self->readfds);
+       FD_SET(self->sfd[1], &self->readfds);
+}
+
+FIXTURE_TEARDOWN(select_basic)
+{
+       /* FD_ISSET(self->sfd[0] tested in TEST_F: depends on timeout */
+       ASSERT_EQ(FD_ISSET(self->sfd[1], &self->readfds), 0);
+
+       EXPECT_EQ(close(self->sfd[0]), 0);
+       EXPECT_EQ(close(self->sfd[1]), 0);
+}
+
+TEST_F(select_basic, select)
+{
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       ASSERT_EQ(select(self->sfd[1] + 1, &self->readfds,
+                        NULL, NULL, NULL), 1);
+       ASSERT_NE(FD_ISSET(self->sfd[0], &self->readfds), 0);
+}
+
+TEST_F(select_basic, select_with_timeout)
+{
+       struct timeval tv = { .tv_usec = timeout_us };
+
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       ASSERT_EQ(select(self->sfd[1] + 1, &self->readfds,
+                        NULL, NULL, &tv), 1);
+       ASSERT_GE(tv.tv_usec, 1000);
+       ASSERT_NE(FD_ISSET(self->sfd[0], &self->readfds), 0);
+}
+
+TEST_F(select_basic, select_timeout)
+{
+       struct timeval tv = { .tv_usec = timeout_us };
+
+       ASSERT_EQ(select(self->sfd[1] + 1, &self->readfds,
+                        NULL, NULL, &tv), 0);
+       ASSERT_EQ(FD_ISSET(self->sfd[0], &self->readfds), 0);
+}
+
+TEST_F(select_basic, pselect)
+{
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       ASSERT_EQ(pselect(self->sfd[1] + 1, &self->readfds,
+                         NULL, NULL, NULL, NULL), 1);
+       ASSERT_NE(FD_ISSET(self->sfd[0], &self->readfds), 0);
+}
+
+TEST_F(select_basic, pselect_with_timeout)
+{
+       struct timespec ts = { .tv_nsec = timeout_ns };
+
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       ASSERT_EQ(pselect(self->sfd[1] + 1, &self->readfds,
+                         NULL, NULL, &ts, NULL), 1);
+       ASSERT_GE(ts.tv_nsec, 1000);
+       ASSERT_NE(FD_ISSET(self->sfd[0], &self->readfds), 0);
+}
+
+TEST_F(select_basic, pselect_timeout)
+{
+       struct timespec ts = { .tv_nsec = timeout_ns };
+
+       ASSERT_EQ(pselect(self->sfd[1] + 1, &self->readfds,
+                         NULL, NULL, &ts, NULL), 0);
+       ASSERT_EQ(FD_ISSET(self->sfd[0], &self->readfds), 0);
+}
+
+TEST_F(select_basic, pselect_sigset_with_timeout)
+{
+       struct timespec ts = { .tv_nsec = timeout_ns };
+       sigset_t sigmask;
+
+       sigemptyset(&sigmask);
+       sigaddset(&sigmask, SIGUSR1);
+       sigprocmask(SIG_SETMASK, &sigmask, NULL);
+       sigemptyset(&sigmask);
+
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       ASSERT_EQ(pselect(self->sfd[1] + 1, &self->readfds,
+                         NULL, NULL, &ts, &sigmask), 1);
+       ASSERT_GE(ts.tv_nsec, 1000);
+       ASSERT_NE(FD_ISSET(self->sfd[0], &self->readfds), 0);
+}
+
+/* (p)poll: basic invocation with data waiting */
+
+FIXTURE(poll_basic)
+{
+       struct pollfd pfds[2];
+       int sfd[2];
+};
+
+FIXTURE_SETUP(poll_basic)
+{
+       ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, self->sfd), 0);
+
+       self->pfds[0].events = POLLIN;
+       self->pfds[0].revents = 0;
+       self->pfds[0].fd = self->sfd[0];
+
+       self->pfds[1].events = POLLIN;
+       self->pfds[1].revents = 0;
+       self->pfds[1].fd = self->sfd[1];
+}
+
+FIXTURE_TEARDOWN(poll_basic)
+{
+       /* FD_ISSET(self->pfds[0] tested in TEST_F: depends on timeout */
+       EXPECT_EQ(self->pfds[1].revents & POLLIN, 0);
+
+       EXPECT_EQ(close(self->sfd[0]), 0);
+       EXPECT_EQ(close(self->sfd[1]), 0);
+}
+
+TEST_F(poll_basic, poll)
+{
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       EXPECT_EQ(poll(self->pfds, ARRAY_SIZE(self->pfds), 0), 1);
+       EXPECT_EQ(self->pfds[0].revents & POLLIN, POLLIN);
+}
+
+TEST_F(poll_basic, poll_with_timeout)
+{
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       EXPECT_EQ(poll(self->pfds, ARRAY_SIZE(self->pfds), 1001), 1);
+       EXPECT_EQ(self->pfds[0].revents & POLLIN, POLLIN);
+}
+
+TEST_F(poll_basic, poll_timeout)
+{
+       EXPECT_EQ(poll(self->pfds, ARRAY_SIZE(self->pfds), 1001), 0);
+       EXPECT_EQ(self->pfds[0].revents & POLLIN, 0);
+}
+
+TEST_F(poll_basic, ppoll)
+{
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       EXPECT_EQ(ppoll(self->pfds, ARRAY_SIZE(self->pfds), NULL, NULL), 1);
+       EXPECT_EQ(self->pfds[0].revents & POLLIN, POLLIN);
+}
+
+TEST_F(poll_basic, ppoll_with_timeout)
+{
+       struct timespec ts = { .tv_nsec = timeout_ns };
+
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       EXPECT_EQ(ppoll(self->pfds, ARRAY_SIZE(self->pfds), &ts, NULL), 1);
+       ASSERT_GE(ts.tv_nsec, 1000);
+       EXPECT_EQ(self->pfds[0].revents & POLLIN, POLLIN);
+}
+
+TEST_F(poll_basic, ppoll_timeout)
+{
+       struct timespec ts = { .tv_nsec = timeout_ns };
+
+       EXPECT_EQ(ppoll(self->pfds, ARRAY_SIZE(self->pfds), &ts, NULL), 0);
+       EXPECT_EQ(self->pfds[0].revents & POLLIN, 0);
+}
+
+TEST_F(poll_basic, ppoll_sigset_with_timeout)
+{
+       struct timespec ts = { .tv_nsec = timeout_ns };
+       sigset_t sigmask;
+
+       sigemptyset(&sigmask);
+       sigaddset(&sigmask, SIGUSR1);
+       sigprocmask(SIG_SETMASK, &sigmask, NULL);
+       sigemptyset(&sigmask);
+
+       ASSERT_EQ(write(self->sfd[1], "w", 1), 1);
+       EXPECT_EQ(ppoll(self->pfds, ARRAY_SIZE(self->pfds), &ts, &sigmask), 1);
+       ASSERT_GE(ts.tv_nsec, 1000);
+       EXPECT_EQ(self->pfds[0].revents & POLLIN, POLLIN);
+}
+
+TEST_HARNESS_MAIN
-- 
2.30.0.284.gd98b1dd5eaa7-goog

Reply via email to