Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Apr 2026 13:49:11 +0000
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 09fe5cc789d5 - stable/15 - tests: kqueue: improve diagnostics for our CPONFORK test
Message-ID:  <69ea2357.21dc4.4fdf0738@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by kevans:

URL: https://cgit.FreeBSD.org/src/commit/?id=09fe5cc789d5eaa2ed98535a1b3efd5e7366cfe3

commit 09fe5cc789d5eaa2ed98535a1b3efd5e7366cfe3
Author:     Kyle Evans <kevans@FreeBSD.org>
AuthorDate: 2026-04-17 03:57:06 +0000
Commit:     Kyle Evans <kevans@FreeBSD.org>
CommitDate: 2026-04-23 13:48:45 +0000

    tests: kqueue: improve diagnostics for our CPONFORK test
    
    Notably, confirm in the child that our close-on-fork fd is actually
    closed, and break RECV_ALL out into a table and check each bit
    individually to provide a better message when the test fails.
    
    While we're here, just switch to waitid() rather than trying to identify
    the point where we have to make the switch.  This reduces maintenance
    slightly, as keeping our assertion static would require still adding to
    a _RECV_ALL mask *just* for that purpose.
    
    Reviewed by:    kib, markj (both slightly earlier version)
    
    (cherry picked from commit 51d2c38010824b90d7462711896a88165db9d015)
---
 tests/sys/kqueue/kqueue_fork.c | 71 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 60 insertions(+), 11 deletions(-)

diff --git a/tests/sys/kqueue/kqueue_fork.c b/tests/sys/kqueue/kqueue_fork.c
index 6f517a2e0e29..ad8f69056e07 100644
--- a/tests/sys/kqueue/kqueue_fork.c
+++ b/tests/sys/kqueue/kqueue_fork.c
@@ -92,21 +92,68 @@ ATF_TC_BODY(shared_table_filt_sig, tc)
 #define	RECV_VNODE	0x02
 #define	RECV_CLOREAD	0x04
 #define	RECV_ERROR	0x80
-#define	RECV_ALL	(RECV_TIMER | RECV_VNODE)
+
+static const struct cponfork_recv {
+	const char	*recv_error_desc;
+	unsigned int	 recv_bit;
+	bool		 recv_parent_only;
+} cponfork_recv[] = {
+	{ "EVFILT_TIMER did not fire", RECV_TIMER, false },
+	{ "EVFILT_VNODE expected with creation of canary", RECV_VNODE, false },
+	{ "EVFILT_READ received for fd closed on fork", RECV_CLOREAD, true },
+};
+
+static void
+cponfork_notes_mask_check(unsigned int mask, bool childmask)
+{
+	const struct cponfork_recv *rcv;
+	unsigned int expect;
+
+	ATF_REQUIRE(mask != RECV_ERROR);
+	for (size_t i = 0; i < nitems(cponfork_recv); i++) {
+		rcv = &cponfork_recv[i];
+
+		expect = childmask && rcv->recv_parent_only ? 0 : rcv->recv_bit;
+		ATF_REQUIRE_EQ_MSG(expect, mask & rcv->recv_bit,
+		    "%s (%s, mask %x)", rcv->recv_error_desc,
+		    childmask ? "child" : "parent",
+		    mask);
+	}
+}
+
+static unsigned int
+cponfork_notes_mask(bool inchild)
+{
+	const struct cponfork_recv *rcv;
+	unsigned int mask = 0;
+
+	for (size_t i = 0; i < nitems(cponfork_recv); i++) {
+		rcv = &cponfork_recv[i];
+
+		if (!inchild || !rcv->recv_parent_only)
+			mask |= rcv->recv_bit;
+	}
+
+	ATF_REQUIRE(mask != 0);
+	return (mask);
+}
 
 static int
 cponfork_notes_check(int kq, int clofd)
 {
 	struct kevent ev;
+	unsigned int mask;
 	int error, received = 0;
 
+	mask = cponfork_notes_mask(true);
+
 	EV_SET(&ev, TIMER_TIMEOUT, EVFILT_TIMER,
 	    EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_SECONDS, 4, NULL);
 	error = kevent(kq, &ev, 1, NULL, 0, NULL);
 	if (error == -1)
 		return (RECV_ERROR);
 
-	while ((received & RECV_ALL) != RECV_ALL) {
+	while ((received & mask) != mask) {
 		error = kevent(kq, NULL, 0, &ev, 1, NULL);
 		if (error < 0)
 			return (RECV_ERROR);
@@ -138,7 +185,8 @@ ATF_TC_WITHOUT_HEAD(cponfork_notes);
 ATF_TC_BODY(cponfork_notes, tc)
 {
 	struct kevent ev[3];
-	int clofd, dfd, error, kq, pdfd, pmask, status;
+	siginfo_t info;
+	int clofd, dfd, error, kq, pdfd, pmask;
 	pid_t pid;
 
 	kq = kqueuex(KQUEUE_CPONFORK);
@@ -164,8 +212,8 @@ ATF_TC_BODY(cponfork_notes, tc)
 	/*
 	 * Every event we setup here we should expect to observe in both the
 	 * child and the parent, with exception to the EVFILT_READ of clofd.  We
-	 * except that one to be dropped in the child when the kqueue it's
-	 * attached to goes away, thus its exclusion from the RECV_ALL mask.
+	 * expect that one to be dropped in the child when the kqueue it's
+	 * attached to goes away, thus its exclusion from the child mask.
 	 */
 	EV_SET(&ev[0], dfd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
 	    NOTE_WRITE, 0, NULL);
@@ -195,6 +243,9 @@ ATF_TC_BODY(cponfork_notes, tc)
 		else if (kf.kf_type != KF_TYPE_KQUEUE)
 			_exit(RECV_ERROR);
 
+		if (fcntl(clofd, F_KINFO, &kf) != -1 || errno != EBADF)
+			_exit(RECV_ERROR);
+
 		_exit(cponfork_notes_check(kq, clofd));
 	}
 
@@ -209,15 +260,13 @@ ATF_TC_BODY(cponfork_notes, tc)
 	 * still fire twice (once in parent, once in child).
 	 */
 	pmask = cponfork_notes_check(kq, clofd);
-	ATF_REQUIRE_EQ(pmask, RECV_ALL | RECV_CLOREAD);
+	cponfork_notes_mask_check(pmask, false);
 
 	/* Wait for the child to timeout or observe the timer. */
-	_Static_assert(RECV_ALL <= UCHAR_MAX,
-	    "Too many events to observe -- switch from waitpid -> waitid");
-	error = waitpid(pid, &status, 0);
+	error = waitid(P_PID, pid, &info, WEXITED);
 	ATF_REQUIRE(error != -1);
-	ATF_REQUIRE(WIFEXITED(status));
-	ATF_REQUIRE_EQ(WEXITSTATUS(status), RECV_ALL);
+	ATF_REQUIRE_EQ(CLD_EXITED, info.si_code);
+	cponfork_notes_mask_check(info.si_status, true);
 }
 
 ATF_TP_ADD_TCS(tp)


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69ea2357.21dc4.4fdf0738>