[PATCH 1/6] selftests/filesystems: add initial select and poll selftest

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Willem de Bruijn <willemb@xxxxxxxxxx>

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 <willemb@xxxxxxxxxx>
---
 .../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




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux