Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 10 Jun 2025 06:06:06 GMT
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 19e599c0e00d - main - tests/unix_stream: refactor event mech tests
Message-ID:  <202506100606.55A666XL003548@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=19e599c0e00dcf0699c38798e5d58fb8423e5810

commit 19e599c0e00dcf0699c38798e5d58fb8423e5810
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-06-10 02:59:31 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-06-10 04:57:04 +0000

    tests/unix_stream: refactor event mech tests
    
    Provide a context that can be used both for writability and readability
    checks.  This collapses two check functions per mech into one. Provide a
    possibility to check advanced features of an event mech, e.g. returned
    kev_flags for kevent(2).
    
    Should be no functional change.
---
 tests/sys/kern/unix_stream.c | 293 ++++++++++++++++++++++++-------------------
 1 file changed, 161 insertions(+), 132 deletions(-)

diff --git a/tests/sys/kern/unix_stream.c b/tests/sys/kern/unix_stream.c
index f8ba288308bd..72dbe8ca1d92 100644
--- a/tests/sys/kern/unix_stream.c
+++ b/tests/sys/kern/unix_stream.c
@@ -102,98 +102,78 @@ ATF_TC_BODY(send_0, tc)
 	close(sv[1]);
 }
 
-static void
-check_readable_select(int fd, int expect, bool timeout)
-{
-	fd_set rdfds;
-	int nfds;
-
-	FD_ZERO(&rdfds);
-	FD_SET(fd, &rdfds);
-	nfds = select(fd + 1, &rdfds, NULL, NULL, timeout ?
-	    &(struct timeval){.tv_usec = 1000} : NULL);
-	ATF_REQUIRE_MSG(nfds == expect,
-	    "select() returns %d errno %d", nfds, errno);
-}
+struct check_ctx;
+typedef void check_func_t(struct check_ctx *);
+struct check_ctx {
+	check_func_t	*method;
+	int		sv[2];
+	bool		timeout;
+	union {
+		enum { SELECT_RD, SELECT_WR } select_what;
+		short	poll_events;
+		short	kev_filter;
+	};
+	int		nfds;
+	union {
+		short	poll_revents;
+		unsigned short	kev_flags;
+	};
+};
 
 static void
