Module Name: src Committed By: riastradh Date: Sun Oct 15 15:18:17 UTC 2023
Modified Files: src/tests/kernel: t_fdrestart.c Log Message: t_fdrestart: Rework this to be a little more robust. For the write test, need to make sure the pipe's buffer is full first before the write that blocks, so that it doesn't return partial progress rather than ERESTART if woken. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/tests/kernel/t_fdrestart.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/tests/kernel/t_fdrestart.c diff -u src/tests/kernel/t_fdrestart.c:1.2 src/tests/kernel/t_fdrestart.c:1.3 --- src/tests/kernel/t_fdrestart.c:1.2 Sun Oct 15 14:30:51 2023 +++ src/tests/kernel/t_fdrestart.c Sun Oct 15 15:18:17 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: t_fdrestart.c,v 1.2 2023/10/15 14:30:51 riastradh Exp $ */ +/* $NetBSD: t_fdrestart.c,v 1.3 2023/10/15 15:18:17 riastradh Exp $ */ /*- * Copyright (c) 2023 The NetBSD Foundation, Inc. @@ -29,8 +29,9 @@ #define _KMEMUSER /* ERESTART */ #include <sys/cdefs.h> -__RCSID("$NetBSD: t_fdrestart.c,v 1.2 2023/10/15 14:30:51 riastradh Exp $"); +__RCSID("$NetBSD: t_fdrestart.c,v 1.3 2023/10/15 15:18:17 riastradh Exp $"); +#include <sys/ioctl.h> #include <sys/socket.h> #include <sys/un.h> @@ -51,18 +52,47 @@ struct fdrestart { }; static void +waitforbarrier(struct fdrestart *F, const char *caller) +{ + int error; + + error = pthread_barrier_wait(&F->barrier); + switch (error) { + case 0: + case PTHREAD_BARRIER_SERIAL_THREAD: + break; + default: + atf_tc_fail("%s: pthread_barrier_wait: %d, %s", caller, error, + strerror(error)); + } +} + +static void doread(struct fdrestart *F) { char c; ssize_t nread; int error; + /* + * Wait for the other thread to be ready. + */ + waitforbarrier(F, "reader"); + + /* + * Start a read. This should block, and then, when the other + * thread closes the fd, should be woken to fail with ERESTART. + */ nread = rump_sys_read(F->fd, &c, sizeof(c)); ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread); error = errno; ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error, strerror(error)); + /* + * Now further attempts at I/O should fail with EBADF because + * the fd has been closed. + */ nread = rump_sys_read(F->fd, &c, sizeof(c)); ATF_REQUIRE_EQ_MSG(nread, -1, "nread=%zd", nread); error = errno; @@ -77,14 +107,38 @@ dowrite(struct fdrestart *F) ssize_t nwrit; int error; + /* + * Make sure the pipe's buffer is full first. + */ + for (;;) { + int nspace; + + RL(rump_sys_ioctl(F->fd, FIONSPACE, &nspace)); + ATF_REQUIRE_MSG(nspace >= 0, "nspace=%d", nspace); + if (nspace == 0) + break; + RL(rump_sys_write(F->fd, buf, (size_t)nspace)); + } + + /* + * Wait for the other thread to be ready. + */ + waitforbarrier(F, "writer"); + + /* + * Start a write. This should block, and then, when the other + * thread closes the fd, should be woken to fail with ERESTART. + */ nwrit = rump_sys_write(F->fd, buf, sizeof(buf)); - if (nwrit != -1) /* filled buffer, try again */ - nwrit = rump_sys_write(F->fd, buf, sizeof(buf)); ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit); error = errno; ATF_REQUIRE_EQ_MSG(error, ERESTART, "errno=%d (%s)", error, strerror(error)); + /* + * Now further attempts at I/O should fail with EBADF because + * the fd has been closed. + */ nwrit = rump_sys_write(F->fd, buf, sizeof(buf)); ATF_REQUIRE_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit); error = errno; @@ -92,28 +146,11 @@ dowrite(struct fdrestart *F) strerror(error)); } -static void -waitforbarrier(struct fdrestart *F, const char *caller) -{ - int error; - - error = pthread_barrier_wait(&F->barrier); - switch (error) { - case 0: - case PTHREAD_BARRIER_SERIAL_THREAD: - break; - default: - atf_tc_fail("%s: pthread_barrier_wait: %d, %s", caller, error, - strerror(error)); - } -} - static void * doit(void *cookie) { struct fdrestart *F = cookie; - waitforbarrier(F, "user"); (*F->op)(F); return NULL; @@ -138,9 +175,10 @@ testfdrestart(struct fdrestart *F) RZ(pthread_create(&t, NULL, &doit, F)); waitforbarrier(F, "closer"); /* wait for thread to start */ (void)sleep(1); /* wait for op to start */ - (void)alarm(1); - RL(rump_sys_close(F->fd)); - RZ(pthread_join(t, NULL)); + (void)alarm(1); /* set a deadline */ + RL(rump_sys_close(F->fd)); /* wake op in other thread */ + RZ(pthread_join(t, NULL)); /* wait for op to wake and fail */ + (void)alarm(0); /* clear the deadline */ } ATF_TC(pipe_read);