-check_writable_select(int fd, int expect, bool timeout)
+check_select(struct check_ctx *ctx)
 {
-	fd_set wrfds;
+	fd_set fds;
 	int nfds;
 
-	FD_ZERO(&wrfds);
-	FD_SET(fd, &wrfds);
-	nfds = select(fd + 1, NULL, &wrfds, NULL, timeout ?
-	    &(struct timeval){.tv_usec = 1000} : NULL);
-	ATF_REQUIRE_MSG(nfds == expect,
+	FD_ZERO(&fds);
+	FD_SET(ctx->sv[0], &fds);
+	nfds = select(ctx->sv[0] + 1,
+	    ctx->select_what == SELECT_RD ? &fds : NULL,
+	    ctx->select_what == SELECT_WR ? &fds : NULL,
+	    NULL,
+	    ctx->timeout ?  &(struct timeval){.tv_usec = 1000} : NULL);
+	ATF_REQUIRE_MSG(nfds == ctx->nfds,
 	    "select() returns %d errno %d", nfds, errno);
 }
 
 static void
-check_readable_poll(int fd, int expect, bool timeout)
+check_poll(struct check_ctx *ctx)
 {
 	struct pollfd pfd[1];
 	int nfds;
 
 	pfd[0] = (struct pollfd){
-		.fd = fd,
-		.events = POLLIN | POLLRDNORM,
+		.fd = ctx->sv[0],
+		.events = ctx->poll_events,
 	};
-	nfds = poll(pfd, 1, timeout ? 1 : INFTIM);
-	ATF_REQUIRE_MSG(nfds == expect,
+	nfds = poll(pfd, 1, ctx->timeout ? 1 : INFTIM);
+	ATF_REQUIRE_MSG(nfds == ctx->nfds,
 	    "poll() returns %d errno %d", nfds, errno);
+	ATF_REQUIRE((pfd[0].revents & ctx->poll_revents) == ctx->poll_revents);
 }
 
 static void
-check_writable_poll(int fd, int expect, bool timeout)
-{
-	struct pollfd pfd[1];
-	int nfds;
-
-	pfd[0] = (struct pollfd){
-		.fd = fd,
-		.events = POLLOUT | POLLWRNORM,
-	};
-	nfds = poll(pfd, 1, timeout ? 1 : INFTIM);
-	ATF_REQUIRE_MSG(nfds == expect,
-	    "poll() returns %d errno %d", nfds, errno);
-}
-
-static void
-check_writable_kevent(int fd, int expect, bool timeout)
+check_kevent(struct check_ctx *ctx)
 {
 	struct kevent kev;
 	int nfds, kq;
 
 	ATF_REQUIRE(kq = kqueue());
-	EV_SET(&kev, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+	EV_SET(&kev, ctx->sv[0], ctx->kev_filter, EV_ADD, 0, 0, NULL);
 	nfds = kevent(kq, &kev, 1, NULL, 0, NULL);
 	ATF_REQUIRE_MSG(nfds == 0,
 	    "kevent() returns %d errno %d", nfds, errno);
-	nfds = kevent(kq, NULL, 0, &kev, 1, timeout ?
+	nfds = kevent(kq, NULL, 0, &kev, 1, ctx->timeout ?
 	    &(struct timespec){.tv_nsec = 1000000} : NULL);
-	ATF_REQUIRE_MSG(nfds == expect,
+	ATF_REQUIRE_MSG(nfds == ctx->nfds,
 	    "kevent() returns %d errno %d", nfds, errno);
+	ATF_REQUIRE(kev.ident == (uintptr_t)ctx->sv[0] &&
+	    kev.filter == ctx->kev_filter &&
+	    (kev.flags & ctx->kev_flags) == ctx->kev_flags);
 	close(kq);
 }
 
-typedef void check_writable_func_t(int, int, bool);
-struct check_writable_ctx {
-	check_writable_func_t	*method;
-	int			fd;
-};
-
-static void *
-check_writable_blocking_thread(void *arg)
-{
-	struct check_writable_ctx *ctx = arg;
-
-	ctx->method(ctx->fd, 1, false);
-
-	return (NULL);
-}
-
 static void
 full_socketpair(int *sv)
 {
@@ -210,13 +190,19 @@ full_socketpair(int *sv)
 	free(buf);
 }
 
+static void *
+pthread_wrap(void *arg)
+{
+	struct check_ctx *ctx = arg;
+
+	ctx->method(ctx);
+
+	return (NULL);
+}
+
 static void
-full_writability_check(int *sv, check_writable_func_t method)
+full_writability_check(struct check_ctx *ctx)
 {
-	struct check_writable_ctx ctx = {
-		.method = method,
-		.fd = sv[0],
-	};
 	pthread_t thr;
 	void *buf;
 	u_long space;
@@ -225,26 +211,30 @@ full_writability_check(int *sv, check_writable_func_t method)
 	ATF_REQUIRE((buf = malloc(space)) != NULL);
 
 	/* First check with timeout, expecting 0 fds returned. */
-	method(sv[0], 0, true);
+	ctx->timeout = true;
+	ctx->nfds = 0;
+	ctx->method(ctx);
 
 	/* Launch blocking thread. */
-	ATF_REQUIRE(pthread_create(&thr, NULL, check_writable_blocking_thread,
-	    &ctx) == 0);
+	ctx->timeout = false;
+	ctx->nfds = 1;
+	ATF_REQUIRE(pthread_create(&thr, NULL, pthread_wrap, ctx) == 0);
 
 	/* Sleep a bit to make sure that thread is put to sleep. */
 	usleep(10000);
 	ATF_REQUIRE(pthread_peekjoin_np(thr, NULL) == EBUSY);
 
 	/* Read some data and re-check, the fd is expected to be returned. */
-	ATF_REQUIRE(read(sv[1], buf, space) == (ssize_t)space);
-
-	method(sv[0], 1, true);
+	ATF_REQUIRE(read(ctx->sv[1], buf, space) == (ssize_t)space);
 
 	/* Now check that thread was successfully woken up and exited. */
 	ATF_REQUIRE(pthread_join(thr, NULL) == 0);
 
-	close(sv[0]);
-	close(sv[1]);
+	/* Extra check repeating what joined thread already did. */
+	ctx->method(ctx);
+
+	close(ctx->sv[0]);
+	close(ctx->sv[1]);
 	free(buf);
 }
 
@@ -254,130 +244,169 @@ full_writability_check(int *sv, check_writable_func_t method)
 ATF_TC_WITHOUT_HEAD(full_writability_select);
 ATF_TC_BODY(full_writability_select, tc)
 {
-	int sv[2];
+	struct check_ctx ctx = {
+		.method = check_select,
+		.select_what = SELECT_WR,
+	};
 
-	full_socketpair(sv);
-	full_writability_check(sv, check_writable_select);
-	close(sv[0]);
-	close(sv[1]);
+	full_socketpair(ctx.sv);
+	full_writability_check(&ctx);
+	close(ctx.sv[0]);
+	close(ctx.sv[1]);
 }
 
 ATF_TC_WITHOUT_HEAD(full_writability_poll);
 ATF_TC_BODY(full_writability_poll, tc)
 {
-	int sv[2];
+	struct check_ctx ctx = {
+		.method = check_poll,
+		.poll_events = POLLOUT | POLLWRNORM,
+	};
 
-	full_socketpair(sv);
-	full_writability_check(sv, check_writable_poll);
-	close(sv[0]);
-	close(sv[1]);
+	full_socketpair(ctx.sv);
+	full_writability_check(&ctx);
+	close(ctx.sv[0]);
+	close(ctx.sv[1]);
 }
 
 ATF_TC_WITHOUT_HEAD(full_writability_kevent);
 ATF_TC_BODY(full_writability_kevent, tc)
 {
-	int sv[2];
+	struct check_ctx ctx = {
+		.method = check_kevent,
+		.kev_filter = EVFILT_WRITE,
+	};
 
-	full_socketpair(sv);
-	full_writability_check(sv, check_writable_kevent);
-	close(sv[0]);
-	close(sv[1]);
+	full_socketpair(ctx.sv);
+	full_writability_check(&ctx);
+	close(ctx.sv[0]);
+	close(ctx.sv[1]);
 }
 
 ATF_TC_WITHOUT_HEAD(connected_writability);
 ATF_TC_BODY(connected_writability, tc)
 {
-	int sv[2];
+	struct check_ctx ctx = {
+		.timeout = true,
+		.nfds = 1,
+	};
 
-	do_socketpair(sv);
-	check_writable_select(sv[0], 1, true);
-	check_writable_poll(sv[0], 1, true);
-	check_writable_kevent(sv[0], 1, true);
-	close(sv[0]);
-	close(sv[1]);
+	do_socketpair(ctx.sv);
+
+	ctx.select_what = SELECT_WR;
+	check_select(&ctx);
+	ctx.poll_events = POLLOUT | POLLWRNORM;
+	check_poll(&ctx);
+	ctx.kev_filter = EVFILT_WRITE;
+	check_kevent(&ctx);
+
+	close(ctx.sv[0]);
+	close(ctx.sv[1]);
 }
 
 ATF_TC_WITHOUT_HEAD(unconnected_writability);
 ATF_TC_BODY(unconnected_writability, tc)
 {
-	int s;
+	struct check_ctx ctx = {
+		.timeout = true,
+		.nfds = 0,
+	};
+
+	ATF_REQUIRE((ctx.sv[0] = socket(PF_LOCAL, SOCK_STREAM, 0)) > 0);
 
-	ATF_REQUIRE((s = socket(PF_LOCAL, SOCK_STREAM, 0)) > 0);
-	check_writable_select(s, 0, true);
-	check_writable_poll(s, 0, true);
-	check_writable_kevent(s, 0, true);
-	close(s);
+	ctx.select_what = SELECT_WR;
+	check_select(&ctx);
+	ctx.poll_events = POLLOUT | POLLWRNORM;
+	check_poll(&ctx);
+	ctx.kev_filter = EVFILT_WRITE;
+	check_kevent(&ctx);
+
+	close(ctx.sv[0]);
 }
 
 ATF_TC_WITHOUT_HEAD(peerclosed_writability);
 ATF_TC_BODY(peerclosed_writability, tc)
 {
-	struct kevent kev;
-	int sv[2], kq;
-
-	do_socketpair(sv);
-	close(sv[1]);
+	struct check_ctx ctx = {
+		.timeout = false,
+		.nfds = 1,
+	};
 
-	check_writable_select(sv[0], 1, false);
-	check_writable_poll(sv[0], 1, false);
+	do_socketpair(ctx.sv);
+	close(ctx.sv[1]);
 
-	ATF_REQUIRE(kq = kqueue());
-	EV_SET(&kev, sv[0], EVFILT_WRITE, EV_ADD, 0, 0, NULL);
-	ATF_REQUIRE(kevent(kq, &kev, 1, &kev, 1, NULL) == 1);
-	ATF_REQUIRE(kev.ident == (uintptr_t)sv[0] &&
-	    kev.filter == EVFILT_WRITE &&
-	    kev.flags == EV_EOF);
+	ctx.select_what = SELECT_WR;
+	check_select(&ctx);
+	ctx.poll_events = POLLOUT | POLLWRNORM;
+	check_poll(&ctx);
+	ctx.kev_filter = EVFILT_WRITE;
+	ctx.kev_flags = EV_EOF;
+	check_kevent(&ctx);
 
-	close(sv[0]);
+	close(ctx.sv[0]);
 }
 
 ATF_TC_WITHOUT_HEAD(peershutdown_writability);
 ATF_TC_BODY(peershutdown_writability, tc)
 {
-	int sv[2];
+	struct check_ctx ctx = {
+		.timeout = false,
+		.nfds = 1,
+	};
 
-	do_socketpair(sv);
-	shutdown(sv[1], SHUT_RD);
+	do_socketpair(ctx.sv);
+	shutdown(ctx.sv[1], SHUT_RD);
 
-	check_writable_select(sv[0], 1, false);
-	check_writable_poll(sv[0], 1, false);
+	ctx.select_what = SELECT_WR;
+	check_select(&ctx);
+	ctx.poll_events = POLLOUT | POLLWRNORM;
+	check_poll(&ctx);
 	/*
 	 * XXXGL: historically unix(4) sockets were not reporting peer's
 	 * shutdown(SHUT_RD) as our EV_EOF.  The kevent(2) manual page says
 	 * "filter will set EV_EOF when the reader disconnects", which is hard
 	 * to interpret unambigously.  For now leave the historic behavior,
 	 * but we may want to change that in uipc_usrreq.c:uipc_filt_sowrite(),
-	 * and then this test will look like the peerclosed_writability test.
+	 * and then this test will also expect EV_EOF in returned flags.
 	 */
-	check_writable_kevent(sv[0], 1, false);
+	ctx.kev_filter = EVFILT_WRITE;
+	check_kevent(&ctx);
 
-	close(sv[0]);
-	close(sv[1]);
+	close(ctx.sv[0]);
+	close(ctx.sv[1]);
 }
 
 ATF_TC_WITHOUT_HEAD(peershutdown_readability);
 ATF_TC_BODY(peershutdown_readability, tc)
 {
+	struct check_ctx ctx = {
+		.timeout = false,
+		.nfds = 1,
+	};
 	ssize_t readsz;
-	int sv[2];
 	char c;
 
-	do_socketpair(sv);
-	shutdown(sv[1], SHUT_WR);
+	do_socketpair(ctx.sv);
+	shutdown(ctx.sv[1], SHUT_WR);
 
 	/*
 	 * The other side should flag as readable in select(2) to allow it to
 	 * read(2) and observe EOF.  Ensure that both poll(2) and select(2)
 	 * are consistent here.
 	 */
-	check_readable_select(sv[0], 1, false);
-	check_readable_poll(sv[0], 1, false);
+	ctx.select_what = SELECT_RD;
+	check_select(&ctx);
+	ctx.poll_events = POLLIN | POLLRDNORM;
+	check_poll(&ctx);
 
-	readsz = read(sv[0], &c, sizeof(c));
+	/*
+	 * Also check that read doesn't block.
+	 */
+	readsz = read(ctx.sv[0], &c, sizeof(c));
 	ATF_REQUIRE_INTEQ(0, readsz);
 
-	close(sv[0]);
-	close(sv[1]);
+	close(ctx.sv[0]);
+	close(ctx.sv[1]);
 }
 
 ATF_TP_ADD_TCS(tp)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202506100606.55A666XL003548>