summaryrefslogtreecommitdiff
path: root/lib/libc/sys
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/sys')
-rw-r--r--lib/libc/sys/Makefile23
-rw-r--r--lib/libc/sys/t_clock_gettime.c46
-rw-r--r--lib/libc/sys/t_clone.c57
-rw-r--r--lib/libc/sys/t_dup.c8
-rw-r--r--lib/libc/sys/t_futex_ops.c614
-rw-r--r--lib/libc/sys/t_getitimer.c57
-rw-r--r--lib/libc/sys/t_getrusage.c5
-rw-r--r--lib/libc/sys/t_kill.c17
-rw-r--r--lib/libc/sys/t_pipe2.c35
-rw-r--r--lib/libc/sys/t_poll.c1859
-rw-r--r--lib/libc/sys/t_posix_fadvise.c15
-rw-r--r--lib/libc/sys/t_ptrace.c89
-rw-r--r--lib/libc/sys/t_ptrace_amd64_wait.h3
-rw-r--r--lib/libc/sys/t_ptrace_bytetransfer_wait.h4
-rw-r--r--lib/libc/sys/t_ptrace_clone_wait.h3
-rw-r--r--lib/libc/sys/t_ptrace_core_wait.h6
-rw-r--r--lib/libc/sys/t_ptrace_eventmask_wait.h3
-rw-r--r--lib/libc/sys/t_ptrace_fork_wait.h8
-rw-r--r--lib/libc/sys/t_ptrace_lwp_wait.h3
-rw-r--r--lib/libc/sys/t_ptrace_register_wait.h3
-rw-r--r--lib/libc/sys/t_ptrace_sigchld.c17
-rw-r--r--lib/libc/sys/t_ptrace_siginfo_wait.h6
-rw-r--r--lib/libc/sys/t_ptrace_signal_wait.h282
-rw-r--r--lib/libc/sys/t_ptrace_syscall_wait.h3
-rw-r--r--lib/libc/sys/t_ptrace_threads_wait.h46
-rw-r--r--lib/libc/sys/t_ptrace_topology_wait.h3
-rw-r--r--lib/libc/sys/t_ptrace_wait.c15
-rw-r--r--lib/libc/sys/t_ptrace_wait.h92
-rw-r--r--lib/libc/sys/t_ptrace_x86_wait.h427
-rw-r--r--lib/libc/sys/t_select.c45
-rw-r--r--lib/libc/sys/t_setrlimit.c149
-rw-r--r--lib/libc/sys/t_sigtimedwait.c161
-rw-r--r--lib/libc/sys/t_socketpair.c35
-rw-r--r--lib/libc/sys/t_swapcontext.c14
-rw-r--r--lib/libc/sys/t_timer_create.c331
-rw-r--r--lib/libc/sys/t_timerfd.c177
36 files changed, 3805 insertions, 856 deletions
diff --git a/lib/libc/sys/Makefile b/lib/libc/sys/Makefile
index 21e66aa74946..5d808b2a7700 100644
--- a/lib/libc/sys/Makefile
+++ b/lib/libc/sys/Makefile
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.74 2023/08/08 06:27:32 mrg Exp $
+# $NetBSD: Makefile,v 1.80 2025/10/10 15:53:55 christos Exp $
MKMAN= no
@@ -9,6 +9,10 @@ MKMAN= no
TESTSDIR= ${TESTSBASE}/lib/libc/sys
TESTS_C+= t_access
+TESTS_C+= t_aio_cancel
+TESTS_C+= t_aio_lio
+TESTS_C+= t_aio_rw
+TESTS_C+= t_aio_suspend
TESTS_C+= t_bind
TESTS_C+= t_chroot
TESTS_C+= t_clock_gettime
@@ -36,10 +40,10 @@ TESTS_C+= t_kevent
TESTS_C+= t_kill
TESTS_C+= t_link
TESTS_C+= t_listen
-TESTS_C+= t_lwp_ctl
TESTS_C+= t_lwp_create
-TESTS_C+= t_minherit
+TESTS_C+= t_lwp_ctl
TESTS_C+= t_mincore
+TESTS_C+= t_minherit
TESTS_C+= t_mkdir
TESTS_C+= t_mkfifo
TESTS_C+= t_mknod
@@ -59,6 +63,7 @@ TESTS_C+= t_pollts
TESTS_C+= t_posix_fallocate
TESTS_C+= t_ppoll
TESTS_C+= t_ptrace
+TESTS_C+= t_ptrace_kill
TESTS_C+= t_ptrace_sigchld
TESTS_C+= t_ptrace_wait
TESTS_C+= t_ptrace_wait3
@@ -78,8 +83,8 @@ TESTS_C+= t_sigaltstack
TESTS_C+= t_sigqueue
TESTS_C+= t_sigtimedwait
TESTS_C+= t_socketpair
-TESTS_C+= t_swapcontext
TESTS_C+= t_stat
+TESTS_C+= t_swapcontext
TESTS_C+= t_syscall
TESTS_C+= t_timer_create
TESTS_C+= t_timerfd
@@ -95,9 +100,16 @@ TESTS_C+= t_write
SRCS.t_mprotect= t_mprotect.c ${SRCS_EXEC_PROT} t_mprotect_helper.c
+LDADD.t_aio_cancel+= -lrt -lpthread
+LDADD.t_aio_suspend+= -lrt -lpthread
+LDADD.t_aio_rw+= -lrt -lpthread
+LDADD.t_aio_lio+= -lrt -lpthread
+
LDADD.t_eventfd+= -lpthread
LDADD.t_getpid+= -lpthread
LDADD.t_mmap+= -lpthread
+LDADD.t_poll+= -lpthread
+LDADD.t_ptrace_kill+= -lpthread
LDADD.t_timerfd+= -lpthread
LDADD.t_ptrace_sigchld+= -pthread -lm
@@ -149,7 +161,8 @@ FILESGRP_truncate_test.root_owned= wheel
CLEANFILES= truncate_test.root_owned
truncate_test.root_owned:
- dd if=/dev/null bs=1 count=1 of=${.TARGET}
+ @${_MKTARGET_CREATE}
+ touch ${.TARGET}
WARNS= 4
diff --git a/lib/libc/sys/t_clock_gettime.c b/lib/libc/sys/t_clock_gettime.c
index 6421b1ab0cb8..abe0dce623d0 100644
--- a/lib/libc/sys/t_clock_gettime.c
+++ b/lib/libc/sys/t_clock_gettime.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_clock_gettime.c,v 1.6 2023/07/09 19:19:40 riastradh Exp $ */
+/* $NetBSD: t_clock_gettime.c,v 1.10 2025/03/25 19:51:32 riastradh Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -58,7 +58,7 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2008\
The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_clock_gettime.c,v 1.6 2023/07/09 19:19:40 riastradh Exp $");
+__RCSID("$NetBSD: t_clock_gettime.c,v 1.10 2025/03/25 19:51:32 riastradh Exp $");
#include <sys/param.h>
@@ -117,10 +117,12 @@ check_timecounter(void)
if (diff < 0 || diff > MINPOSDIFF) {
long long elapsed;
- (void)printf("%stime TSA: 0x%jx.%08jx, TSB: 0x%jx.%08jx, "
+ (void)printf("%stime"
+ " TSA: 0x%jx.%08jx, TSB: 0x%jx.%08jx, "
"diff = %lld nsec, ", (diff < 0) ? "BAD " : "",
(uintmax_t)tsa.tv_sec, (uintmax_t)tsa.tv_nsec,
- (uintmax_t)tsb.tv_sec, (uintmax_t)tsb.tv_nsec, diff);
+ (uintmax_t)tsb.tv_sec, (uintmax_t)tsb.tv_nsec,
+ diff);
elapsed = 1000000000LL * (tsb.tv_sec - tsl.tv_sec)
+ tsb.tv_nsec - tsl.tv_nsec;
@@ -285,12 +287,48 @@ ATF_TC_BODY(clock_gettime_thread_cputime_is_monotonic, tc)
CLOCK_THREAD_CPUTIME_ID, &waste_user_time);
}
+static void
+check_resolution(const char *clockname, clockid_t clockid)
+{
+ struct timespec ts;
+ int rv;
+
+ RLF(rv = clock_getres(clockid, &ts), "%s", clockname);
+ if (rv != -1) {
+ ATF_CHECK_MSG(ts.tv_sec == 0,
+ "The resolution of the clock %s is reported as %jd.%09ld"
+ " which is lower than a second; most likely a wrong value",
+ clockname, ts.tv_sec, ts.tv_nsec);
+ }
+}
+
+ATF_TC(clock_getres);
+ATF_TC_HEAD(clock_getres, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks that clock_getres(2) returns some reasonable resolution"
+ " for all supported clocks");
+}
+ATF_TC_BODY(clock_getres, tc)
+{
+ check_resolution("CLOCK_REALTIME", CLOCK_REALTIME);
+ check_resolution("CLOCK_MONOTONIC", CLOCK_MONOTONIC);
+ atf_tc_expect_fail("These clocks aren't supported but are documented"
+ " in clock_gettime(2) for some reason");
+ check_resolution("CLOCK_VIRTUAL", CLOCK_VIRTUAL);
+ check_resolution("CLOCK_PROF", CLOCK_PROF);
+ atf_tc_expect_pass();
+ check_resolution("CLOCK_PROCESS_CPUTIME_ID", CLOCK_PROCESS_CPUTIME_ID);
+ check_resolution("CLOCK_THREAD_CPUTIME_ID", CLOCK_THREAD_CPUTIME_ID);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, clock_gettime_real);
ATF_TP_ADD_TC(tp, clock_gettime_process_cputime_is_monotonic);
ATF_TP_ADD_TC(tp, clock_gettime_thread_cputime_is_monotonic);
+ ATF_TP_ADD_TC(tp, clock_getres);
return atf_no_error();
}
diff --git a/lib/libc/sys/t_clone.c b/lib/libc/sys/t_clone.c
index d21140132f75..7e359510e2f3 100644
--- a/lib/libc/sys/t_clone.c
+++ b/lib/libc/sys/t_clone.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_clone.c,v 1.4 2017/05/23 15:56:55 christos Exp $ */
+/* $NetBSD: t_clone.c,v 1.6 2024/09/27 18:50:01 riastradh Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -32,11 +32,12 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2008\
The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_clone.c,v 1.4 2017/05/23 15:56:55 christos Exp $");
+__RCSID("$NetBSD: t_clone.c,v 1.6 2024/09/27 18:50:01 riastradh Exp $");
+#include <sys/param.h>
+#include <sys/types.h>
#include <sys/mman.h>
#include <sys/resource.h>
-#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
@@ -53,6 +54,27 @@ __RCSID("$NetBSD: t_clone.c,v 1.4 2017/05/23 15:56:55 christos Exp $");
#define FROBVAL 41973
#define CHILDEXIT 0xa5
+static void *
+getstack(void)
+{
+ void *stack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON, -1, (off_t) 0);
+ ATF_REQUIRE_ERRNO(errno, stack != MAP_FAILED);
+#ifndef __MACHINE_STACK_GROWS_UP
+ stack = (char *)stack + STACKSIZE;
+#endif
+ return stack;
+}
+
+static void
+putstack(void *stack)
+{
+#ifndef __MACHINE_STACK_GROWS_UP
+ stack = (char *)stack - STACKSIZE;
+#endif
+ ATF_REQUIRE_ERRNO(errno, munmap(stack, STACKSIZE) != -1);
+}
+
static int
dummy(void *arg)
{
@@ -94,21 +116,11 @@ ATF_TC_HEAD(clone_basic, tc)
ATF_TC_BODY(clone_basic, tc)
{
sigset_t mask;
- void *allocstack, *stack;
+ void *stack = getstack();
pid_t pid;
volatile long frobme[2];
int stat;
- allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANON, -1, (off_t) 0);
-
- ATF_REQUIRE_ERRNO(errno, allocstack != MAP_FAILED);
-
- stack = allocstack;
-#ifndef __MACHINE_STACK_GROWS_UP
- stack = (char *)stack + STACKSIZE;
-#endif
-
printf("parent: stack = %p, frobme = %p\n", stack, frobme);
fflush(stdout);
@@ -158,7 +170,7 @@ ATF_TC_BODY(clone_basic, tc)
/*NOTREACHED*/
}
- ATF_REQUIRE_ERRNO(errno, munmap(allocstack, STACKSIZE) != -1);
+ putstack(stack);
}
ATF_TC(clone_null_stack);
@@ -190,16 +202,9 @@ ATF_TC_HEAD(clone_null_func, tc)
ATF_TC_BODY(clone_null_func, tc)
{
- void *allocstack, *stack;
+ void *stack = getstack();
int rv;
- allocstack = mmap(NULL, STACKSIZE, PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANON, -1, (off_t) 0);
- ATF_REQUIRE_ERRNO(errno, allocstack != MAP_FAILED);
- stack = allocstack;
-#ifndef __MACHINE_STACK_GROWS_UP
- stack = (char *)stack + STACKSIZE;
-#endif
errno = 0;
rv = __clone(0, stack,
@@ -208,7 +213,7 @@ ATF_TC_BODY(clone_null_func, tc)
ATF_REQUIRE_EQ(rv, -1);
ATF_REQUIRE_EQ(errno, EINVAL);
- ATF_REQUIRE_ERRNO(errno, munmap(allocstack, STACKSIZE) != -1);
+ putstack(stack);
}
ATF_TC(clone_out_of_proc);
@@ -222,6 +227,7 @@ ATF_TC_HEAD(clone_out_of_proc, tc)
ATF_TC_BODY(clone_out_of_proc, tc)
{
+ char *stack = getstack();
struct rlimit rl;
int rv;
@@ -233,11 +239,12 @@ ATF_TC_BODY(clone_out_of_proc, tc)
ATF_REQUIRE_ERRNO(errno, setrlimit(RLIMIT_NPROC, &rl) != -1);
errno = 0;
- rv = __clone(dummy, malloc(10240),
+ rv = __clone(dummy, stack,
CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|SIGCHLD, (void *)&rl);
ATF_REQUIRE_EQ(rv, -1);
ATF_REQUIRE_EQ(errno, EAGAIN);
+ putstack(stack);
}
ATF_TP_ADD_TCS(tp)
diff --git a/lib/libc/sys/t_dup.c b/lib/libc/sys/t_dup.c
index 93ad718c5497..219904a6779b 100644
--- a/lib/libc/sys/t_dup.c
+++ b/lib/libc/sys/t_dup.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_dup.c,v 1.9 2017/01/13 20:31:53 christos Exp $ */
+/* $NetBSD: t_dup.c,v 1.10 2024/05/20 00:27:53 christos Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_dup.c,v 1.9 2017/01/13 20:31:53 christos Exp $");
+__RCSID("$NetBSD: t_dup.c,v 1.10 2024/05/20 00:27:53 christos Exp $");
#include <sys/resource.h>
#include <sys/stat.h>
@@ -208,10 +208,10 @@ ATF_TC_BODY(dup3_err, tc)
ATF_REQUIRE(fd >= 0);
errno = 0;
- ATF_REQUIRE(dup3(fd, fd, O_CLOEXEC) != -1);
+ ATF_REQUIRE_ERRNO(EINVAL, dup3(fd, fd, O_CLOEXEC) == -1);
errno = 0;
- ATF_REQUIRE_ERRNO(EBADF, dup3(-1, -1, O_CLOEXEC) == -1);
+ ATF_REQUIRE_ERRNO(EINVAL, dup3(-1, -1, O_CLOEXEC) == -1);
errno = 0;
ATF_REQUIRE_ERRNO(EBADF, dup3(fd, -1, O_CLOEXEC) == -1);
diff --git a/lib/libc/sys/t_futex_ops.c b/lib/libc/sys/t_futex_ops.c
index 2941d4e2b6c6..03dd66dbab05 100644
--- a/lib/libc/sys/t_futex_ops.c
+++ b/lib/libc/sys/t_futex_ops.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_futex_ops.c,v 1.5 2020/05/06 05:14:27 thorpej Exp $ */
+/* $NetBSD: t_futex_ops.c,v 1.14 2025/03/05 12:02:00 riastradh Exp $ */
/*-
* Copyright (c) 2019, 2020 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2019, 2020\
The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_futex_ops.c,v 1.5 2020/05/06 05:14:27 thorpej Exp $");
+__RCSID("$NetBSD: t_futex_ops.c,v 1.14 2025/03/05 12:02:00 riastradh Exp $");
#include <sys/fcntl.h>
#include <sys/mman.h>
@@ -49,6 +49,8 @@ __RCSID("$NetBSD: t_futex_ops.c,v 1.5 2020/05/06 05:14:27 thorpej Exp $");
#include <libc/include/futex_private.h>
+#include "h_macros.h"
+
#define LOAD(x) (*(volatile int *)(x))
#define STORE(x, y) *(volatile int *)(x) = (y)
@@ -104,7 +106,7 @@ static long bs_pagesize;
static void
create_lwp_waiter(struct lwp_data *d)
{
- ATF_REQUIRE(_lwp_create(&d->context, 0, &d->lwpid) == 0);
+ RL(_lwp_create(&d->context, 0, &d->lwpid));
}
static void
@@ -116,7 +118,7 @@ exit_lwp_waiter(void)
static void
reap_lwp_waiter(struct lwp_data *d)
{
- ATF_REQUIRE(_lwp_wait(d->lwpid, NULL) == 0);
+ RL(_lwp_wait(d->lwpid, NULL));
}
static void
@@ -124,7 +126,7 @@ create_proc_waiter(struct lwp_data *d)
{
pid_t pid;
- ATF_REQUIRE((pid = fork()) != -1);
+ RL(pid = fork());
if (pid == 0) {
(*d->func)(d);
_exit(666); /* backstop */
@@ -141,11 +143,14 @@ exit_proc_waiter(void)
static void
reap_proc_waiter(struct lwp_data *d)
{
+ pid_t pid;
int status;
- ATF_REQUIRE(waitpid(d->child, &status, 0) == d->child);
- ATF_REQUIRE(WIFEXITED(status));
- ATF_REQUIRE(WEXITSTATUS(status) == 0);
+ RL(pid = waitpid(d->child, &status, 0));
+ ATF_CHECK_EQ_MSG(pid, d->child,
+ "pid=%lld d->child=%lld", (long long)pid, (long long)d->child);
+ ATF_CHECK_MSG(WIFEXITED(status), "status=0x%x", status);
+ ATF_CHECK_EQ_MSG(WEXITSTATUS(status), 0, "status=0x%x", status);
}
static void
@@ -153,10 +158,12 @@ setup_lwp_context(struct lwp_data *d, void (*func)(void *))
{
memset(d, 0, sizeof(*d));
- d->stack_base = mmap(NULL, STACK_SIZE, PROT_READ | PROT_WRITE,
- MAP_ANON | MAP_STACK | MAP_PRIVATE, -1, 0);
- ATF_REQUIRE(d->stack_base != MAP_FAILED);
- _lwp_makecontext(&d->context, func, d, NULL, d->stack_base, STACK_SIZE);
+ REQUIRE_LIBC(d->stack_base = mmap(NULL, STACK_SIZE,
+ PROT_READ | PROT_WRITE, MAP_ANON | MAP_STACK | MAP_PRIVATE,
+ -1, 0),
+ MAP_FAILED);
+ _lwp_makecontext(&d->context, func, d, NULL, d->stack_base,
+ STACK_SIZE);
d->threadid = 0;
d->func = func;
}
@@ -173,7 +180,7 @@ simple_test_waiter_lwp(void *arg)
membar_sync();
if (__futex(d->futex_ptr, d->wait_op | d->op_flags,
- d->block_val, NULL, NULL, 0, d->bitset) == -1) {
+ d->block_val, NULL, NULL, 0, d->bitset) == -1) {
d->futex_error = errno;
membar_sync();
atomic_dec_uint(&nlwps_running);
@@ -191,14 +198,15 @@ simple_test_waiter_lwp(void *arg)
static bool
verify_zero_bs(void)
{
+ ssize_t nread;
if (bs_verify_buffer == NULL) {
- bs_verify_buffer = malloc(bs_pagesize);
- ATF_REQUIRE(bs_verify_buffer != NULL);
+ REQUIRE_LIBC(bs_verify_buffer = malloc(bs_pagesize), NULL);
}
- ATF_REQUIRE(pread(bs_fd, bs_verify_buffer,
- bs_pagesize, 0) == bs_pagesize);
+ RL(nread = pread(bs_fd, bs_verify_buffer, bs_pagesize, 0));
+ ATF_REQUIRE_EQ_MSG(nread, bs_pagesize, "nread=%zu bs_pagesize=%lu",
+ nread, bs_pagesize);
return (memcmp(bs_verify_buffer, bs_source_buffer, bs_pagesize) == 0);
}
@@ -206,25 +214,24 @@ verify_zero_bs(void)
static void
create_bs(int map_flags)
{
+ ssize_t nwrit;
bs_pagesize = sysconf(_SC_PAGESIZE);
- ATF_REQUIRE(bs_pagesize > 0);
+ ATF_REQUIRE_MSG(bs_pagesize > 0, "bs_pagesize=%ld", bs_pagesize);
if ((map_flags & (MAP_FILE | MAP_ANON)) == MAP_FILE) {
- bs_source_buffer = calloc(1, bs_pagesize);
- ATF_REQUIRE(bs_source_buffer != NULL);
+ REQUIRE_LIBC(bs_source_buffer = calloc(1, bs_pagesize), NULL);
- bs_fd = open(bs_path, O_RDWR | O_CREAT | O_EXCL, 0644);
- ATF_REQUIRE(bs_fd != -1);
-
- ATF_REQUIRE(pwrite(bs_fd, bs_source_buffer,
- bs_pagesize, 0) == bs_pagesize);
+ RL(bs_fd = open(bs_path, O_RDWR | O_CREAT | O_EXCL, 0644));
+ RL(nwrit = pwrite(bs_fd, bs_source_buffer, bs_pagesize, 0));
+ ATF_REQUIRE_EQ_MSG(nwrit, bs_pagesize,
+ "nwrit=%zu bs_pagesize=%lu", nwrit, bs_pagesize);
ATF_REQUIRE(verify_zero_bs());
}
- bs_addr = mmap(NULL, bs_pagesize, PROT_READ | PROT_WRITE,
- map_flags | MAP_HASSEMAPHORE, bs_fd, 0);
- ATF_REQUIRE(bs_addr != MAP_FAILED);
+ REQUIRE_LIBC(bs_addr = mmap(NULL, bs_pagesize, PROT_READ | PROT_WRITE,
+ map_flags | MAP_HASSEMAPHORE, bs_fd, 0),
+ MAP_FAILED);
}
static void
@@ -283,7 +290,7 @@ wait_wake_test_waiter_lwp(void *arg)
/* This will block because *futex_ptr == 1. */
if (__futex(d->futex_ptr, FUTEX_WAIT | d->op_flags,
- 1, NULL, NULL, 0, 0) == -1) {
+ 1, NULL, NULL, 0, 0) == -1) {
STORE(d->error_ptr, errno);
(*d->exit_func)();
} else {
@@ -305,7 +312,7 @@ wait_wake_test_waiter_lwp(void *arg)
/* This will not block because futex_word != 666. */
if (__futex(d->futex_ptr, FUTEX_WAIT | d->op_flags,
- 666, NULL, NULL, 0, 0) == -1) {
+ 666, NULL, NULL, 0, 0) == -1) {
/* This SHOULD be EAGAIN. */
STORE(d->error_ptr, errno);
}
@@ -318,13 +325,14 @@ wait_wake_test_waiter_lwp(void *arg)
static void
do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr,
- void (*create_func)(struct lwp_data *),
- void (*exit_func)(void),
- void (*reap_func)(struct lwp_data *),
- int flags)
+ void (*create_func)(struct lwp_data *),
+ void (*exit_func)(void),
+ void (*reap_func)(struct lwp_data *),
+ int flags)
{
struct lwp_data *wlwp = &lwp_data[WAITER_LWP0];
int tries;
+ int n;
if (error_ptr == NULL)
error_ptr = &wlwp->futex_error;
@@ -359,7 +367,7 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr,
sleep(1);
}
membar_sync();
- ATF_REQUIRE(LOAD(futex_ptr) == 1);
+ ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 1, "LOAD(futex_ptr)=%d", n);
/*
* If the LWP is blocked in the futex, it will not have yet
@@ -374,16 +382,16 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr,
sleep(1);
}
membar_sync();
- ATF_REQUIRE(LOAD(error_ptr) == -1);
+ ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), -1, "error=%d", n);
/* Make sure invalid #wakes in rejected. */
ATF_REQUIRE_ERRNO(EINVAL,
__futex(futex_ptr, FUTEX_WAKE | flags,
- -1, NULL, NULL, 0, 0) == -1);
+ -1, NULL, NULL, 0, 0) == -1);
DPRINTF(("futex_basic_wait_wake: waking 1 waiter\n"));
- ATF_REQUIRE(__futex(futex_ptr, FUTEX_WAKE | flags,
- 1, NULL, NULL, 0, 0) == 1);
+ RL(n = __futex(futex_ptr, FUTEX_WAKE | flags, 1, NULL, NULL, 0, 0));
+ ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n);
DPRINTF(("futex_basic_wait_wake: checking for successful wake (%d)\n",
LOAD(error_ptr)));
@@ -394,7 +402,7 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr,
sleep(1);
}
membar_sync();
- ATF_REQUIRE(LOAD(error_ptr) == 0);
+ ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), 0, "error=%d", n);
STORE(futex_ptr, 0);
membar_sync();
@@ -407,7 +415,7 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr,
sleep(1);
}
membar_sync();
- ATF_REQUIRE(LOAD(futex_ptr) == 2);
+ ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 2, "LOAD(futex_ptr)=%d", n);
STORE(futex_ptr, 3);
membar_sync();
@@ -420,10 +428,10 @@ do_futex_wait_wake_test(volatile int *futex_ptr, volatile int *error_ptr,
sleep(1);
}
membar_sync();
- ATF_REQUIRE(LOAD(futex_ptr) == 4);
+ ATF_REQUIRE_EQ_MSG((n = LOAD(futex_ptr)), 4, "error=%d", n);
DPRINTF(("futex_basic_wait_wake: checking for expected EGAIN\n"));
- ATF_REQUIRE(LOAD(error_ptr) == EAGAIN);
+ ATF_REQUIRE_EQ_MSG((n = LOAD(error_ptr)), EAGAIN, "error=%d", n);
DPRINTF(("futex_basic_wait_wake: reaping LWP %d\n", wlwp->lwpid));
(*reap_func)(wlwp);
@@ -438,8 +446,8 @@ ATF_TC_HEAD(futex_basic_wait_wake_private, tc)
ATF_TC_BODY(futex_basic_wait_wake_private, tc)
{
do_futex_wait_wake_test(&futex_word, NULL,
- NULL, NULL, NULL,
- FUTEX_PRIVATE_FLAG);
+ NULL, NULL, NULL,
+ FUTEX_PRIVATE_FLAG);
}
ATF_TC_CLEANUP(futex_basic_wait_wake_private, tc)
{
@@ -455,8 +463,8 @@ ATF_TC_HEAD(futex_basic_wait_wake_shared, tc)
ATF_TC_BODY(futex_basic_wait_wake_shared, tc)
{
do_futex_wait_wake_test(&futex_word, NULL,
- NULL, NULL, NULL,
- 0);
+ NULL, NULL, NULL,
+ 0);
}
ATF_TC_CLEANUP(futex_basic_wait_wake_shared, tc)
{
@@ -473,8 +481,8 @@ ATF_TC_BODY(futex_wait_wake_anon_bs_private, tc)
{
create_bs(MAP_ANON | MAP_PRIVATE);
do_futex_wait_wake_test(&bs_addr[0], NULL,
- NULL, NULL, NULL,
- FUTEX_PRIVATE_FLAG);
+ NULL, NULL, NULL,
+ FUTEX_PRIVATE_FLAG);
}
ATF_TC_CLEANUP(futex_wait_wake_anon_bs_private, tc)
{
@@ -491,8 +499,8 @@ ATF_TC_BODY(futex_wait_wake_anon_bs_shared, tc)
{
create_bs(MAP_ANON | MAP_PRIVATE);
do_futex_wait_wake_test(&bs_addr[0], NULL,
- NULL, NULL, NULL,
- 0);
+ NULL, NULL, NULL,
+ 0);
}
ATF_TC_CLEANUP(futex_wait_wake_anon_bs_shared, tc)
{
@@ -514,9 +522,9 @@ ATF_TC_BODY(futex_wait_wake_file_bs_private, tc)
*/
create_bs(MAP_FILE | MAP_SHARED);
do_futex_wait_wake_test(&bs_addr[0], NULL,
- NULL, NULL, NULL,
- FUTEX_PRIVATE_FLAG);
- ATF_REQUIRE(! verify_zero_bs());
+ NULL, NULL, NULL,
+ FUTEX_PRIVATE_FLAG);
+ ATF_REQUIRE(!verify_zero_bs());
}
ATF_TC_CLEANUP(futex_wait_wake_file_bs_private, tc)
{
@@ -533,8 +541,8 @@ ATF_TC_BODY(futex_wait_wake_file_bs_cow_private, tc)
{
create_bs(MAP_FILE | MAP_PRIVATE);
do_futex_wait_wake_test(&bs_addr[0], NULL,
- NULL, NULL, NULL,
- FUTEX_PRIVATE_FLAG);
+ NULL, NULL, NULL,
+ FUTEX_PRIVATE_FLAG);
ATF_REQUIRE(verify_zero_bs());
}
ATF_TC_CLEANUP(futex_wait_wake_file_bs_cow_private, tc)
@@ -552,9 +560,9 @@ ATF_TC_BODY(futex_wait_wake_file_bs_shared, tc)
{
create_bs(MAP_FILE | MAP_SHARED);
do_futex_wait_wake_test(&bs_addr[0], NULL,
- NULL, NULL, NULL,
- 0);
- ATF_REQUIRE(! verify_zero_bs());
+ NULL, NULL, NULL,
+ 0);
+ ATF_REQUIRE(!verify_zero_bs());
}
ATF_TC_CLEANUP(futex_wait_wake_file_bs_shared, tc)
{
@@ -576,8 +584,8 @@ ATF_TC_BODY(futex_wait_wake_file_bs_cow_shared, tc)
*/
create_bs(MAP_FILE | MAP_PRIVATE);
do_futex_wait_wake_test(&bs_addr[0], NULL,
- NULL, NULL, NULL,
- 0);
+ NULL, NULL, NULL,
+ 0);
ATF_REQUIRE(verify_zero_bs());
}
ATF_TC_CLEANUP(futex_wait_wake_file_bs_cow_shared, tc)
@@ -595,10 +603,10 @@ ATF_TC_BODY(futex_wait_wake_anon_bs_shared_proc, tc)
{
create_bs(MAP_ANON | MAP_SHARED);
do_futex_wait_wake_test(&bs_addr[0], &bs_addr[1],
- create_proc_waiter,
- exit_proc_waiter,
- reap_proc_waiter,
- 0);
+ create_proc_waiter,
+ exit_proc_waiter,
+ reap_proc_waiter,
+ 0);
}
ATF_TC_CLEANUP(futex_wait_wake_anon_bs_shared_proc, tc)
{
@@ -615,10 +623,10 @@ ATF_TC_BODY(futex_wait_wake_file_bs_shared_proc, tc)
{
create_bs(MAP_FILE | MAP_SHARED);
do_futex_wait_wake_test(&bs_addr[0], &bs_addr[1],
- create_proc_waiter,
- exit_proc_waiter,
- reap_proc_waiter,
- 0);
+ create_proc_waiter,
+ exit_proc_waiter,
+ reap_proc_waiter,
+ 0);
}
ATF_TC_CLEANUP(futex_wait_wake_file_bs_shared_proc, tc)
{
@@ -647,7 +655,7 @@ do_futex_wait_wake_bitset_test(int flags)
{
struct lwp_data *wlwp0 = &lwp_data[WAITER_LWP0];
struct lwp_data *wlwp1 = &lwp_data[WAITER_LWP1];
- int i, tries;
+ int i, tries, n;
for (i = WAITER_LWP0; i <= WAITER_LWP1; i++) {
setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp);
@@ -662,8 +670,8 @@ do_futex_wait_wake_bitset_test(int flags)
STORE(&futex_word, 1);
membar_sync();
- ATF_REQUIRE(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid) == 0);
- ATF_REQUIRE(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid) == 0);
+ RL(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid));
+ RL(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid));
for (tries = 0; tries < 5; tries++) {
membar_sync();
@@ -672,25 +680,30 @@ do_futex_wait_wake_bitset_test(int flags)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 2, "waiters failed to start");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 2,
+ "waiters failed to start, nlwps_running=%u", nlwps_running);
/* Ensure they're blocked. */
- ATF_REQUIRE(wlwp0->futex_error == -1);
- ATF_REQUIRE(wlwp1->futex_error == -1);
+ ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, -1, "wlwp0->futex_error=%d",
+ wlwp0->futex_error);
+ ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, -1, "wlwp1->futex_error=%d",
+ wlwp1->futex_error);
/* Make sure invalid #wakes in rejected. */
ATF_REQUIRE_ERRNO(EINVAL,
__futex(&futex_word, FUTEX_WAKE_BITSET | flags,
- -1, NULL, NULL, 0, 0) == -1);
+ -1, NULL, NULL, 0, 0) == -1);
/* This should result in no wakeups because no bits are set. */
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_BITSET | flags,
- INT_MAX, NULL, NULL, 0, 0) == 0);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags,
+ INT_MAX, NULL, NULL, 0, 0));
+ ATF_REQUIRE_EQ_MSG(n, 0, "n=%d wakeups", n);
/* This should result in no wakeups because the wrongs bits are set. */
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_BITSET | flags,
- INT_MAX, NULL, NULL, 0,
- ~(wlwp0->bitset | wlwp1->bitset)) == 0);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags,
+ INT_MAX, NULL, NULL, 0,
+ ~(wlwp0->bitset | wlwp1->bitset)));
+ ATF_REQUIRE_EQ_MSG(n, 0, "n=%d wakeups", n);
/* Trust, but verify. */
sleep(1);
@@ -701,12 +714,13 @@ do_futex_wait_wake_bitset_test(int flags)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 2, "waiters exited unexpectedly");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 2,
+ "waiters exited unexpectedly, nlwps_running=%u", nlwps_running);
/* Wake up the first LWP. */
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_BITSET | flags,
- INT_MAX, NULL, NULL, 0,
- wlwp0->bitset) == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags,
+ INT_MAX, NULL, NULL, 0, wlwp0->bitset));
+ ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n);
sleep(1);
for (tries = 0; tries < 5; tries++) {
membar_sync();
@@ -715,14 +729,16 @@ do_futex_wait_wake_bitset_test(int flags)
sleep(1);
}
membar_sync();
- ATF_REQUIRE(nlwps_running == 1);
- ATF_REQUIRE(wlwp0->futex_error == 0);
- ATF_REQUIRE(_lwp_wait(wlwp0->lwpid, NULL) == 0);
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "nlwps_running=%u",
+ nlwps_running);
+ ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, 0, "wlwp0->futex_error=%d",
+ wlwp0->futex_error);
+ RL(_lwp_wait(wlwp0->lwpid, NULL));
/* Wake up the second LWP. */
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_BITSET | flags,
- INT_MAX, NULL, NULL, 0,
- wlwp1->bitset) == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_BITSET | flags,
+ INT_MAX, NULL, NULL, 0, wlwp1->bitset));
+ ATF_REQUIRE_EQ_MSG(n, 1, "n=%d wakeups", n);
sleep(1);
for (tries = 0; tries < 5; tries++) {
membar_sync();
@@ -731,9 +747,11 @@ do_futex_wait_wake_bitset_test(int flags)
sleep(1);
}
membar_sync();
- ATF_REQUIRE(nlwps_running == 0);
- ATF_REQUIRE(wlwp1->futex_error == 0);
- ATF_REQUIRE(_lwp_wait(wlwp1->lwpid, NULL) == 0);
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "nlwps_running=%u",
+ nlwps_running);
+ ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, 0, "wlwp1->futex_error=%d",
+ wlwp1->futex_error);
+ RL(_lwp_wait(wlwp1->lwpid, NULL));
}
ATF_TC_WITH_CLEANUP(futex_wait_wake_bitset);
@@ -762,7 +780,7 @@ do_futex_requeue_test(int flags, int op)
struct lwp_data *wlwp3 = &lwp_data[WAITER_LWP3];
const int good_val3 = (op == FUTEX_CMP_REQUEUE) ? 1 : 0;
const int bad_val3 = (op == FUTEX_CMP_REQUEUE) ? 666 : 0;
- int i, tries;
+ int i, tries, n;
for (i = WAITER_LWP0; i <= WAITER_LWP3; i++) {
setup_lwp_context(&lwp_data[i], simple_test_waiter_lwp);
@@ -778,10 +796,10 @@ do_futex_requeue_test(int flags, int op)
STORE(&futex_word1, 1);
membar_sync();
- ATF_REQUIRE(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid) == 0);
- ATF_REQUIRE(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid) == 0);
- ATF_REQUIRE(_lwp_create(&wlwp2->context, 0, &wlwp2->lwpid) == 0);
- ATF_REQUIRE(_lwp_create(&wlwp3->context, 0, &wlwp3->lwpid) == 0);
+ RL(_lwp_create(&wlwp0->context, 0, &wlwp0->lwpid));
+ RL(_lwp_create(&wlwp1->context, 0, &wlwp1->lwpid));
+ RL(_lwp_create(&wlwp2->context, 0, &wlwp2->lwpid));
+ RL(_lwp_create(&wlwp3->context, 0, &wlwp3->lwpid));
for (tries = 0; tries < 5; tries++) {
membar_sync();
@@ -790,22 +808,27 @@ do_futex_requeue_test(int flags, int op)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 4, "waiters failed to start");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 4,
+ "waiters failed to start, nlwps_running=%u", nlwps_running);
/* Ensure they're blocked. */
- ATF_REQUIRE(wlwp0->futex_error == -1);
- ATF_REQUIRE(wlwp1->futex_error == -1);
- ATF_REQUIRE(wlwp2->futex_error == -1);
- ATF_REQUIRE(wlwp3->futex_error == -1);
+ ATF_REQUIRE_EQ_MSG(wlwp0->futex_error, -1, "wlwp0->futex_error=%d",
+ wlwp0->futex_error);
+ ATF_REQUIRE_EQ_MSG(wlwp1->futex_error, -1, "wlwp1->futex_error=%d",
+ wlwp1->futex_error);
+ ATF_REQUIRE_EQ_MSG(wlwp2->futex_error, -1, "wlwp2->futex_error=%d",
+ wlwp2->futex_error);
+ ATF_REQUIRE_EQ_MSG(wlwp3->futex_error, -1, "wlwp3->futex_error=%d",
+ wlwp3->futex_error);
/* Make sure invalid #wakes and #requeues are rejected. */
ATF_REQUIRE_ERRNO(EINVAL,
__futex(&futex_word, op | flags,
- -1, NULL, &futex_word1, INT_MAX, bad_val3) == -1);
+ -1, NULL, &futex_word1, INT_MAX, bad_val3) == -1);
ATF_REQUIRE_ERRNO(EINVAL,
__futex(&futex_word, op | flags,
- 0, NULL, &futex_word1, -1, bad_val3) == -1);
+ 0, NULL, &futex_word1, -1, bad_val3) == -1);
/*
* FUTEX 0: 4 LWPs
@@ -816,7 +839,7 @@ do_futex_requeue_test(int flags, int op)
/* This should fail because the futex_word value is 1. */
ATF_REQUIRE_ERRNO(EAGAIN,
__futex(&futex_word, op | flags,
- 0, NULL, &futex_word1, INT_MAX, bad_val3) == -1);
+ 0, NULL, &futex_word1, INT_MAX, bad_val3) == -1);
}
/*
@@ -825,8 +848,9 @@ do_futex_requeue_test(int flags, int op)
*/
/* Move all waiters from 0 to 1. */
- ATF_REQUIRE(__futex(&futex_word, op | flags,
- 0, NULL, &futex_word1, INT_MAX, good_val3) == 0);
+ RL(n = __futex(&futex_word, op | flags, 0, NULL, &futex_word1,
+ INT_MAX, good_val3));
+ ATF_CHECK_EQ_MSG(n, 4, "n=%d woken or requeued", n);
/*
* FUTEX 0: 0 LWPs
@@ -837,7 +861,7 @@ do_futex_requeue_test(int flags, int op)
/* This should fail because the futex_word1 value is 1. */
ATF_REQUIRE_ERRNO(EAGAIN,
__futex(&futex_word1, op | flags,
- 1, NULL, &futex_word, 1, bad_val3) == -1);
+ 1, NULL, &futex_word, 1, bad_val3) == -1);
}
/*
@@ -846,8 +870,9 @@ do_futex_requeue_test(int flags, int op)
*/
/* Wake one waiter on 1, move one waiter to 0. */
- ATF_REQUIRE(__futex(&futex_word1, op | flags,
- 1, NULL, &futex_word, 1, good_val3) == 1);
+ RL(n = __futex(&futex_word1, op | flags, 1, NULL, &futex_word,
+ 1, good_val3));
+ ATF_CHECK_EQ_MSG(n, 2, "n=%d woken or requeued", n);
/*
* FUTEX 0: 1 LWP
@@ -855,12 +880,14 @@ do_futex_requeue_test(int flags, int op)
*/
/* Wake all waiters on 0 (should be 1). */
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE | flags,
- INT_MAX, NULL, NULL, 0, 0) == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE | flags, INT_MAX, NULL, NULL,
+ 0, 0));
+ ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
/* Wake all waiters on 1 (should be 2). */
- ATF_REQUIRE(__futex(&futex_word1, FUTEX_WAKE | flags,
- INT_MAX, NULL, NULL, 0, 0) == 2);
+ RL(n = __futex(&futex_word1, FUTEX_WAKE | flags, INT_MAX, NULL, NULL,
+ 0, 0));
+ ATF_CHECK_EQ_MSG(n, 2, "n=%d woken", n);
/* Trust, but verify. */
sleep(1);
@@ -871,12 +898,13 @@ do_futex_requeue_test(int flags, int op)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "waiters failed to exit");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 0,
+ "waiters failed to exit, nlwps_running=%u", nlwps_running);
- ATF_REQUIRE(_lwp_wait(wlwp0->lwpid, NULL) == 0);
- ATF_REQUIRE(_lwp_wait(wlwp1->lwpid, NULL) == 0);
- ATF_REQUIRE(_lwp_wait(wlwp2->lwpid, NULL) == 0);
- ATF_REQUIRE(_lwp_wait(wlwp3->lwpid, NULL) == 0);
+ RL(_lwp_wait(wlwp0->lwpid, NULL));
+ RL(_lwp_wait(wlwp1->lwpid, NULL));
+ RL(_lwp_wait(wlwp2->lwpid, NULL));
+ RL(_lwp_wait(wlwp3->lwpid, NULL));
}
ATF_TC_WITH_CLEANUP(futex_requeue);
@@ -909,12 +937,36 @@ ATF_TC_CLEANUP(futex_cmp_requeue, tc)
do_cleanup();
}
+ATF_TC(futex_cmp_requeue_trivial);
+ATF_TC_HEAD(futex_cmp_requeue_trivial, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "tests trivial cases of futex CMP_REQUEUE operations");
+}
+ATF_TC_BODY(futex_cmp_requeue_trivial, tc)
+{
+ int nwoken;
+
+ futex_word = 123;
+ futex_word1 = 456; /* should be ignored */
+ ATF_CHECK_ERRNO(EAGAIN, __futex(&futex_word, FUTEX_CMP_REQUEUE,
+ /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 0) == -1);
+ ATF_CHECK_ERRNO(EAGAIN, __futex(&futex_word, FUTEX_CMP_REQUEUE,
+ /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 122) == -1);
+ nwoken = __futex(&futex_word, FUTEX_CMP_REQUEUE,
+ /*nwake*/1, NULL, &futex_word1, /*nrequeue*/1, 123);
+ ATF_CHECK_MSG(nwoken != -1, "errno=%d (%s)", errno, strerror(errno));
+ ATF_CHECK_EQ_MSG(nwoken, 0, "nwoken=%d", nwoken);
+ ATF_CHECK_EQ_MSG(futex_word, 123, "futex_word=%d", futex_word);
+ ATF_CHECK_EQ_MSG(futex_word1, 456, "futex_word1=%d", futex_word1);
+}
+
/*****************************************************************************/
static void
do_futex_wake_op_op_test(int flags)
{
- int op;
+ int op, n;
futex_word = 0;
futex_word1 = 0;
@@ -928,61 +980,85 @@ do_futex_wake_op_op_test(int flags)
* rejecting unaligned futex addresses here.
*/
op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE_ERRNO(EINVAL,
+ ATF_CHECK_ERRNO(EINVAL,
__futex((int *)1, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 0, op) == -1);
- ATF_REQUIRE(futex_word1 == 0);
+ 0, NULL, &futex_word1, 0, op) == -1);
+ ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
- ATF_REQUIRE_ERRNO(EINVAL,
+ ATF_CHECK_ERRNO(EINVAL,
__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, (int *)1, 0, op) == -1);
- ATF_REQUIRE(futex_word == 0);
+ 0, NULL, (int *)1, 0, op) == -1);
+ ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word);
/* Check unmapped uaddr2 handling, too. */
- ATF_REQUIRE_ERRNO(EFAULT,
+ ATF_CHECK_ERRNO(EFAULT,
__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, NULL, 0, op) == -1);
- ATF_REQUIRE(futex_word == 0);
+ 0, NULL, NULL, 0, op) == -1);
+ ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word);
op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 0, op) == 0);
- ATF_REQUIRE(futex_word1 == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 0, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
op = FUTEX_OP(FUTEX_OP_ADD, 1, FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 0, op) == 0);
- ATF_REQUIRE(futex_word1 == 2);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 0, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
op = FUTEX_OP(FUTEX_OP_OR, 2, FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 0, op) == 0);
- ATF_REQUIRE(futex_word1 == 2);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 0, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
/* This should fail because of invalid shift value 32. */
op = FUTEX_OP(FUTEX_OP_OR | FUTEX_OP_OPARG_SHIFT, 32,
- FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE_ERRNO(EINVAL,
+ FUTEX_OP_CMP_EQ, 0);
+ ATF_CHECK_ERRNO(EINVAL,
__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 0, op) == -1);
- ATF_REQUIRE(futex_word1 == 2);
+ 0, NULL, &futex_word1, 0, op) == -1);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
op = FUTEX_OP(FUTEX_OP_OR | FUTEX_OP_OPARG_SHIFT, 31,
- FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 0, op) == 0);
- ATF_REQUIRE(futex_word1 == (int)0x80000002);
+ FUTEX_OP_CMP_EQ, 0);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 0, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, (int)0x80000002,
+ "futex_word1=0x%x", futex_word1);
op = FUTEX_OP(FUTEX_OP_ANDN | FUTEX_OP_OPARG_SHIFT, 31,
- FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 0, op) == 0);
- ATF_REQUIRE(futex_word1 == 2);
+ FUTEX_OP_CMP_EQ, 0);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 0, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
op = FUTEX_OP(FUTEX_OP_XOR, 2, FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 0, op) == 0);
- ATF_REQUIRE(futex_word1 == 0);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 0, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
+
+ /*
+ * Verify oparg is sign-extended.
+ */
+ futex_word1 = 0;
+ op = FUTEX_OP(FUTEX_OP_SET, 0xfff, FUTEX_OP_CMP_EQ, 0);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 0, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1);
+
+ futex_word1 = 0;
+ op = FUTEX_OP(FUTEX_OP_SET, -1, FUTEX_OP_CMP_EQ, 0);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 0, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, -1, "futex_word1=%d", futex_word1);
}
ATF_TC_WITH_CLEANUP(futex_wake_op_op);
@@ -1016,8 +1092,7 @@ create_wake_op_test_lwps(int flags)
lwp_data[i].block_val = 0;
lwp_data[i].bitset = 0;
lwp_data[i].wait_op = FUTEX_WAIT;
- ATF_REQUIRE(_lwp_create(&lwp_data[i].context, 0,
- &lwp_data[i].lwpid) == 0);
+ RL(_lwp_create(&lwp_data[i].context, 0, &lwp_data[i].lwpid));
}
for (i = 0; i < 5; i++) {
@@ -1027,11 +1102,14 @@ create_wake_op_test_lwps(int flags)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 6, "waiters failed to start");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 6,
+ "waiters failed to start, nlwps_running=%u", nlwps_running);
/* Ensure they're blocked. */
for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) {
- ATF_REQUIRE(lwp_data[i].futex_error == -1);
+ ATF_REQUIRE_EQ_MSG(lwp_data[i].futex_error, -1,
+ "i=%d lwp_data[i].futex_error=%d",
+ i, lwp_data[i].futex_error);
}
}
@@ -1041,14 +1119,14 @@ reap_wake_op_test_lwps(void)
int i;
for (i = WAITER_LWP0; i <= WAITER_LWP5; i++) {
- ATF_REQUIRE(_lwp_wait(lwp_data[i].lwpid, NULL) == 0);
+ RL(_lwp_wait(lwp_data[i].lwpid, NULL));
}
}
static void
do_futex_wake_op_cmp_test(int flags)
{
- int tries, op;
+ int tries, op, n;
futex_word = 0;
membar_sync();
@@ -1061,70 +1139,97 @@ do_futex_wake_op_cmp_test(int flags)
create_wake_op_test_lwps(flags);
/* #LWPs = 6 */
+ futex_word1 = 0xfff;
+ op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 0xfff);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
+
+ futex_word1 = 0xfff;
+ op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, -1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
+
op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 1);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 0);
- ATF_REQUIRE(futex_word1 == 0);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 0, "futex_word1=%d", futex_word1);
- op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 1);
- ATF_REQUIRE(futex_word1 == 1);
+ futex_word1 = -1;
+ op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_EQ, 0xfff);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
/* #LWPs = 5 */
op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_NE, 1);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 0);
- ATF_REQUIRE(futex_word1 == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_NE, 2);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 1);
- ATF_REQUIRE(futex_word1 == 2);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
/* #LWPs = 4 */
op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 2);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 0);
- ATF_REQUIRE(futex_word1 == 2);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_LT, 3);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 1);
- ATF_REQUIRE(futex_word1 == 2);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
/* #LWPs = 3 */
op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 0);
- ATF_REQUIRE(futex_word1 == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
op = FUTEX_OP(FUTEX_OP_SET, 1, FUTEX_OP_CMP_LE, 1);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 1);
- ATF_REQUIRE(futex_word1 == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 1, "futex_word1=%d", futex_word1);
/* #LWPs = 2 */
op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GT, 3);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 0);
- ATF_REQUIRE(futex_word1 == 3);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 3, "futex_word1=%d", futex_word1);
op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GT, 2);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 1);
- ATF_REQUIRE(futex_word1 == 2);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
/* #LWPs = 1 */
op = FUTEX_OP(FUTEX_OP_SET, 3, FUTEX_OP_CMP_GE, 4);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 0);
- ATF_REQUIRE(futex_word1 == 3);
-
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 0, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 3, "futex_word1=%d", futex_word1);
+
op = FUTEX_OP(FUTEX_OP_SET, 2, FUTEX_OP_CMP_GE, 3);
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE_OP | flags,
- 0, NULL, &futex_word1, 1, op) == 1);
- ATF_REQUIRE(futex_word1 == 2);
+ RL(n = __futex(&futex_word, FUTEX_WAKE_OP | flags,
+ 0, NULL, &futex_word1, 1, op));
+ ATF_CHECK_EQ_MSG(n, 1, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word1, 2, "futex_word1=%d", futex_word1);
/* #LWPs = 0 */
@@ -1137,7 +1242,8 @@ do_futex_wake_op_cmp_test(int flags)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "waiters failed to exit");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 0,
+ "waiters failed to exit, nlwps_running=%u", nlwps_running);
reap_wake_op_test_lwps();
@@ -1149,11 +1255,12 @@ do_futex_wake_op_cmp_test(int flags)
create_wake_op_test_lwps(flags);
/* #LWPs = 6 */
- ATF_REQUIRE(futex_word == 0);
+ ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word);
op = FUTEX_OP(FUTEX_OP_SET, 0, FUTEX_OP_CMP_EQ, 666);
- ATF_REQUIRE(__futex(&futex_word1, FUTEX_WAKE_OP | flags,
- INT_MAX, NULL, &futex_word, 0, op) == 6);
- ATF_REQUIRE(futex_word == 0);
+ RL(n = __futex(&futex_word1, FUTEX_WAKE_OP | flags,
+ INT_MAX, NULL, &futex_word, 0, op));
+ ATF_CHECK_EQ_MSG(n, 6, "n=%d woken", n);
+ ATF_CHECK_EQ_MSG(futex_word, 0, "futex_word=%d", futex_word);
/* #LWPs = 0 */
@@ -1166,7 +1273,8 @@ do_futex_wake_op_cmp_test(int flags)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "waiters failed to exit");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 0,
+ "waiters failed to exit, nlwps_running=%u", nlwps_running);
reap_wake_op_test_lwps();
}
@@ -1188,6 +1296,10 @@ ATF_TC_CLEANUP(futex_wake_op_cmp, tc)
/*****************************************************************************/
+
+
+/*****************************************************************************/
+
static void
do_futex_wait_timeout(bool relative, clockid_t clock)
{
@@ -1198,7 +1310,7 @@ do_futex_wait_timeout(bool relative, clockid_t clock)
if (clock == CLOCK_REALTIME)
op |= FUTEX_CLOCK_REALTIME;
- ATF_REQUIRE(clock_gettime(clock, &deadline) == 0);
+ RL(clock_gettime(clock, &deadline));
deadline.tv_sec += 2;
if (relative) {
ts.tv_sec = 2;
@@ -1210,14 +1322,20 @@ do_futex_wait_timeout(bool relative, clockid_t clock)
futex_word = 1;
ATF_REQUIRE_ERRNO(ETIMEDOUT,
__futex(&futex_word, op | FUTEX_PRIVATE_FLAG,
- 1, &ts, NULL, 0, FUTEX_BITSET_MATCH_ANY) == -1);
+ 1, &ts, NULL, 0, FUTEX_BITSET_MATCH_ANY) == -1);
/* Can't reliably check CLOCK_REALTIME in the presence of NTP. */
if (clock != CLOCK_REALTIME) {
- ATF_REQUIRE(clock_gettime(clock, &ts) == 0);
- ATF_REQUIRE(ts.tv_sec >= deadline.tv_sec);
- ATF_REQUIRE(ts.tv_sec > deadline.tv_sec ||
- ts.tv_nsec >= deadline.tv_nsec);
+ RL(clock_gettime(clock, &ts));
+ ATF_CHECK_MSG(ts.tv_sec >= deadline.tv_sec,
+ "ts=%lld.%09ldsec deadline=%lld.%09ldsec",
+ (long long)ts.tv_sec, ts.tv_nsec,
+ (long long)deadline.tv_sec, deadline.tv_nsec);
+ ATF_CHECK_MSG((ts.tv_sec > deadline.tv_sec ||
+ ts.tv_nsec >= deadline.tv_nsec),
+ "ts=%lld.%09ldsec deadline=%lld.%09ldsec",
+ (long long)ts.tv_sec, ts.tv_nsec,
+ (long long)deadline.tv_sec, deadline.tv_nsec);
}
}
@@ -1281,8 +1399,7 @@ do_futex_wait_evil_unmapped(int map_flags)
create_bs(map_flags);
- old_act = signal(SIGUSR1, sig_noop);
- ATF_REQUIRE(old_act != SIG_ERR);
+ REQUIRE_LIBC(signal(SIGUSR1, sig_noop), SIG_ERR);
setup_lwp_context(&lwp_data[0], simple_test_waiter_lwp);
lwp_data[0].op_flags = 0;
@@ -1291,8 +1408,7 @@ do_futex_wait_evil_unmapped(int map_flags)
lwp_data[0].block_val = 0;
lwp_data[0].bitset = 0;
lwp_data[0].wait_op = FUTEX_WAIT;
- ATF_REQUIRE(_lwp_create(&lwp_data[0].context, 0,
- &lwp_data[0].lwpid) == 0);
+ RL(_lwp_create(&lwp_data[0].context, 0, &lwp_data[0].lwpid));
for (i = 0; i < 5; i++) {
membar_sync();
@@ -1301,16 +1417,18 @@ do_futex_wait_evil_unmapped(int map_flags)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "waiters failed to start");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 1,
+ "waiters failed to start, nlwps_running=%u", nlwps_running);
/* Ensure it's blocked. */
- ATF_REQUIRE(lwp_data[0].futex_error == -1);
+ ATF_REQUIRE_EQ_MSG(lwp_data[0].futex_error, -1,
+ "lwp_data[0].futex_error=%d", lwp_data[0].futex_error);
/* Rudely unmap the backing store. */
cleanup_bs();
/* Signal the waiter so that it leaves the futex. */
- ATF_REQUIRE(_lwp_kill(lwp_data[0].threadid, SIGUSR1) == 0);
+ RL(_lwp_kill(lwp_data[0].threadid, SIGUSR1));
/* Yay! No panic! */
@@ -1347,10 +1465,10 @@ lowpri_simple_test_waiter_lwp(void *arg)
d->threadid = _lwp_self();
- ATF_REQUIRE(_sched_getparam(getpid(), d->threadid, &policy, &sp) == 0);
+ RL(_sched_getparam(getpid(), d->threadid, &policy, &sp));
policy = SCHED_RR;
sp.sched_priority = pri_min;
- ATF_REQUIRE(_sched_setparam(getpid(), d->threadid, policy, &sp) == 0);
+ RL(_sched_setparam(getpid(), d->threadid, policy, &sp));
simple_test_waiter_lwp(arg);
}
@@ -1364,10 +1482,10 @@ highpri_simple_test_waiter_lwp(void *arg)
d->threadid = _lwp_self();
- ATF_REQUIRE(_sched_getparam(getpid(), d->threadid, &policy, &sp) == 0);
+ RL(_sched_getparam(getpid(), d->threadid, &policy, &sp));
policy = SCHED_RR;
sp.sched_priority = pri_max;
- ATF_REQUIRE(_sched_setparam(getpid(), d->threadid, policy, &sp) == 0);
+ RL(_sched_setparam(getpid(), d->threadid, policy, &sp));
simple_test_waiter_lwp(arg);
}
@@ -1378,10 +1496,11 @@ do_test_wake_highest_pri(void)
lwpid_t waiter;
int tries;
long pri;
+ int n;
- ATF_REQUIRE((pri = sysconf(_SC_SCHED_PRI_MIN)) != -1);
+ RL(pri = sysconf(_SC_SCHED_PRI_MIN));
pri_min = (int)pri;
- ATF_REQUIRE((pri = sysconf(_SC_SCHED_PRI_MAX)) != -1);
+ RL(pri = sysconf(_SC_SCHED_PRI_MAX));
pri_max = (int)pri;
futex_word = 0;
@@ -1394,8 +1513,7 @@ do_test_wake_highest_pri(void)
lwp_data[0].block_val = 0;
lwp_data[0].bitset = 0;
lwp_data[0].wait_op = FUTEX_WAIT;
- ATF_REQUIRE(_lwp_create(&lwp_data[0].context, 0,
- &lwp_data[0].lwpid) == 0);
+ RL(_lwp_create(&lwp_data[0].context, 0, &lwp_data[0].lwpid));
for (tries = 0; tries < 5; tries++) {
membar_sync();
@@ -1404,10 +1522,12 @@ do_test_wake_highest_pri(void)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "lowpri waiter failed to start");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 1,
+ "lowpri waiter failed to start, nlwps_running=%u", nlwps_running);
/* Ensure it's blocked. */
- ATF_REQUIRE(lwp_data[0].futex_error == -1);
+ ATF_REQUIRE_EQ_MSG(lwp_data[0].futex_error, -1,
+ "lwp_data[0].futex_error=%d", lwp_data[0].futex_error);
setup_lwp_context(&lwp_data[1], highpri_simple_test_waiter_lwp);
lwp_data[1].op_flags = FUTEX_PRIVATE_FLAG;
@@ -1416,8 +1536,7 @@ do_test_wake_highest_pri(void)
lwp_data[1].block_val = 0;
lwp_data[1].bitset = 0;
lwp_data[1].wait_op = FUTEX_WAIT;
- ATF_REQUIRE(_lwp_create(&lwp_data[1].context, 0,
- &lwp_data[1].lwpid) == 0);
+ RL(_lwp_create(&lwp_data[1].context, 0, &lwp_data[1].lwpid));
for (tries = 0; tries < 5; tries++) {
membar_sync();
@@ -1426,14 +1545,17 @@ do_test_wake_highest_pri(void)
sleep(1);
}
membar_sync();
- ATF_REQUIRE_EQ_MSG(nlwps_running, 2, "highpri waiter failed to start");
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 2,
+ "highpri waiter failed to start, nlwps_running=%u", nlwps_running);
/* Ensure it's blocked. */
- ATF_REQUIRE(lwp_data[1].futex_error == -1);
+ ATF_REQUIRE_EQ_MSG(lwp_data[1].futex_error, -1,
+ "lwp_data[1].futex_error=%d", lwp_data[1].futex_error);
/* Wake the first LWP. We should get the highpri thread. */
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
- 1, NULL, NULL, 0, 0) == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
+ 1, NULL, NULL, 0, 0));
+ ATF_REQUIRE_EQ_MSG(n, 1, "n=%d woken", n);
sleep(1);
for (tries = 0; tries < 5; tries++) {
membar_sync();
@@ -1442,13 +1564,17 @@ do_test_wake_highest_pri(void)
sleep(1);
}
membar_sync();
- ATF_REQUIRE(nlwps_running == 1);
- ATF_REQUIRE(_lwp_wait(0, &waiter) == 0);
- ATF_REQUIRE(waiter == lwp_data[1].threadid);
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 1, "nlwps_running=%u",
+ nlwps_running);
+ RL(_lwp_wait(0, &waiter));
+ ATF_REQUIRE_EQ_MSG(waiter, lwp_data[1].threadid,
+ "waiter=%ld lwp_data[1].threadid=%ld",
+ (long)waiter, (long)lwp_data[1].threadid);
/* Wake the second LWP. We should get the lowpri thread. */
- ATF_REQUIRE(__futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
- 1, NULL, NULL, 0, 0) == 1);
+ RL(n = __futex(&futex_word, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
+ 1, NULL, NULL, 0, 0));
+ ATF_REQUIRE_EQ_MSG(n, 1, "n=%d woken", n);
sleep(1);
for (tries = 0; tries < 5; tries++) {
membar_sync();
@@ -1457,9 +1583,12 @@ do_test_wake_highest_pri(void)
sleep(1);
}
membar_sync();
- ATF_REQUIRE(nlwps_running == 0);
- ATF_REQUIRE(_lwp_wait(0, &waiter) == 0);
- ATF_REQUIRE(waiter == lwp_data[0].threadid);
+ ATF_REQUIRE_EQ_MSG(nlwps_running, 0, "nlwps_running=%u",
+ nlwps_running);
+ RL(_lwp_wait(0, &waiter));
+ ATF_REQUIRE_EQ_MSG(waiter, lwp_data[0].threadid,
+ "waiter=%ld lwp_data[0].threadid=%ld",
+ (long)waiter, (long)lwp_data[0].threadid);
}
ATF_TC_WITH_CLEANUP(futex_wake_highest_pri);
@@ -1507,6 +1636,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, futex_requeue);
ATF_TP_ADD_TC(tp, futex_cmp_requeue);
+ ATF_TP_ADD_TC(tp, futex_cmp_requeue_trivial);
ATF_TP_ADD_TC(tp, futex_wake_op_op);
ATF_TP_ADD_TC(tp, futex_wake_op_cmp);
diff --git a/lib/libc/sys/t_getitimer.c b/lib/libc/sys/t_getitimer.c
index b8d1d87d8bb5..f3a268e15c23 100644
--- a/lib/libc/sys/t_getitimer.c
+++ b/lib/libc/sys/t_getitimer.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_getitimer.c,v 1.4 2022/04/04 19:33:46 andvar Exp $ */
+/* $NetBSD: t_getitimer.c,v 1.6 2026/02/07 01:47:23 riastradh Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_getitimer.c,v 1.4 2022/04/04 19:33:46 andvar Exp $");
+__RCSID("$NetBSD: t_getitimer.c,v 1.6 2026/02/07 01:47:23 riastradh Exp $");
#include <sys/time.h>
@@ -40,15 +40,19 @@ __RCSID("$NetBSD: t_getitimer.c,v 1.4 2022/04/04 19:33:46 andvar Exp $");
#include <string.h>
#include <unistd.h>
-static bool fail;
-static void sighandler(int);
+#include "h_macros.h"
+
+#define TIME_MAX __type_max(time_t)
+
+static sig_atomic_t fired;
+static void sighandler(int);
static void
sighandler(int signo)
{
if (signo == SIGALRM || signo == SIGVTALRM)
- fail = false;
+ fired = 1;
}
ATF_TC(getitimer_empty);
@@ -125,8 +129,7 @@ ATF_TC_BODY(setitimer_basic, tc)
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 0;
- fail = true;
-
+ fired = 0;
ATF_REQUIRE(signal(SIGALRM, sighandler) != SIG_ERR);
ATF_REQUIRE(setitimer(ITIMER_REAL, &it, NULL) == 0);
@@ -139,7 +142,7 @@ ATF_TC_BODY(setitimer_basic, tc)
*/
(void)sleep(1);
- if (fail != false)
+ if (!fired)
atf_tc_fail("timer did not fire");
}
@@ -201,6 +204,43 @@ ATF_TC_BODY(setitimer_old, tc)
atf_tc_fail("setitimer(2) did not store old values");
}
+ATF_TC(setitimer_invalidtime);
+ATF_TC_HEAD(setitimer_invalidtime, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test invalid values in setitimer(2)");
+}
+
+ATF_TC_BODY(setitimer_invalidtime, tc)
+{
+ const struct itimerval it[] = {
+ [0] = { .it_value = {-1, 0} },
+ [1] = { .it_value = {0, -1} },
+ [2] = { .it_value = {0, 1000001} },
+ [3] = { .it_value = {1, 0}, .it_interval = {-1, 0} },
+ [4] = { .it_value = {1, 0}, .it_interval = {0, -1} },
+ [5] = { .it_value = {1, 0}, .it_interval = {0, 1000001} },
+ [6] = { .it_value = {TIME_MAX - 1, 0}, .it_interval = {0, 0} },
+ [7] = { .it_value = {TIME_MAX, 0}, .it_interval = {0, 0} },
+ };
+ sigset_t sigs, mask;
+ unsigned i;
+
+ RL(sigemptyset(&sigs));
+ RL(sigaddset(&sigs, SIGALRM));
+ RL(sigprocmask(SIG_BLOCK, &sigs, &mask));
+
+ for (i = 0; i < __arraycount(it); i++) {
+ fprintf(stderr, "case %u\n", i);
+ ATF_CHECK_ERRNO(EINVAL,
+ setitimer(ITIMER_REAL, &it[i], NULL) == -1);
+ }
+
+ /* Wait up to 2sec to make sure no timer got set anyway. */
+ ATF_CHECK_ERRNO(EAGAIN,
+ sigtimedwait(&sigs, NULL, &(const struct timespec){2, 0}) == -1);
+ RL(sigprocmask(SIG_SETMASK, &mask, NULL));
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -209,6 +249,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, setitimer_basic);
ATF_TP_ADD_TC(tp, setitimer_err);
ATF_TP_ADD_TC(tp, setitimer_old);
+ ATF_TP_ADD_TC(tp, setitimer_invalidtime);
return atf_no_error();
}
diff --git a/lib/libc/sys/t_getrusage.c b/lib/libc/sys/t_getrusage.c
index 03d3f03f39b7..8b54f6f2423d 100644
--- a/lib/libc/sys/t_getrusage.c
+++ b/lib/libc/sys/t_getrusage.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_getrusage.c,v 1.8 2018/05/09 08:45:03 mrg Exp $ */
+/* $NetBSD: t_getrusage.c,v 1.9 2024/04/12 07:16:50 gson Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_getrusage.c,v 1.8 2018/05/09 08:45:03 mrg Exp $");
+__RCSID("$NetBSD: t_getrusage.c,v 1.9 2024/04/12 07:16:50 gson Exp $");
#include <sys/resource.h>
#include <sys/time.h>
@@ -126,6 +126,7 @@ ATF_TC(getrusage_maxrss);
ATF_TC_HEAD(getrusage_maxrss, tc)
{
atf_tc_set_md_var(tc, "descr", "Test maxrss growing with getrusage(2)");
+ atf_tc_set_md_var(tc, "require.memory", "64M");
}
ATF_TC_BODY(getrusage_maxrss, tc)
diff --git a/lib/libc/sys/t_kill.c b/lib/libc/sys/t_kill.c
index 2f4286246ad2..b03b7fbd8040 100644
--- a/lib/libc/sys/t_kill.c
+++ b/lib/libc/sys/t_kill.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_kill.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $ */
+/* $NetBSD: t_kill.c,v 1.2 2024/07/15 06:19:07 riastradh Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_kill.c,v 1.1 2011/07/07 06:57:53 jruoho Exp $");
+__RCSID("$NetBSD: t_kill.c,v 1.2 2024/07/15 06:19:07 riastradh Exp $");
#include <sys/wait.h>
@@ -299,6 +299,18 @@ ATF_TC_BODY(kill_pgrp_zero, tc)
atf_tc_fail("failed to kill(2) a process group");
}
+ATF_TC(kill_int_min);
+ATF_TC_HEAD(kill_int_min, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test kill(INT_MIN) fails with ESRCH");
+}
+
+ATF_TC_BODY(kill_int_min, tc)
+{
+
+ ATF_CHECK_ERRNO(ESRCH, kill(INT_MIN, 0));
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -307,6 +319,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, kill_perm);
ATF_TP_ADD_TC(tp, kill_pgrp_neg);
ATF_TP_ADD_TC(tp, kill_pgrp_zero);
+ ATF_TP_ADD_TC(tp, kill_int_min);
return atf_no_error();
}
diff --git a/lib/libc/sys/t_pipe2.c b/lib/libc/sys/t_pipe2.c
index 12a9394b7f2b..a81b62731c56 100644
--- a/lib/libc/sys/t_pipe2.c
+++ b/lib/libc/sys/t_pipe2.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_pipe2.c,v 1.9 2017/01/13 21:19:45 christos Exp $ */
+/* $NetBSD: t_pipe2.c,v 1.10 2025/07/17 19:50:40 kre Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_pipe2.c,v 1.9 2017/01/13 21:19:45 christos Exp $");
+__RCSID("$NetBSD: t_pipe2.c,v 1.10 2025/07/17 19:50:40 kre Exp $");
#include <atf-c.h>
#include <fcntl.h>
@@ -45,6 +45,13 @@ __RCSID("$NetBSD: t_pipe2.c,v 1.9 2017/01/13 21:19:45 christos Exp $");
#include <errno.h>
#include <sys/resource.h>
+#ifndef FD_CLOFORK
+#define FD_CLOFORK 0
+#endif
+#ifndef O_CLOFORK
+#define O_CLOFORK 0
+#endif
+
static void
run(int flags)
{
@@ -69,6 +76,14 @@ run(int flags)
ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOEXEC) == 0);
}
+ if (flags & O_CLOFORK) {
+ ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOFORK) != 0);
+ ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOFORK) != 0);
+ } else {
+ ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOFORK) == 0);
+ ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOFORK) == 0);
+ }
+
if (flags & O_NONBLOCK) {
ATF_REQUIRE((fcntl(fd[0], F_GETFL) & O_NONBLOCK) != 0);
ATF_REQUIRE((fcntl(fd[1], F_GETFL) & O_NONBLOCK) != 0);
@@ -156,6 +171,21 @@ ATF_TC_BODY(pipe2_cloexec, tc)
run(O_CLOEXEC);
}
+ATF_TC(pipe2_clofork);
+ATF_TC_HEAD(pipe2_clofork, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "A close-on-fork test of pipe2(2)");
+}
+
+ATF_TC_BODY(pipe2_clofork, tc)
+{
+#if defined(O_CLOFORK) && O_CLOFORK != 0
+ run(O_CLOFORK);
+#else
+ atf_tc_skip("O_CLOFORK not yet implemented");
+#endif
+}
+
ATF_TC(pipe2_nosigpipe);
ATF_TC_HEAD(pipe2_nosigpipe, tc)
{
@@ -186,6 +216,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, pipe2_consume);
ATF_TP_ADD_TC(tp, pipe2_nonblock);
ATF_TP_ADD_TC(tp, pipe2_cloexec);
+ ATF_TP_ADD_TC(tp, pipe2_clofork);
ATF_TP_ADD_TC(tp, pipe2_nosigpipe);
ATF_TP_ADD_TC(tp, pipe2_einval);
diff --git a/lib/libc/sys/t_poll.c b/lib/libc/sys/t_poll.c
index 48f63e528eee..104bf4adde09 100644
--- a/lib/libc/sys/t_poll.c
+++ b/lib/libc/sys/t_poll.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_poll.c,v 1.8 2021/10/02 17:32:55 thorpej Exp $ */
+/* $NetBSD: t_poll.c,v 1.12 2025/02/10 02:41:34 riastradh Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,6 +29,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <sys/ioctl.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
@@ -38,11 +40,15 @@
#include <fcntl.h>
#include <paths.h>
#include <poll.h>
+#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
+#include <termios.h>
#include <unistd.h>
+#include "h_macros.h"
+
static int desc;
static void
@@ -101,35 +107,33 @@ ATF_TC_BODY(3way, tc)
int pf[2];
int status, i;
pid_t pid;
+ ssize_t nwrit;
- pipe(pf);
+ RL(pipe(pf));
desc = pf[0];
- pid = fork();
- ATF_REQUIRE(pid >= 0);
-
+ RL(pid = fork());
if (pid == 0) {
- (void)close(pf[1]);
+ if (close(pf[1]) == -1)
+ _exit(1);
child1();
_exit(0);
/* NOTREACHED */
}
- pid = fork();
- ATF_REQUIRE(pid >= 0);
-
+ RL(pid = fork());
if (pid == 0) {
- (void)close(pf[1]);
+ if (close(pf[1]) == -1)
+ _exit(1);
child2();
_exit(0);
/* NOTREACHED */
}
- pid = fork();
- ATF_REQUIRE( pid >= 0);
-
+ RL(pid = fork());
if (pid == 0) {
- (void)close(pf[1]);
+ if (close(pf[1]) == -1)
+ _exit(1);
child3();
_exit(0);
/* NOTREACHED */
@@ -139,10 +143,11 @@ ATF_TC_BODY(3way, tc)
(void)printf("parent write\n");
- ATF_REQUIRE(write(pf[1], "konec\n", 6) == 6);
+ RL(nwrit = write(pf[1], "konec\n", 6));
+ ATF_REQUIRE_EQ_MSG(nwrit, 6, "nwrit=%zd", nwrit);
- for(i = 0; i < 3; ++i)
- (void)wait(&status);
+ for (i = 0; i < 3; i++)
+ RL(wait(&status));
(void)printf("parent terminated\n");
}
@@ -160,8 +165,9 @@ ATF_TC_BODY(basic, tc)
int fds[2];
struct pollfd pfds[2];
int ret;
+ ssize_t nwrit;
- ATF_REQUIRE_EQ(pipe(fds), 0);
+ RL(pipe(fds));
pfds[0].fd = fds[0];
pfds[0].events = POLLIN;
@@ -174,16 +180,16 @@ ATF_TC_BODY(basic, tc)
*/
pfds[0].revents = -1;
pfds[1].revents = -1;
- ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[0], 1, 1), 0,
- "got: %d", ret);
+ RL(ret = poll(&pfds[0], 1, 1));
+ ATF_REQUIRE_EQ_MSG(ret, 0, "got: %d", ret);
ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
ATF_REQUIRE_EQ_MSG(pfds[1].revents, -1, "got: %d", pfds[1].revents);
/* Check that the write end of the pipe as reported as ready. */
pfds[0].revents = -1;
pfds[1].revents = -1;
- ATF_REQUIRE_EQ_MSG(ret = poll(&pfds[1], 1, 1), 1,
- "got: %d", ret);
+ RL(ret = poll(&pfds[1], 1, 1));
+ ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
ATF_REQUIRE_EQ_MSG(pfds[0].revents, -1, "got: %d", pfds[0].revents);
ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",\
pfds[1].revents);
@@ -191,27 +197,28 @@ ATF_TC_BODY(basic, tc)
/* Check that only the write end of the pipe as reported as ready. */
pfds[0].revents = -1;
pfds[1].revents = -1;
- ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 1,
- "got: %d", ret);
+ RL(ret = poll(pfds, 2, 1));
+ ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
ATF_REQUIRE_EQ_MSG(pfds[0].revents, 0, "got: %d", pfds[0].revents);
ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
pfds[1].revents);
/* Write data to our pipe. */
- ATF_REQUIRE_EQ(write(fds[1], "", 1), 1);
+ RL(nwrit = write(fds[1], "", 1));
+ ATF_REQUIRE_EQ_MSG(nwrit, 1, "nwrit=%zd", nwrit);
/* Check that both ends of our pipe are reported as ready. */
pfds[0].revents = -1;
pfds[1].revents = -1;
- ATF_REQUIRE_EQ_MSG(ret = poll(pfds, 2, 1), 2,
- "got: %d", ret);
+ RL(ret = poll(pfds, 2, 1));
+ ATF_REQUIRE_EQ_MSG(ret, 2, "got: %d", ret);
ATF_REQUIRE_EQ_MSG(pfds[0].revents, POLLIN, "got: %d",
pfds[0].revents);
ATF_REQUIRE_EQ_MSG(pfds[1].revents, POLLOUT, "got: %d",
pfds[1].revents);
- ATF_REQUIRE_EQ(close(fds[0]), 0);
- ATF_REQUIRE_EQ(close(fds[1]), 0);
+ RL(close(fds[0]));
+ RL(close(fds[1]));
}
ATF_TC(err);
@@ -240,9 +247,10 @@ static const char fifo_path[] = "pollhup_fifo";
static void
fifo_support(void)
{
+
errno = 0;
if (mkfifo(fifo_path, 0600) == 0) {
- ATF_REQUIRE(unlink(fifo_path) == 0);
+ RL(unlink(fifo_path));
return;
}
@@ -266,19 +274,20 @@ ATF_TC_BODY(fifo_inout, tc)
char *buf;
int rfd, wfd;
long pipe_buf;
+ int ret;
+ ssize_t nwrit, nread;
fifo_support();
- ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
- ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
- ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY | O_NONBLOCK)) >= 0);
+ RL(mkfifo(fifo_path, 0600));
+ RL(rfd = open(fifo_path, O_RDONLY | O_NONBLOCK));
+ RL(wfd = open(fifo_path, O_WRONLY | O_NONBLOCK));
/* Get the maximum atomic pipe write size. */
pipe_buf = fpathconf(wfd, _PC_PIPE_BUF);
- ATF_REQUIRE(pipe_buf > 1);
+ ATF_REQUIRE_MSG(pipe_buf > 1, "pipe_buf=%ld", pipe_buf);
- buf = malloc(pipe_buf);
- ATF_REQUIRE(buf != NULL);
+ REQUIRE_LIBC(buf = malloc(pipe_buf), NULL);
memset(&pfd, 0, sizeof(pfd));
pfd[0].fd = rfd;
@@ -287,20 +296,28 @@ ATF_TC_BODY(fifo_inout, tc)
pfd[1].events = POLLOUT | POLLWRNORM;
/* We expect the FIFO to be writable but not readable. */
- ATF_REQUIRE(poll(pfd, 2, 0) == 1);
- ATF_REQUIRE(pfd[0].revents == 0);
- ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
+ RL(ret = poll(pfd, 2, 0));
+ ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
+ ATF_REQUIRE_EQ_MSG(pfd[0].revents, 0,
+ "pfd[0].revents=0x%x", pfd[0].revents);
+ ATF_REQUIRE_EQ_MSG(pfd[1].revents, POLLOUT|POLLWRNORM,
+ "pfd[1].revents=0x%x", pfd[1].revents);
/* Write a single byte of data into the FIFO. */
- ATF_REQUIRE(write(wfd, buf, 1) == 1);
+ RL(nwrit = write(wfd, buf, 1));
+ ATF_REQUIRE_EQ_MSG(nwrit, 1, "nwrit=%zd", nwrit);
/* We expect the FIFO to be readable and writable. */
- ATF_REQUIRE(poll(pfd, 2, 0) == 2);
- ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
- ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
+ RL(ret = poll(pfd, 2, 0));
+ ATF_REQUIRE_EQ_MSG(ret, 2, "got: %d", ret);
+ ATF_REQUIRE_EQ_MSG(pfd[0].revents, POLLIN|POLLRDNORM,
+ "pfd[0].revents=0x%x", pfd[0].revents);
+ ATF_REQUIRE_EQ_MSG(pfd[1].revents, POLLOUT|POLLWRNORM,
+ "pfd[1].revents=0x%x", pfd[1].revents);
/* Read that single byte back out. */
- ATF_REQUIRE(read(rfd, buf, 1) == 1);
+ RL(nread = read(rfd, buf, 1));
+ ATF_REQUIRE_EQ_MSG(nread, 1, "nread=%zd", nread);
/*
* Write data into the FIFO until it is full, which is
@@ -310,33 +327,44 @@ ATF_TC_BODY(fifo_inout, tc)
while (write(wfd, buf, pipe_buf) != -1) {
continue;
}
- ATF_REQUIRE(errno == EAGAIN);
+ ATF_REQUIRE_EQ_MSG(errno, EAGAIN, "errno=%d", errno);
/* We expect the FIFO to be readble but not writable. */
- ATF_REQUIRE(poll(pfd, 2, 0) == 1);
- ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
- ATF_REQUIRE(pfd[1].revents == 0);
+ RL(ret = poll(pfd, 2, 0));
+ ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
+ ATF_REQUIRE_EQ_MSG(pfd[0].revents, POLLIN|POLLRDNORM,
+ "pfd[0].revents=0x%x", pfd[0].revents);
+ ATF_REQUIRE_EQ_MSG(pfd[1].revents, 0,
+ "pfd[1].revents=0x%x", pfd[1].revents);
/* Read a single byte of data from the FIFO. */
- ATF_REQUIRE(read(rfd, buf, 1) == 1);
+ RL(nread = read(rfd, buf, 1));
+ ATF_REQUIRE_EQ_MSG(nread, 1, "nread=%zd", nread);
/*
* Because we have read only a single byte out, there will
* be insufficient space for a pipe_buf-sized message, so
* the FIFO should still not be writable.
*/
- ATF_REQUIRE(poll(pfd, 2, 0) == 1);
- ATF_REQUIRE(pfd[0].revents == (POLLIN | POLLRDNORM));
- ATF_REQUIRE(pfd[1].revents == 0);
+ RL(ret = poll(pfd, 2, 0));
+ ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
+ ATF_REQUIRE_EQ_MSG(pfd[0].revents, POLLIN|POLLRDNORM,
+ "pfd[0].revents=0x%x", pfd[0].revents);
+ ATF_REQUIRE_EQ_MSG(pfd[1].revents, 0,
+ "pfd[1].revents=0x%x", pfd[1].revents);
/*
* Now read enough so that exactly pipe_buf space should
* be available. The FIFO should be writable after that.
* N.B. we don't care if it's readable at this point.
*/
- ATF_REQUIRE(read(rfd, buf, pipe_buf - 1) == pipe_buf - 1);
- ATF_REQUIRE(poll(pfd, 2, 0) >= 1);
- ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
+ RL(nread = read(rfd, buf, pipe_buf - 1));
+ ATF_REQUIRE_EQ_MSG(nread, pipe_buf - 1, "nread=%zd pipe_buf-1=%ld",
+ nread, pipe_buf - 1);
+ RL(ret = poll(pfd, 2, 0));
+ ATF_REQUIRE_MSG(ret >= 1, "got: %d", ret);
+ ATF_REQUIRE_EQ_MSG(pfd[1].revents, POLLOUT|POLLWRNORM,
+ "pfd[1].revents=0x%x", pfd[1].revents);
/*
* Now read all of the data out of the FIFO and ensure that
@@ -345,14 +373,17 @@ ATF_TC_BODY(fifo_inout, tc)
while (read(rfd, buf, pipe_buf) != -1) {
continue;
}
- ATF_REQUIRE(errno == EAGAIN);
+ ATF_REQUIRE_EQ_MSG(errno, EAGAIN, "errno=%d", errno);
- ATF_REQUIRE(poll(pfd, 2, 0) == 1);
- ATF_REQUIRE(pfd[0].revents == 0);
- ATF_REQUIRE(pfd[1].revents == (POLLOUT | POLLWRNORM));
+ RL(ret = poll(pfd, 2, 0));
+ ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
+ ATF_REQUIRE_EQ_MSG(pfd[0].revents, 0,
+ "pfd[0].revents=0x%x", pfd[0].revents);
+ ATF_REQUIRE_EQ_MSG(pfd[1].revents, POLLOUT|POLLWRNORM,
+ "pfd[1].revents=0x%x", pfd[1].revents);
- (void)close(wfd);
- (void)close(rfd);
+ RL(close(wfd));
+ RL(close(rfd));
}
ATF_TC_CLEANUP(fifo_inout, tc)
@@ -371,21 +402,25 @@ ATF_TC_BODY(fifo_hup1, tc)
{
struct pollfd pfd;
int rfd, wfd;
+ int ret;
fifo_support();
- ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
- ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
- ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
+ RL(mkfifo(fifo_path, 0600));
+ RL(rfd = open(fifo_path, O_RDONLY | O_NONBLOCK));
+ RL(wfd = open(fifo_path, O_WRONLY));
memset(&pfd, 0, sizeof(pfd));
pfd.fd = rfd;
pfd.events = POLLIN;
- (void)close(wfd);
+ RL(close(wfd));
- ATF_REQUIRE(poll(&pfd, 1, 0) == 1);
- ATF_REQUIRE((pfd.revents & POLLHUP) != 0);
+ RL(ret = poll(&pfd, 1, 0));
+ ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
+ ATF_REQUIRE_EQ_MSG((pfd.revents & (POLLHUP|POLLOUT)), POLLHUP,
+ "revents=0x%x expected POLLHUP=0x%x but not POLLOUT=0x%x",
+ pfd.revents, POLLHUP, POLLOUT);
/*
* Check that POLLHUP is cleared when a writer re-connects.
@@ -396,8 +431,9 @@ ATF_TC_BODY(fifo_hup1, tc)
pfd.fd = rfd;
pfd.events = POLLIN;
- ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
- ATF_REQUIRE(poll(&pfd, 1, 0) == 0);
+ RL(wfd = open(fifo_path, O_WRONLY));
+ RL(ret = poll(&pfd, 1, 0));
+ ATF_REQUIRE_EQ_MSG(ret, 0, "got: %d", ret);
}
ATF_TC_CLEANUP(fifo_hup1, tc)
@@ -418,36 +454,43 @@ ATF_TC_BODY(fifo_hup2, tc)
int rfd, wfd;
pid_t pid;
struct timespec ts1, ts2;
+ int ret;
fifo_support();
- ATF_REQUIRE(mkfifo(fifo_path, 0600) == 0);
- ATF_REQUIRE((rfd = open(fifo_path, O_RDONLY | O_NONBLOCK)) >= 0);
- ATF_REQUIRE((wfd = open(fifo_path, O_WRONLY)) >= 0);
+ RL(mkfifo(fifo_path, 0600));
+ RL(rfd = open(fifo_path, O_RDONLY | O_NONBLOCK));
+ RL(wfd = open(fifo_path, O_WRONLY));
memset(&pfd, 0, sizeof(pfd));
pfd.fd = rfd;
pfd.events = POLLIN;
- pid = fork();
- ATF_REQUIRE(pid >= 0);
-
+ RL(pid = fork());
if (pid == 0) {
- (void)close(rfd);
+ if (close(rfd))
+ _exit(1);
sleep(5);
- (void)close(wfd);
+ if (close(wfd))
+ _exit(1);
_exit(0);
}
- (void)close(wfd);
+ RL(close(wfd));
- ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts1) == 0);
- ATF_REQUIRE(poll(&pfd, 1, INFTIM) == 1);
- ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &ts2) == 0);
+ RL(clock_gettime(CLOCK_MONOTONIC, &ts1));
+ RL(ret = poll(&pfd, 1, INFTIM));
+ ATF_REQUIRE_EQ_MSG(ret, 1, "got: %d", ret);
+ RL(clock_gettime(CLOCK_MONOTONIC, &ts2));
/* Make sure at least a couple of seconds have elapsed. */
- ATF_REQUIRE(ts2.tv_sec - ts1.tv_sec >= 2);
+ ATF_REQUIRE_MSG(ts2.tv_sec - ts1.tv_sec >= 2,
+ "ts1=%lld.%09ld ts2=%lld.%09ld",
+ (long long)ts1.tv_sec, ts1.tv_nsec,
+ (long long)ts2.tv_sec, ts2.tv_nsec);
- ATF_REQUIRE((pfd.revents & POLLHUP) != 0);
+ ATF_REQUIRE_EQ_MSG((pfd.revents & (POLLHUP|POLLOUT)), POLLHUP,
+ "revents=0x%x expected POLLHUP=0x%x but not POLLOUT=0x%x",
+ pfd.revents, POLLHUP, POLLOUT);
}
ATF_TC_CLEANUP(fifo_hup2, tc)
@@ -455,6 +498,1592 @@ ATF_TC_CLEANUP(fifo_hup2, tc)
(void)unlink(fifo_path);
}
+static void
+fillpipebuf(int writefd)
+{
+ char buf[BUFSIZ] = {0};
+ size_t n = 0;
+ ssize_t nwrit;
+ int flags;
+
+ RL(flags = fcntl(writefd, F_GETFL));
+ RL(fcntl(writefd, F_SETFL, flags|O_NONBLOCK));
+ while ((nwrit = write(writefd, buf, sizeof(buf))) != -1)
+ n += (size_t)nwrit;
+ ATF_CHECK_EQ_MSG(errno, EAGAIN, "errno=%d", errno);
+ RL(fcntl(writefd, F_SETFL, flags));
+ fprintf(stderr, "filled %d with %zu bytes\n", writefd, n);
+}
+
+static void
+check_write_fail(int writefd, int error)
+{
+ int flags;
+ void (*sighandler)(int);
+ char c = 0;
+ ssize_t nwrit;
+
+ RL(flags = fcntl(writefd, F_GETFL));
+ RL(fcntl(writefd, F_SETFL, flags|O_NONBLOCK));
+
+ REQUIRE_LIBC(sighandler = signal(SIGPIPE, SIG_IGN), SIG_ERR);
+ ATF_CHECK_ERRNO(error, (nwrit = write(writefd, &c, 1)) == -1);
+ ATF_CHECK_EQ_MSG(nwrit, -1, "nwrit=%zd", nwrit);
+ REQUIRE_LIBC(signal(SIGPIPE, sighandler), SIG_ERR);
+
+ RL(fcntl(writefd, F_SETFL, flags));
+}
+
+static void
+check_read_eof(int readfd)
+{
+ int flags;
+ char c;
+ ssize_t nread;
+
+ RL(flags = fcntl(readfd, F_GETFL));
+ RL(fcntl(readfd, F_SETFL, flags|O_NONBLOCK));
+
+ RL(nread = read(readfd, &c, 1));
+ ATF_CHECK_EQ_MSG(nread, 0, "nread=%zu", nread);
+
+ RL(fcntl(readfd, F_SETFL, flags));
+}
+
+static void
+check_pollclosed_delayed_write(int writefd, int readfd,
+ int expected, int writeerror)
+{
+ struct pollfd pfd = { .fd = writefd, .events = POLLOUT };
+ struct timespec start, end, delta;
+ int nfds;
+
+ /*
+ * Don't let poll sleep for more than 3sec. (The close delay
+ * will be 2sec, and we make sure that we sleep at least 1sec.)
+ */
+ REQUIRE_LIBC(alarm(3), (unsigned)-1);
+
+ /*
+ * Wait in poll(2) indefinitely (subject to the alarm) and
+ * measure how long we slept.
+ */
+ fprintf(stderr, "poll %d\n", writefd);
+ RL(clock_gettime(CLOCK_MONOTONIC, &start));
+ RL(nfds = poll(&pfd, 1, INFTIM));
+ RL(clock_gettime(CLOCK_MONOTONIC, &end));
+ fprintf(stderr, "poll %d done nfds=%d\n", writefd, nfds);
+
+ REQUIRE_LIBC(alarm(0), (unsigned)-1);
+
+ /*
+ * The reader has been closed, so write will fail immediately
+ * with EPIPE/SIGPIPE, and thus POLLOUT must be set. POLLHUP
+ * is only returned for reads, not for writes (and is mutually
+ * exclusive with POLLOUT). Except we _do_ return POLLHUP
+ * instead of POLLOUT for terminals.
+ */
+ RL(nfds = poll(&pfd, 1, 0));
+ ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds);
+ ATF_CHECK_EQ_MSG(pfd.fd, writefd, "pfd.fd=%d writefd=%d",
+ pfd.fd, writefd);
+ ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), expected,
+ "revents=0x%x expected=0x%x"
+ " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x",
+ pfd.revents, expected, POLLOUT, POLLHUP, POLLIN);
+
+ /*
+ * We should have slept at least 1sec.
+ */
+ timespecsub(&end, &start, &delta);
+ ATF_CHECK_MSG(delta.tv_sec >= 1,
+ "slept only %lld.%09ld", (long long)delta.tv_sec, delta.tv_nsec);
+
+ /*
+ * Write should fail with EPIPE/SIGPIPE now, or EIO for
+ * terminals -- and continue to do so.
+ */
+ check_write_fail(writefd, writeerror);
+ check_write_fail(writefd, writeerror);
+}
+
+static void
+check_pollclosed_delayed_write_fifopipesocket(int writefd, int readfd)
+{
+
+ check_pollclosed_delayed_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+static void
+check_pollclosed_delayed_write_terminal(int writefd, int readfd)
+{
+
+ check_pollclosed_delayed_write(writefd, readfd, POLLHUP, EIO);
+}
+
+static void
+check_pollclosed_delayed_read(int readfd, int writefd, int pollhup)
+{
+ struct pollfd pfd;
+ struct timespec start, end, delta;
+ int nfds;
+
+ /*
+ * Don't let poll sleep for more than 3sec. (The close delay
+ * will be 2sec, and we make sure that we sleep at least 1sec.)
+ */
+ REQUIRE_LIBC(alarm(3), (unsigned)-1);
+
+ /*
+ * Wait in poll(2) indefinitely (subject to the alarm) and
+ * measure how long we slept.
+ */
+ pfd = (struct pollfd) { .fd = readfd, .events = POLLIN };
+ fprintf(stderr, "poll %d\n", readfd);
+ RL(clock_gettime(CLOCK_MONOTONIC, &start));
+ RL(nfds = poll(&pfd, 1, INFTIM));
+ RL(clock_gettime(CLOCK_MONOTONIC, &end));
+ fprintf(stderr, "poll %d done nfds=%d\n", readfd, nfds);
+
+ REQUIRE_LIBC(alarm(0), (unsigned)-1);
+
+ /*
+ * Read will yield EOF without blocking, so POLLIN should be
+ * set, and the write side has been closed, so POLLHUP should
+ * also be set, unsolicited, if this is a pipe or FIFO -- but
+ * not if it's a socket, where POLLHUP is never set. Since we
+ * didn't ask for POLLOUT, it should be clear.
+ */
+ ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds);
+ ATF_CHECK_EQ_MSG(pfd.fd, readfd, "pfd.fd=%d readfd=%d writefd=%d",
+ pfd.fd, readfd, writefd);
+ ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)),
+ pollhup|POLLIN,
+ "revents=0x%x expected=0x%x"
+ " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x",
+ pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT);
+
+ /*
+ * We should have slept at least 1sec.
+ */
+ timespecsub(&end, &start, &delta);
+ ATF_CHECK_MSG(delta.tv_sec >= 1,
+ "slept only %lld.%09ld", (long long)delta.tv_sec, delta.tv_nsec);
+
+ /*
+ * Read should return EOF now -- and continue to do so.
+ */
+ check_read_eof(readfd);
+ check_read_eof(readfd);
+
+ /*
+ * POLLHUP|POLLIN state should be persistent (until the writer
+ * side is reopened if possible, as in a named pipe).
+ */
+ pfd = (struct pollfd) { .fd = readfd, .events = POLLIN };
+ RL(nfds = poll(&pfd, 1, 0));
+ ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds);
+ ATF_CHECK_EQ_MSG(pfd.fd, readfd, "pfd.fd=%d readfd=%d writefd=%d",
+ pfd.fd, readfd, writefd);
+ ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)),
+ pollhup|POLLIN,
+ "revents=0x%x expected=0x%x"
+ " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x",
+ pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT);
+}
+
+static void
+check_pollclosed_delayed_read_devfifopipe(int readfd, int writefd)
+{
+
+ check_pollclosed_delayed_read(readfd, writefd, POLLHUP);
+}
+
+static void
+check_pollclosed_delayed_read_socket(int readfd, int writefd)
+{
+
+ check_pollclosed_delayed_read(readfd, writefd, /*no POLLHUP*/0);
+}
+
+static void
+check_pollclosed_delayed_process(int pollfd, int closefd,
+ void (*check_pollhup)(int, int))
+{
+ pid_t pid;
+ int status;
+
+ /*
+ * Fork a child to close closefd after a 2sec delay.
+ */
+ RL(pid = fork());
+ if (pid == 0) {
+ sleep(2);
+ fprintf(stderr, "[child] close %d\n", closefd);
+ if (close(closefd) == -1)
+ _exit(1);
+ _exit(0);
+ }
+
+ /*
+ * Close closefd in the parent so the child has the last
+ * reference to it.
+ */
+ fprintf(stderr, "[parent] close %d\n", closefd);
+ RL(close(closefd));
+
+ /*
+ * Test poll(2).
+ */
+ (*check_pollhup)(pollfd, closefd);
+
+ /*
+ * Wait for the child and make sure it exited successfully.
+ */
+ RL(waitpid(pid, &status, 0));
+ ATF_CHECK_EQ_MSG(status, 0, "child exited with status 0x%x", status);
+}
+
+static void *
+check_pollclosed_thread(void *cookie)
+{
+ int *closefdp = cookie;
+
+ sleep(2);
+ fprintf(stderr, "[thread] close %d\n", *closefdp);
+ RL(close(*closefdp));
+ return NULL;
+}
+
+static void
+check_pollclosed_delayed_thread(int pollfd, int closefd,
+ void (*check_pollhup)(int, int))
+{
+ pthread_t t;
+
+ /*
+ * Create a thread to close closefd (in this process, not a
+ * child) after a 2sec delay.
+ */
+ RZ(pthread_create(&t, NULL, &check_pollclosed_thread, &closefd));
+
+ /*
+ * Test poll(2).
+ */
+ (*check_pollhup)(pollfd, closefd);
+
+ /*
+ * Wait for the thread to complete.
+ */
+ RZ(pthread_join(t, NULL));
+}
+
+static void
+check_pollclosed_immediate_write(int writefd, int readfd, int expected,
+ int writeerror)
+{
+ struct pollfd pfd = { .fd = writefd, .events = POLLOUT };
+ int nfds;
+
+ /*
+ * Close the reader side immediately.
+ */
+ fprintf(stderr, "[immediate] close %d\n", readfd);
+ RL(close(readfd));
+
+ /*
+ * The reader has been closed, so write will fail immediately
+ * with EPIPE/SIGPIPE, and thus POLLOUT must be set. POLLHUP
+ * is only returned for reads, not for writes (and is mutually
+ * exclusive with POLLOUT). Except we _do_ return POLLHUP
+ * instead of POLLOUT for terminals.
+ */
+ RL(nfds = poll(&pfd, 1, 0));
+ ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds);
+ ATF_CHECK_EQ_MSG(pfd.fd, writefd, "pfd.fd=%d writefd=%d",
+ pfd.fd, writefd);
+ ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)), expected,
+ "revents=0x%x expected=0x%x"
+ " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x",
+ pfd.revents, expected, POLLOUT, POLLHUP, POLLIN);
+
+ /*
+ * Write should fail with EPIPE/SIGPIPE now -- and continue to
+ * do so.
+ */
+ check_write_fail(writefd, writeerror);
+ check_write_fail(writefd, writeerror);
+}
+
+static void
+check_pollclosed_immediate_readnone(int readfd, int writefd, int pollhup)
+{
+ struct pollfd pfd = { .fd = readfd, .events = POLLIN };
+ int nfds;
+
+ /*
+ * Close the writer side immediately.
+ */
+ fprintf(stderr, "[immediate] close %d\n", writefd);
+ RL(close(writefd));
+
+ /*
+ * Read will yield EOF without blocking, so POLLIN should be
+ * set, and the write side has been closed, so POLLHUP should
+ * be set, unsolicited, if this is a pipe or FIFO -- but not if
+ * it's a socket, where POLLHUP is never set. Since we didn't
+ * ask for POLLOUT, it should be clear.
+ */
+ RL(nfds = poll(&pfd, 1, 0));
+ ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds);
+ ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)),
+ pollhup|POLLIN,
+ "revents=0x%x expected=0x%x"
+ " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x",
+ pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT);
+
+ /*
+ * Read should return EOF now -- and continue to do so.
+ */
+ check_read_eof(readfd);
+ check_read_eof(readfd);
+}
+
+static void
+check_pollclosed_immediate_readsome(int readfd, int writefd, int pollhup)
+{
+ struct pollfd pfd;
+ char buf[BUFSIZ];
+ ssize_t nread;
+ int nfds;
+
+ /*
+ * Close the writer side immediately.
+ */
+ fprintf(stderr, "[immediate] close %d\n", writefd);
+ RL(close(writefd));
+
+ /*
+ * Some data should be ready to read, so POLLIN should be set,
+ * and the write side has been closed, so POLLHUP should also
+ * be set, unsolicited, if this is a pipe or FIFO -- but not if
+ * it's a socket, where POLLHUP is never set. Since we didn't
+ * ask for POLLOUT, it should be clear.
+ */
+ pfd = (struct pollfd) { .fd = readfd, .events = POLLIN };
+ RL(nfds = poll(&pfd, 1, 0));
+ ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds);
+ ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)),
+ pollhup|POLLIN,
+ "revents=0x%x expected=0x%x"
+ " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x",
+ pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT);
+
+ /*
+ * Read all the data. Each read should complete instantly --
+ * no blocking, either because there's data to read or because
+ * the writer has hung up and we get EOF.
+ */
+ do {
+ REQUIRE_LIBC(alarm(1), (unsigned)-1);
+ RL(nread = read(readfd, buf, sizeof(buf)));
+ REQUIRE_LIBC(alarm(0), (unsigned)-1);
+ } while (nread != 0);
+
+ /*
+ * Read will yield EOF without blocking, so POLLIN should be
+ * set, and the write side has been closed, so POLLHUP should
+ * also be set, unsolicited, if this is a pipe or FIFO -- but
+ * not if it's a socket, where POLLHUP is never set. Since we
+ * didn't ask for POLLOUT, it should be clear.
+ */
+ pfd = (struct pollfd) { .fd = readfd, .events = POLLIN };
+ RL(nfds = poll(&pfd, 1, 0));
+ ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds);
+ ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)),
+ pollhup|POLLIN,
+ "revents=0x%x expected=0x%x"
+ " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x",
+ pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT);
+
+ /*
+ * Read should return EOF now -- and continue to do so.
+ */
+ check_read_eof(readfd);
+ check_read_eof(readfd);
+
+ /*
+ * POLLHUP|POLLIN state should be persistent (until the writer
+ * side is reopened if possible, as in a named pipe).
+ */
+ pfd = (struct pollfd) { .fd = readfd, .events = POLLIN };
+ RL(nfds = poll(&pfd, 1, 0));
+ ATF_CHECK_EQ_MSG(nfds, 1, "nfds=%d", nfds);
+ ATF_CHECK_EQ_MSG((pfd.revents & (POLLHUP|POLLIN|POLLOUT)),
+ pollhup|POLLIN,
+ "revents=0x%x expected=0x%x"
+ " POLLHUP=0x%x POLLIN=0x%x POLLOUT=0x%x",
+ pfd.revents, pollhup|POLLIN, POLLHUP, POLLIN, POLLOUT);
+}
+
+static void *
+pollclosed_fifo_writer_thread(void *cookie)
+{
+ int *pp = cookie;
+
+ RL(*pp = open(fifo_path, O_WRONLY));
+ return NULL;
+}
+
+static void *
+pollclosed_fifo_reader_thread(void *cookie)
+{
+ int *pp = cookie;
+
+ RL(*pp = open(fifo_path, O_RDONLY));
+ return NULL;
+}
+
+static void
+pollclosed_fifo0_setup(int *writefdp, int *readfdp)
+{
+ int p0, p1;
+ pthread_t t;
+
+ fifo_support();
+
+ RL(mkfifo(fifo_path, 0600));
+ RZ(pthread_create(&t, NULL, &pollclosed_fifo_reader_thread, &p0));
+ REQUIRE_LIBC(alarm(1), (unsigned)-1);
+ RL(p1 = open(fifo_path, O_WRONLY));
+ REQUIRE_LIBC(alarm(0), (unsigned)-1);
+ RZ(pthread_join(t, NULL));
+
+ *writefdp = p1;
+ *readfdp = p0;
+}
+
+static void
+pollclosed_fifo1_setup(int *writefdp, int *readfdp)
+{
+ int p0, p1;
+ pthread_t t;
+
+ fifo_support();
+
+ RL(mkfifo(fifo_path, 0600));
+ RZ(pthread_create(&t, NULL, &pollclosed_fifo_writer_thread, &p0));
+ REQUIRE_LIBC(alarm(1), (unsigned)-1);
+ RL(p1 = open(fifo_path, O_RDONLY));
+ REQUIRE_LIBC(alarm(0), (unsigned)-1);
+ RZ(pthread_join(t, NULL));
+
+ *writefdp = p0;
+ *readfdp = p1;
+}
+
+static void
+pollclosed_pipe_setup(int *writefdp, int *readfdp)
+{
+ int p[2];
+
+ RL(pipe(p));
+
+ *readfdp = p[0]; /* reader side */
+ *writefdp = p[1]; /* writer side */
+}
+
+static void
+pollclosed_ptyapp_setup(int *writefdp, int *readfdp)
+{
+ int hostfd, appfd;
+ struct termios t;
+ char *pts;
+
+ RL(hostfd = posix_openpt(O_RDWR|O_NOCTTY));
+ RL(grantpt(hostfd));
+ RL(unlockpt(hostfd));
+ REQUIRE_LIBC(pts = ptsname(hostfd), NULL);
+ RL(appfd = open(pts, O_RDWR|O_NOCTTY));
+
+ RL(tcgetattr(appfd, &t));
+ t.c_lflag &= ~ICANON; /* block rather than drop input */
+ RL(tcsetattr(appfd, TCSANOW, &t));
+
+ *readfdp = appfd;
+ *writefdp = hostfd;
+}
+
+static void
+pollclosed_ptyhost_setup(int *writefdp, int *readfdp)
+{
+ int hostfd, appfd;
+ struct termios t;
+ char *pts;
+
+ RL(hostfd = posix_openpt(O_RDWR|O_NOCTTY));
+ RL(grantpt(hostfd));
+ RL(unlockpt(hostfd));
+ REQUIRE_LIBC(pts = ptsname(hostfd), NULL);
+ RL(appfd = open(pts, O_RDWR|O_NOCTTY));
+
+ RL(tcgetattr(appfd, &t));
+ t.c_lflag &= ~ICANON; /* block rather than drop input */
+ RL(tcsetattr(appfd, TCSANOW, &t));
+
+ *writefdp = appfd;
+ *readfdp = hostfd;
+}
+
+static void
+pollclosed_socketpair0_setup(int *writefdp, int *readfdp)
+{
+ int s[2];
+
+ RL(socketpair(AF_LOCAL, SOCK_STREAM, 0, s));
+ *readfdp = s[0];
+ *writefdp = s[1];
+}
+
+static void
+pollclosed_socketpair1_setup(int *writefdp, int *readfdp)
+{
+ int s[2];
+
+ RL(socketpair(AF_LOCAL, SOCK_STREAM, 0, s));
+ *readfdp = s[1];
+ *writefdp = s[0];
+}
+
+/*
+ * Cartesian product of:
+ *
+ * 1. [fifo0] first fifo opener
+ * 2. [fifo1] second fifo opener
+ * 3. [pipe] pipe
+ * 4. [ptyhost] host side of pty
+ * 5. [ptyapp] application side of pty
+ * 6. [socketpair0] first side of socket pair
+ * 7. [socketpair1] second side of socket pair
+ *
+ * with
+ *
+ * 1. [immediate] closed before poll starts
+ * 2. [delayed_thread] closed by another thread after poll starts
+ * 3. [delayed_process] closed by another process after poll starts
+ *
+ * with
+ *
+ * 1. [writefull] close reader, poll for write when buffer full
+ * 2. [writeempty] close reader, poll for write when buffer empty
+ * 3. [readnone] close writer, poll for read when nothing to read
+ * 4. [readsome] close writer, poll for read when something to read
+ *
+ * except that in the delayed cases we only do writefull [write] and
+ * readnone [read], because there's no delay in the writeempty/readsome
+ * cases.
+ */
+
+ATF_TC(pollclosed_fifo0_immediate_writefull);
+ATF_TC_HEAD(pollclosed_fifo0_immediate_writefull, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo0_immediate_writefull, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo0_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_fifo0_immediate_writeempty);
+ATF_TC_HEAD(pollclosed_fifo0_immediate_writeempty, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo0_immediate_writeempty, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo0_setup(&writefd, &readfd);
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_fifo0_immediate_readsome);
+ATF_TC_HEAD(pollclosed_fifo0_immediate_readsome, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo0_immediate_readsome, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns nothing, when it is supposed to return
+ * POLLHUP|POLLIN.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_fifo0_immediate_readnone);
+ATF_TC_HEAD(pollclosed_fifo0_immediate_readnone, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo0_immediate_readnone, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_fifo0_delayed_process_write);
+ATF_TC_HEAD(pollclosed_fifo0_delayed_process_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo0_delayed_process_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo0_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_process(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_fifo0_delayed_process_read);
+ATF_TC_HEAD(pollclosed_fifo0_delayed_process_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo0_delayed_process_read, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't
+ * persistent as it is supposed to be -- it returns nothing
+ * after that.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_fifo0_delayed_thread_write);
+ATF_TC_HEAD(pollclosed_fifo0_delayed_thread_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo0_delayed_thread_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo0_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_thread(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_fifo0_delayed_thread_read);
+ATF_TC_HEAD(pollclosed_fifo0_delayed_thread_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo0_delayed_thread_read, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't
+ * persistent as it is supposed to be -- it returns nothing
+ * after that.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_fifo1_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_thread(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_fifo1_immediate_writefull);
+ATF_TC_HEAD(pollclosed_fifo1_immediate_writefull, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo1_immediate_writefull, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo1_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_fifo1_immediate_writeempty);
+ATF_TC_HEAD(pollclosed_fifo1_immediate_writeempty, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo1_immediate_writeempty, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo1_setup(&writefd, &readfd);
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_fifo1_immediate_readsome);
+ATF_TC_HEAD(pollclosed_fifo1_immediate_readsome, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo1_immediate_readsome, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns nothing, when it is supposed to return
+ * POLLHUP|POLLIN.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_fifo1_immediate_readnone);
+ATF_TC_HEAD(pollclosed_fifo1_immediate_readnone, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo1_immediate_readnone, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_fifo1_delayed_process_write);
+ATF_TC_HEAD(pollclosed_fifo1_delayed_process_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo1_delayed_process_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo1_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_process(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_fifo1_delayed_process_read);
+ATF_TC_HEAD(pollclosed_fifo1_delayed_process_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo1_delayed_process_read, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't
+ * persistent as it is supposed to be -- it returns nothing
+ * after that.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_fifo1_delayed_thread_write);
+ATF_TC_HEAD(pollclosed_fifo1_delayed_thread_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo1_delayed_thread_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_fifo1_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_thread(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_fifo1_delayed_thread_read);
+ATF_TC_HEAD(pollclosed_fifo1_delayed_thread_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second opener of a named pipe");
+}
+ATF_TC_BODY(pollclosed_fifo1_delayed_thread_read, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) wakes up with POLLHUP|POLLIN, but the state isn't
+ * persistent as it is supposed to be -- it returns nothing
+ * after that.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_fifo0_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_pipe_immediate_writefull);
+ATF_TC_HEAD(pollclosed_pipe_immediate_writefull, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with a closed pipe");
+}
+ATF_TC_BODY(pollclosed_pipe_immediate_writefull, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP|POLLOUT, which is forbidden --
+ * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is
+ * only supposed to be returned by polling for read, not
+ * polling for write. So it should be POLLOUT.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_pipe_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_pipe_immediate_writeempty);
+ATF_TC_HEAD(pollclosed_pipe_immediate_writeempty, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with a closed pipe");
+}
+ATF_TC_BODY(pollclosed_pipe_immediate_writeempty, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP|POLLOUT, which is forbidden --
+ * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is
+ * only supposed to be returned by polling for read, not
+ * polling for write. So it should be POLLOUT.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_pipe_setup(&writefd, &readfd);
+ /* don't fill pipe buf */
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_pipe_immediate_readsome);
+ATF_TC_HEAD(pollclosed_pipe_immediate_readsome, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with a closed pipe");
+}
+ATF_TC_BODY(pollclosed_pipe_immediate_readsome, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_pipe_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_pipe_immediate_readnone);
+ATF_TC_HEAD(pollclosed_pipe_immediate_readnone, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with a closed pipe");
+}
+ATF_TC_BODY(pollclosed_pipe_immediate_readnone, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_pipe_setup(&writefd, &readfd);
+ /* don't fill pipe buf */
+ check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_pipe_delayed_process_write);
+ATF_TC_HEAD(pollclosed_pipe_delayed_process_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with a closed pipe");
+}
+ATF_TC_BODY(pollclosed_pipe_delayed_process_write, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP|POLLOUT, which is forbidden --
+ * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is
+ * only supposed to be returned by polling for read, not
+ * polling for write. So it should be POLLOUT.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_pipe_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_process(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_pipe_delayed_process_read);
+ATF_TC_HEAD(pollclosed_pipe_delayed_process_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with a closed pipe");
+}
+ATF_TC_BODY(pollclosed_pipe_delayed_process_read, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_pipe_setup(&writefd, &readfd);
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_pipe_delayed_thread_write);
+ATF_TC_HEAD(pollclosed_pipe_delayed_thread_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with a closed pipe");
+}
+ATF_TC_BODY(pollclosed_pipe_delayed_thread_write, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP|POLLOUT, which is forbidden --
+ * POLLHUP and POLLOUT are mutually exclusive. And POLLHUP is
+ * only supposed to be returned by polling for read, not
+ * polling for write. So it should be POLLOUT.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_pipe_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_thread(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_pipe_delayed_thread_read);
+ATF_TC_HEAD(pollclosed_pipe_delayed_thread_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with a closed pipe");
+}
+ATF_TC_BODY(pollclosed_pipe_delayed_thread_read, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_pipe_setup(&writefd, &readfd);
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_thread(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_ptyapp_immediate_writefull);
+ATF_TC_HEAD(pollclosed_ptyapp_immediate_writefull, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty application side");
+}
+ATF_TC_BODY(pollclosed_ptyapp_immediate_writefull, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_ptyapp_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO);
+}
+
+ATF_TC(pollclosed_ptyapp_immediate_writeempty);
+ATF_TC_HEAD(pollclosed_ptyapp_immediate_writeempty, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty application side");
+}
+ATF_TC_BODY(pollclosed_ptyapp_immediate_writeempty, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_ptyapp_setup(&writefd, &readfd);
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO);
+}
+
+ATF_TC(pollclosed_ptyapp_immediate_readsome);
+ATF_TC_HEAD(pollclosed_ptyapp_immediate_readsome, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty application side");
+}
+ATF_TC_BODY(pollclosed_ptyapp_immediate_readsome, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP but not POLLIN even though read(2)
+ * would return EOF without blocking.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_ptyapp_immediate_readnone);
+ATF_TC_HEAD(pollclosed_ptyapp_immediate_readnone, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty application side");
+}
+ATF_TC_BODY(pollclosed_ptyapp_immediate_readnone, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP but not POLLIN even though read(2)
+ * would return EOF without blocking.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_ptyapp_delayed_process_write);
+ATF_TC_HEAD(pollclosed_ptyapp_delayed_process_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty application side");
+}
+ATF_TC_BODY(pollclosed_ptyapp_delayed_process_write, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * The poll(2) call is not woken by the concurrent close(2)
+ * call.
+ */
+ atf_tc_expect_signal(SIGALRM, "PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyapp_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_process(writefd, readfd,
+ &check_pollclosed_delayed_write_terminal);
+}
+
+ATF_TC(pollclosed_ptyapp_delayed_process_read);
+ATF_TC_HEAD(pollclosed_ptyapp_delayed_process_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty application side");
+}
+ATF_TC_BODY(pollclosed_ptyapp_delayed_process_read, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP but not POLLIN even though read(2)
+ * would return EOF without blocking.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_ptyapp_delayed_thread_write);
+ATF_TC_HEAD(pollclosed_ptyapp_delayed_thread_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty application side");
+}
+ATF_TC_BODY(pollclosed_ptyapp_delayed_thread_write, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * The poll(2) call is not woken by the concurrent close(2)
+ * call.
+ */
+ atf_tc_expect_signal(SIGALRM, "PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyapp_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_thread(writefd, readfd,
+ &check_pollclosed_delayed_write_terminal);
+}
+
+ATF_TC(pollclosed_ptyapp_delayed_thread_read);
+ATF_TC_HEAD(pollclosed_ptyapp_delayed_thread_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty application side");
+}
+ATF_TC_BODY(pollclosed_ptyapp_delayed_thread_read, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP but not POLLIN even though read(2)
+ * would return EOF without blocking.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyhost_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_ptyhost_immediate_writefull);
+ATF_TC_HEAD(pollclosed_ptyhost_immediate_writefull, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty host side");
+}
+ATF_TC_BODY(pollclosed_ptyhost_immediate_writefull, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_ptyhost_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO);
+}
+
+ATF_TC(pollclosed_ptyhost_immediate_writeempty);
+ATF_TC_HEAD(pollclosed_ptyhost_immediate_writeempty, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty host side");
+}
+ATF_TC_BODY(pollclosed_ptyhost_immediate_writeempty, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_ptyhost_setup(&writefd, &readfd);
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_write(writefd, readfd, POLLHUP, EIO);
+}
+
+ATF_TC(pollclosed_ptyhost_immediate_readsome);
+ATF_TC_HEAD(pollclosed_ptyhost_immediate_readsome, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty host side");
+}
+ATF_TC_BODY(pollclosed_ptyhost_immediate_readsome, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP but not POLLIN even though read(2)
+ * would return EOF without blocking.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_readsome(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_ptyhost_immediate_readnone);
+ATF_TC_HEAD(pollclosed_ptyhost_immediate_readnone, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty host side");
+}
+ATF_TC_BODY(pollclosed_ptyhost_immediate_readnone, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP but not POLLIN even though read(2)
+ * would return EOF without blocking.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_readnone(readfd, writefd, POLLHUP);
+}
+
+ATF_TC(pollclosed_ptyhost_delayed_process_write);
+ATF_TC_HEAD(pollclosed_ptyhost_delayed_process_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty host side");
+}
+ATF_TC_BODY(pollclosed_ptyhost_delayed_process_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_ptyhost_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_process(writefd, readfd,
+ &check_pollclosed_delayed_write_terminal);
+}
+
+ATF_TC(pollclosed_ptyhost_delayed_process_read);
+ATF_TC_HEAD(pollclosed_ptyhost_delayed_process_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty host side");
+}
+ATF_TC_BODY(pollclosed_ptyhost_delayed_process_read, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP but not POLLIN even though read(2)
+ * would return EOF without blocking.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_ptyhost_delayed_thread_write);
+ATF_TC_HEAD(pollclosed_ptyhost_delayed_thread_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty host side");
+}
+ATF_TC_BODY(pollclosed_ptyhost_delayed_thread_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_ptyhost_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_thread(writefd, readfd,
+ &check_pollclosed_delayed_write_terminal);
+}
+
+ATF_TC(pollclosed_ptyhost_delayed_thread_read);
+ATF_TC_HEAD(pollclosed_ptyhost_delayed_thread_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the pty host side");
+}
+ATF_TC_BODY(pollclosed_ptyhost_delayed_thread_read, tc)
+{
+ int writefd, readfd;
+
+ /*
+ * poll(2) returns POLLHUP but not POLLIN even though read(2)
+ * would return EOF without blocking.
+ */
+ atf_tc_expect_fail("PR kern/59056: poll POLLHUP bugs");
+
+ pollclosed_ptyapp_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_thread(readfd, writefd,
+ &check_pollclosed_delayed_read_devfifopipe);
+}
+
+ATF_TC(pollclosed_socketpair0_immediate_writefull);
+ATF_TC_HEAD(pollclosed_socketpair0_immediate_writefull, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair0_immediate_writefull, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair0_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_socketpair0_immediate_writeempty);
+ATF_TC_HEAD(pollclosed_socketpair0_immediate_writeempty, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair0_immediate_writeempty, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair0_setup(&writefd, &readfd);
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_socketpair0_immediate_readsome);
+ATF_TC_HEAD(pollclosed_socketpair0_immediate_readsome, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair0_immediate_readsome, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_readsome(readfd, writefd, /*no POLLHUP*/0);
+}
+
+ATF_TC(pollclosed_socketpair0_immediate_readnone);
+ATF_TC_HEAD(pollclosed_socketpair0_immediate_readnone, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair0_immediate_readnone, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_readnone(readfd, writefd, /*no POLLHUP*/0);
+}
+
+ATF_TC(pollclosed_socketpair0_delayed_process_write);
+ATF_TC_HEAD(pollclosed_socketpair0_delayed_process_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair0_delayed_process_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair0_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_process(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_socketpair0_delayed_process_read);
+ATF_TC_HEAD(pollclosed_socketpair0_delayed_process_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair0_delayed_process_read, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_socket);
+}
+
+ATF_TC(pollclosed_socketpair0_delayed_thread_write);
+ATF_TC_HEAD(pollclosed_socketpair0_delayed_thread_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair0_delayed_thread_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair0_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_thread(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_socketpair0_delayed_thread_read);
+ATF_TC_HEAD(pollclosed_socketpair0_delayed_thread_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the first half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair0_delayed_thread_read, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair1_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_thread(readfd, writefd,
+ &check_pollclosed_delayed_read_socket);
+}
+
+ATF_TC(pollclosed_socketpair1_immediate_writefull);
+ATF_TC_HEAD(pollclosed_socketpair1_immediate_writefull, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair1_immediate_writefull, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair1_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_socketpair1_immediate_writeempty);
+ATF_TC_HEAD(pollclosed_socketpair1_immediate_writeempty, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair1_immediate_writeempty, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair1_setup(&writefd, &readfd);
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_write(writefd, readfd, POLLOUT, EPIPE);
+}
+
+ATF_TC(pollclosed_socketpair1_immediate_readsome);
+ATF_TC_HEAD(pollclosed_socketpair1_immediate_readsome, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair1_immediate_readsome, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */
+ fillpipebuf(writefd);
+ check_pollclosed_immediate_readsome(readfd, writefd, /*no POLLHUP*/0);
+}
+
+ATF_TC(pollclosed_socketpair1_immediate_readnone);
+ATF_TC_HEAD(pollclosed_socketpair1_immediate_readnone, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair1_immediate_readnone, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill the pipe buf */
+ check_pollclosed_immediate_readnone(readfd, writefd, /*no POLLHUP*/0);
+}
+
+ATF_TC(pollclosed_socketpair1_delayed_process_write);
+ATF_TC_HEAD(pollclosed_socketpair1_delayed_process_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair1_delayed_process_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair1_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_process(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_socketpair1_delayed_process_read);
+ATF_TC_HEAD(pollclosed_socketpair1_delayed_process_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair1_delayed_process_read, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_socket);
+}
+
+ATF_TC(pollclosed_socketpair1_delayed_thread_write);
+ATF_TC_HEAD(pollclosed_socketpair1_delayed_thread_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair1_delayed_thread_write, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair1_setup(&writefd, &readfd);
+ fillpipebuf(writefd);
+ check_pollclosed_delayed_thread(writefd, readfd,
+ &check_pollclosed_delayed_write_fifopipesocket);
+}
+
+ATF_TC(pollclosed_socketpair1_delayed_thread_read);
+ATF_TC_HEAD(pollclosed_socketpair1_delayed_thread_read, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Checks POLLHUP with closing the second half of a socketpair");
+}
+ATF_TC_BODY(pollclosed_socketpair1_delayed_thread_read, tc)
+{
+ int writefd, readfd;
+
+ pollclosed_socketpair0_setup(&writefd, &readfd); /* reverse r/w */
+ /* don't fill pipe buf */
+ check_pollclosed_delayed_process(readfd, writefd,
+ &check_pollclosed_delayed_read_socket);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -466,5 +2095,69 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, fifo_hup1);
ATF_TP_ADD_TC(tp, fifo_hup2);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_writefull);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_writefull);
+ ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_writefull);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_writefull);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_writefull);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_writefull);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_writefull);
+
+ ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_writeempty);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_writeempty);
+ ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_writeempty);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_writeempty);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_writeempty);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_writeempty);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_writeempty);
+
+ ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_readsome);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_readsome);
+ ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_readsome);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_readsome);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_readsome);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_readsome);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_readsome);
+
+ ATF_TP_ADD_TC(tp, pollclosed_fifo0_immediate_readnone);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo1_immediate_readnone);
+ ATF_TP_ADD_TC(tp, pollclosed_pipe_immediate_readnone);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyapp_immediate_readnone);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyhost_immediate_readnone);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair0_immediate_readnone);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair1_immediate_readnone);
+
+ ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_process_write);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_process_write);
+ ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_process_write);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_process_write);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_process_write);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_process_write);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_process_write);
+
+ ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_process_read);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_process_read);
+ ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_process_read);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_process_read);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_process_read);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_process_read);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_process_read);
+
+ ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_thread_write);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_thread_write);
+ ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_thread_write);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_thread_write);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_thread_write);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_thread_write);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_thread_write);
+
+ ATF_TP_ADD_TC(tp, pollclosed_fifo0_delayed_thread_read);
+ ATF_TP_ADD_TC(tp, pollclosed_fifo1_delayed_thread_read);
+ ATF_TP_ADD_TC(tp, pollclosed_pipe_delayed_thread_read);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyapp_delayed_thread_read);
+ ATF_TP_ADD_TC(tp, pollclosed_ptyhost_delayed_thread_read);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair0_delayed_thread_read);
+ ATF_TP_ADD_TC(tp, pollclosed_socketpair1_delayed_thread_read);
+
return atf_no_error();
}
diff --git a/lib/libc/sys/t_posix_fadvise.c b/lib/libc/sys/t_posix_fadvise.c
index fa8815896e8f..c3ba3909fe63 100644
--- a/lib/libc/sys/t_posix_fadvise.c
+++ b/lib/libc/sys/t_posix_fadvise.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_posix_fadvise.c,v 1.3 2018/06/19 09:20:46 gson Exp $ */
+/* $NetBSD: t_posix_fadvise.c,v 1.4 2025/04/06 19:18:00 riastradh Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -58,7 +58,7 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2008\
The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_posix_fadvise.c,v 1.3 2018/06/19 09:20:46 gson Exp $");
+__RCSID("$NetBSD: t_posix_fadvise.c,v 1.4 2025/04/06 19:18:00 riastradh Exp $");
#include <sys/fcntl.h>
@@ -103,15 +103,12 @@ ATF_TC_BODY(posix_fadvise, tc)
* only check return values here.
*/
- /* posix_fadvise shouldn't affect errno. */
-
#define CE(x, exp) \
do { \
- int save = errno; \
- errno = 999; \
- ATF_CHECK_EQ_MSG(ret = (x), exp, "got: %d", ret); \
- ATF_CHECK_EQ_MSG(errno, 999, "got: %s", strerror(errno)); \
- errno = save; \
+ ATF_CHECK_EQ_MSG(ret = (x), (exp), \
+ "got %d (%s), expected %d (%s)", \
+ ret, strerror(ret), \
+ (exp), strerror(exp)); \
} while (0)
CE(posix_fadvise(fd, 0, 0, -1), EINVAL);
diff --git a/lib/libc/sys/t_ptrace.c b/lib/libc/sys/t_ptrace.c
index 3def2468c3a7..8a6e1134290c 100644
--- a/lib/libc/sys/t_ptrace.c
+++ b/lib/libc/sys/t_ptrace.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace.c,v 1.5 2022/05/24 20:08:38 andvar Exp $ */
+/* $NetBSD: t_ptrace.c,v 1.7 2025/05/02 02:24:44 riastradh Exp $ */
/*-
* Copyright (c) 2016 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace.c,v 1.5 2022/05/24 20:08:38 andvar Exp $");
+__RCSID("$NetBSD: t_ptrace.c,v 1.7 2025/05/02 02:24:44 riastradh Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -50,20 +50,31 @@ __RCSID("$NetBSD: t_ptrace.c,v 1.5 2022/05/24 20:08:38 andvar Exp $");
* overcomplicate the tests - do not log from a child and use err(3)/errx(3)
* wrapped with FORKEE_ASSERT()/FORKEE_ASSERTX() as that is guaranteed to work.
*/
-#define FORKEE_ASSERTX(x) \
-do { \
- int ret = (x); \
- if (!ret) \
- errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \
- __FILE__, __LINE__, __func__, #x); \
+#define FORKEE_ASSERTX(x) \
+do { \
+ int ret = (x); \
+ if (!ret) \
+ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \
+ __FILE__, __LINE__, __func__, #x); \
} while (0)
-#define FORKEE_ASSERT(x) \
-do { \
- int ret = (x); \
- if (!ret) \
- err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \
- __FILE__, __LINE__, __func__, #x); \
+#define FORKEE_ASSERT(x) \
+do { \
+ int ret = (x); \
+ if (!ret) \
+ err(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: %s", \
+ __FILE__, __LINE__, __func__, #x); \
+} while (0)
+
+#define FORKEE_ASSERT_EQ(x, y) \
+do { \
+ uintmax_t vx = (x); \
+ uintmax_t vy = (y); \
+ int ret = vx == vy; \
+ if (!ret) \
+ errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \
+ "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__, \
+ #x, vx, #y, vy); \
} while (0)
ATF_TC(attach_pid0);
@@ -108,8 +119,7 @@ ATF_TC_BODY(attach_pid1_securelevel, tc)
int level;
size_t len = sizeof(level);
- ATF_REQUIRE(sysctlbyname("kern.securelevel", &level, &len, NULL, 0)
- != -1);
+ RL(sysctlbyname("kern.securelevel", &level, &len, NULL, 0));
if (level < 0) {
atf_tc_skip("Test must be run with securelevel >= 0");
@@ -139,7 +149,7 @@ ATF_TC_HEAD(attach_chroot, tc)
"root");
atf_tc_set_md_var(tc, "require.user", "root");
-}
+}
ATF_TC_BODY(attach_chroot, tc)
{
@@ -150,14 +160,14 @@ ATF_TC_BODY(attach_chroot, tc)
uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */
(void)memset(buf, '\0', sizeof(buf));
- ATF_REQUIRE(getcwd(buf, sizeof(buf)) != NULL);
+ REQUIRE_LIBC(getcwd(buf, sizeof(buf)), NULL);
(void)strlcat(buf, "/dir", sizeof(buf));
- ATF_REQUIRE(mkdir(buf, 0500) == 0);
- ATF_REQUIRE(chdir(buf) == 0);
+ RL(mkdir(buf, 0500));
+ RL(chdir(buf));
- ATF_REQUIRE(pipe(fds_toparent) == 0);
- ATF_REQUIRE(pipe(fds_fromparent) == 0);
+ RL(pipe(fds_toparent));
+ RL(pipe(fds_fromparent));
child = atf_utils_fork();
if (child == 0) {
FORKEE_ASSERT(close(fds_toparent[0]) == 0);
@@ -165,33 +175,40 @@ ATF_TC_BODY(attach_chroot, tc)
FORKEE_ASSERT(chroot(buf) == 0);
- rv = write(fds_toparent[1], &msg, sizeof(msg));
- FORKEE_ASSERTX(rv == sizeof(msg));
+ FORKEE_ASSERT((rv = write(fds_toparent[1], &msg, sizeof(msg)))
+ != -1);
+ FORKEE_ASSERT_EQ(rv, sizeof(msg));
- ATF_REQUIRE_ERRNO(EPERM,
- ptrace(PT_ATTACH, getppid(), NULL, 0) == -1);
+ if (ptrace(PT_ATTACH, getppid(), NULL, 0) == 0) {
+ errx(EXIT_FAILURE, "%s unexpectedly succeeded",
+ "ptrace(PT_ATTACH, getppid(), NULL, 0)");
+ } else if (errno != EPERM) {
+ err(EXIT_FAILURE, "%s failed but not with EPERM",
+ "ptrace(PT_ATTACH, getppid(), NULL, 0)");
+ }
- rv = read(fds_fromparent[0], &msg, sizeof(msg));
- FORKEE_ASSERTX(rv == sizeof(msg));
+ FORKEE_ASSERT((rv = read(fds_fromparent[0], &msg, sizeof(msg)))
+ != -1);
+ FORKEE_ASSERT_EQ(rv, sizeof(msg));
_exit(0);
}
- ATF_REQUIRE(close(fds_toparent[1]) == 0);
- ATF_REQUIRE(close(fds_fromparent[0]) == 0);
+ RL(close(fds_toparent[1]));
+ RL(close(fds_fromparent[0]));
printf("Waiting for chrooting of the child PID %d", child);
- rv = read(fds_toparent[0], &msg, sizeof(msg));
- ATF_REQUIRE(rv == sizeof(msg));
+ RL(rv = read(fds_toparent[0], &msg, sizeof(msg)));
+ ATF_REQUIRE(rv == sizeof(msg));
printf("Child is ready, it will try to PT_ATTACH to parent\n");
- rv = write(fds_fromparent[1], &msg, sizeof(msg));
+ RL(rv = write(fds_fromparent[1], &msg, sizeof(msg)));
ATF_REQUIRE(rv == sizeof(msg));
printf("fds_fromparent is no longer needed - close it\n");
- ATF_REQUIRE(close(fds_fromparent[1]) == 0);
+ RL(close(fds_fromparent[1]));
printf("fds_toparent is no longer needed - close it\n");
- ATF_REQUIRE(close(fds_toparent[0]) == 0);
+ RL(close(fds_toparent[0]));
}
ATF_TC(traceme_twice);
@@ -206,7 +223,7 @@ ATF_TC_BODY(traceme_twice, tc)
printf("Mark the parent process (PID %d) a debugger of PID %d",
getppid(), getpid());
- ATF_REQUIRE(ptrace(PT_TRACE_ME, 0, NULL, 0) == 0);
+ RL(ptrace(PT_TRACE_ME, 0, NULL, 0));
printf("Mark the parent process (PID %d) a debugger of PID %d again",
getppid(), getpid());
diff --git a/lib/libc/sys/t_ptrace_amd64_wait.h b/lib/libc/sys/t_ptrace_amd64_wait.h
index 8f1ba708961a..1ad8fcc35123 100644
--- a/lib/libc/sys/t_ptrace_amd64_wait.h
+++ b/lib/libc/sys/t_ptrace_amd64_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_amd64_wait.h,v 1.12 2020/01/08 17:23:15 mgorny Exp $ */
+/* $NetBSD: t_ptrace_amd64_wait.h,v 1.13 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -113,7 +113,6 @@ ATF_TC_BODY(x86_64_regs1, tc)
/// ----------------------------------------------------------------------------
-
#define ATF_TP_ADD_TCS_PTRACE_WAIT_AMD64() \
ATF_TP_ADD_TC_HAVE_GPREGS(tp, x86_64_regs1);
#else
diff --git a/lib/libc/sys/t_ptrace_bytetransfer_wait.h b/lib/libc/sys/t_ptrace_bytetransfer_wait.h
index 6e1c7d3ec794..51f25a20e100 100644
--- a/lib/libc/sys/t_ptrace_bytetransfer_wait.h
+++ b/lib/libc/sys/t_ptrace_bytetransfer_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_bytetransfer_wait.h,v 1.1 2020/05/04 22:05:28 kamil Exp $ */
+/* $NetBSD: t_ptrace_bytetransfer_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
enum bytes_transfer_type {
BYTES_TRANSFER_DATA,
BYTES_TRANSFER_DATAIO,
@@ -845,7 +844,6 @@ BYTES_TRANSFER_EOF(bytes_transfer_eof_piod_read_d, "PIOD_READ_D")
BYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_i, "PIOD_WRITE_I")
BYTES_TRANSFER_EOF(bytes_transfer_eof_piod_write_d, "PIOD_WRITE_D")
-
#define ATF_TP_ADD_TCS_PTRACE_WAIT_BYTETRANSFER() \
ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_8); \
ATF_TP_ADD_TC(tp, bytes_transfer_piod_read_d_16); \
diff --git a/lib/libc/sys/t_ptrace_clone_wait.h b/lib/libc/sys/t_ptrace_clone_wait.h
index 47abcd8da05e..2b692df818aa 100644
--- a/lib/libc/sys/t_ptrace_clone_wait.h
+++ b/lib/libc/sys/t_ptrace_clone_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_clone_wait.h,v 1.3 2020/05/11 21:18:11 kamil Exp $ */
+/* $NetBSD: t_ptrace_clone_wait.h,v 1.4 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
static void
clone_body(int flags, bool trackfork, bool trackvfork,
bool trackvforkdone)
diff --git a/lib/libc/sys/t_ptrace_core_wait.h b/lib/libc/sys/t_ptrace_core_wait.h
index 5e5d06648076..7e0d84679b0e 100644
--- a/lib/libc/sys/t_ptrace_core_wait.h
+++ b/lib/libc/sys/t_ptrace_core_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_core_wait.h,v 1.7 2022/06/09 17:39:21 skrll Exp $ */
+/* $NetBSD: t_ptrace_core_wait.h,v 1.10 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
/*
* Parse the core file and find the requested note. If the reading or parsing
* fails, the test is failed. If the note is found, it is read onto buf, up to
@@ -209,7 +208,8 @@ ATF_TC_BODY(core_dump_procinfo, tc)
"without signal to be sent\n");
#if defined(__aarch64__) || defined(__arm__) || defined(__hppa__) || \
- defined(__powerpc__) || defined(__sh3__) || defined(sparc)
+ defined(__powerpc__) || defined(__riscv__) || defined(__sh3__) || \
+ defined(sparc) || defined(__vax__)
/*
* For these archs, program counter is not automatically incremented
* by a trap instruction. We cannot increment PC in the trap handler,
diff --git a/lib/libc/sys/t_ptrace_eventmask_wait.h b/lib/libc/sys/t_ptrace_eventmask_wait.h
index b92226459a70..561dd34ecb64 100644
--- a/lib/libc/sys/t_ptrace_eventmask_wait.h
+++ b/lib/libc/sys/t_ptrace_eventmask_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_eventmask_wait.h,v 1.1 2020/05/05 00:01:14 kamil Exp $ */
+/* $NetBSD: t_ptrace_eventmask_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
static void
eventmask_preserved(int event)
{
diff --git a/lib/libc/sys/t_ptrace_fork_wait.h b/lib/libc/sys/t_ptrace_fork_wait.h
index 08c523d6706d..cb9795ca7e75 100644
--- a/lib/libc/sys/t_ptrace_fork_wait.h
+++ b/lib/libc/sys/t_ptrace_fork_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_fork_wait.h,v 1.7 2020/06/09 00:28:57 kamil Exp $ */
+/* $NetBSD: t_ptrace_fork_wait.h,v 1.8 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
static void
fork_body(const char *fn, bool trackspawn, bool trackfork, bool trackvfork,
bool trackvforkdone, bool newpgrp)
@@ -563,7 +562,7 @@ unrelated_tracer_fork_body(const char *fn, bool trackspawn, bool trackfork,
"and without signal to be sent\n");
SYSCALL_REQUIRE(
ptrace(PT_CONTINUE, tracee2, (void *)1, 0) != -1);
-
+
DPRINTF("Before resuming the tracee process where it left off "
"and without signal to be sent\n");
SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
@@ -590,7 +589,6 @@ unrelated_tracer_fork_body(const char *fn, bool trackspawn, bool trackfork,
SYSCALL_REQUIRE(ptrace(PT_CONTINUE, tracee, (void *)1, 0) != -1);
}
-
if ((trackspawn && strcmp(fn, "spawn") == 0) ||
(trackfork && strcmp(fn, "fork") == 0) ||
(trackvfork && strcmp(fn, "vfork") == 0)) {
@@ -845,7 +843,7 @@ fork_detach_forker_body(const char *fn, bool kill_process)
op = PTRACE_FORK;
else
op = PTRACE_VFORK;
-
+
ATF_REQUIRE_EQ(state.pe_report_event & op, op);
ATF_REQUIRE_EQ(state.pe_other_pid, child);
diff --git a/lib/libc/sys/t_ptrace_lwp_wait.h b/lib/libc/sys/t_ptrace_lwp_wait.h
index e101cef369ff..c56b477a9aef 100644
--- a/lib/libc/sys/t_ptrace_lwp_wait.h
+++ b/lib/libc/sys/t_ptrace_lwp_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_lwp_wait.h,v 1.1 2020/05/05 00:15:45 kamil Exp $ */
+/* $NetBSD: t_ptrace_lwp_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
static int lwpinfo_thread_sigmask[] = {SIGXCPU, SIGPIPE, SIGALRM, SIGURG};
static pthread_mutex_t lwpinfo_thread_mtx = PTHREAD_MUTEX_INITIALIZER;
diff --git a/lib/libc/sys/t_ptrace_register_wait.h b/lib/libc/sys/t_ptrace_register_wait.h
index 71efc69c72c0..f5c78fbd91cb 100644
--- a/lib/libc/sys/t_ptrace_register_wait.h
+++ b/lib/libc/sys/t_ptrace_register_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_register_wait.h,v 1.4 2021/10/14 13:50:36 gson Exp $ */
+/* $NetBSD: t_ptrace_register_wait.h,v 1.5 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
#if defined(HAVE_GPREGS) || defined(HAVE_FPREGS)
static void
access_regs(const char *regset, const char *aux)
diff --git a/lib/libc/sys/t_ptrace_sigchld.c b/lib/libc/sys/t_ptrace_sigchld.c
index 095cd85cc82c..f8de9cc0a8f6 100644
--- a/lib/libc/sys/t_ptrace_sigchld.c
+++ b/lib/libc/sys/t_ptrace_sigchld.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_sigchld.c,v 1.3 2020/05/05 18:12:20 kamil Exp $ */
+/* $NetBSD: t_ptrace_sigchld.c,v 1.7 2025/05/02 02:37:07 riastradh Exp $ */
/*-
* Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_sigchld.c,v 1.3 2020/05/05 18:12:20 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_sigchld.c,v 1.7 2025/05/02 02:37:07 riastradh Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -73,9 +73,14 @@ __RCSID("$NetBSD: t_ptrace_sigchld.c,v 1.3 2020/05/05 18:12:20 kamil Exp $");
static int debug = 0;
#define DPRINTF(a, ...) do \
- if (debug) \
- printf("%s() %d.%d %s:%d " a, \
- __func__, getpid(), _lwp_self(), __FILE__, __LINE__, ##__VA_ARGS__); \
+ if (debug) { \
+ const char *file = __FILE__, *slash = strrchr(file, '/'); \
+ if (slash) \
+ file = slash + 1; \
+ printf("%s() %d.%d %s:%d " a, \
+ __func__, getpid(), _lwp_self(), file, __LINE__, \
+ ##__VA_ARGS__); \
+ } \
while (/*CONSTCOND*/0)
/// ----------------------------------------------------------------------------
@@ -166,7 +171,7 @@ traceme_raise(int sigval)
break;
default:
break;
- }
+ }
PARENT_TO_CHILD("raise1 child", parent_child, msg);
diff --git a/lib/libc/sys/t_ptrace_siginfo_wait.h b/lib/libc/sys/t_ptrace_siginfo_wait.h
index 07f817ca05ae..20a0e4167b21 100644
--- a/lib/libc/sys/t_ptrace_siginfo_wait.h
+++ b/lib/libc/sys/t_ptrace_siginfo_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_siginfo_wait.h,v 1.1 2020/05/05 00:57:34 kamil Exp $ */
+/* $NetBSD: t_ptrace_siginfo_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,9 +26,9 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
static void
-ptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c), int *signal_caught)
+ptrace_siginfo(bool faked, void (*sah)(int a, siginfo_t *b, void *c),
+ int *signal_caught)
{
const int exitval = 5;
const int sigval = SIGINT;
diff --git a/lib/libc/sys/t_ptrace_signal_wait.h b/lib/libc/sys/t_ptrace_signal_wait.h
index 945cab5c2249..be058c824742 100644
--- a/lib/libc/sys/t_ptrace_signal_wait.h
+++ b/lib/libc/sys/t_ptrace_signal_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_signal_wait.h,v 1.5 2021/03/19 00:44:09 simonb Exp $ */
+/* $NetBSD: t_ptrace_signal_wait.h,v 1.10 2025/05/14 12:16:13 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,6 +26,41 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+/* XXX copied from include/fenv.h -- factor me out, please! */
+#if \
+ (defined(__arm__) && defined(__SOFTFP__)) || \
+ (defined(__m68k__) && !defined(__HAVE_68881__)) || \
+ defined(__mips_soft_float) || \
+ (defined(__powerpc__) && defined(_SOFT_FLOAT)) || \
+ (defined(__sh__) && !defined(__SH_FPU_ANY__)) || \
+ 0
+#define SOFTFLOAT
+#endif
+
+#ifdef SOFTFLOAT
+static void
+softfloat_fudge_sigs(const ki_sigset_t *kbefore, ki_sigset_t *kafter)
+{
+ sigset_t before, after;
+
+ /*
+ * XXX Would be nice if the layout of ki_sigset_t were publicly
+ * documented!
+ */
+ __CTASSERT(sizeof(before) == sizeof(*kbefore));
+ __CTASSERT(sizeof(after) == sizeof(*kafter));
+ memcpy(&before, kbefore, sizeof(before));
+ memcpy(&after, kafter, sizeof(after));
+ if (sigismember(&before, SIGFPE)) {
+ fprintf(stderr, "%s: add SIGFPE\n", __func__);
+ sigaddset(&after, SIGFPE);
+ } else {
+ fprintf(stderr, "%s: del SIGFPE\n", __func__);
+ sigdelset(&after, SIGFPE);
+ }
+ memcpy(kafter, &after, sizeof(after));
+}
+#endif
static void
traceme_raise(int sigval)
@@ -43,7 +78,7 @@ traceme_raise(int sigval)
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -87,13 +122,13 @@ traceme_raise(int sigval)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Assert that PT_GET_PROCESS_STATE returns non-error\n");
SYSCALL_REQUIRE(
ptrace(PT_GET_PROCESS_STATE, child, &state, slen) != -1);
- ATF_REQUIRE(memcmp(&state, &zero_state, slen) == 0);
+ TEST_CHECK_MEMEQ(&state, &zero_state, slen);
DPRINTF("Before resuming the child process where it left off "
"and without signal to be sent\n");
@@ -151,7 +186,7 @@ traceme_raisesignal_ignored(int sigignored)
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -187,8 +222,8 @@ traceme_raisesignal_ignored(int sigignored)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and "
"without signal to be sent\n");
@@ -208,8 +243,8 @@ traceme_raisesignal_ignored(int sigignored)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigignored);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigignored);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and "
"without signal to be sent\n");
@@ -266,7 +301,7 @@ traceme_raisesignal_masked(int sigmasked)
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -301,8 +336,8 @@ traceme_raisesignal_masked(int sigmasked)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and "
"without signal to be sent\n");
@@ -364,7 +399,7 @@ traceme_crash(int sig)
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -410,23 +445,25 @@ traceme_crash(int sig)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sig);
switch (sig) {
case SIGTRAP:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
break;
case SIGSEGV:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
break;
case SIGILL:
- ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
- info.psi_siginfo.si_code <= ILL_BADSTK);
+ ATF_CHECK_MSG((info.psi_siginfo.si_code >= ILL_ILLOPC &&
+ info.psi_siginfo.si_code <= ILL_BADSTK),
+ "info.psi_siginfo.si_code=%d ILL_ILLOPC=%d ILL_BADSTK=%d",
+ info.psi_siginfo.si_code, ILL_ILLOPC, ILL_BADSTK);
break;
case SIGFPE:
-// XXXQEMU ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
+// XXXQEMU TEST_CHECK_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
break;
case SIGBUS:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
break;
}
@@ -488,10 +525,19 @@ traceme_signalmasked_crash(int sig)
if (sig == SIGFPE && !are_fpu_exceptions_supported())
atf_tc_skip("FP exceptions are not supported");
+#ifdef SOFTFLOAT
+ /*
+ * Let's try to track down the dregs of PR misc/56820: Many FPE
+ * related tests fail on softfloat machines.
+ */
+ if (sig == SIGFPE)
+ debug = 1;
+#endif
+
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -542,7 +588,7 @@ traceme_signalmasked_crash(int sig)
name[4] = sizeof(kp);
name[5] = 1;
- ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
+ RL(sysctl(name, namelen, &kp, &len, NULL, 0));
kp_sigmask = kp.p_sigmask;
@@ -555,8 +601,8 @@ traceme_signalmasked_crash(int sig)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and "
"without signal to be sent\n");
@@ -576,7 +622,7 @@ traceme_signalmasked_crash(int sig)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
+ RL(sysctl(name, namelen, &kp, &len, NULL, 0));
DPRINTF("kp_sigmask="
"%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
@@ -588,25 +634,54 @@ traceme_signalmasked_crash(int sig)
kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
- ATF_REQUIRE(!memcmp(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask)));
+#ifdef SOFTFLOAT
+ /*
+ * Hardfloat floating-point exception traps raise SIGFPE even
+ * if the process has masked SIGFPE. As a side effect,
+ * delivery of the signal on trap unmasks it -- but as a
+ * special case, if the process is traced, it first stops and
+ * notifies the tracer _before_ unmasking SIGFPE and removing
+ * it from p_sigmask.
+ *
+ * Softfloat floating-point exception traps try to mimic this
+ * behaviour by sigprocmask and sigqueueinfo in userland, but
+ * it is difficult -- and likely not worthwhile -- to emulate
+ * the special case of a traced process. So when the tracer is
+ * notified of the child's signal, the child has _already_
+ * unmasked SIGFPE so it is no longer in p_sigmask. (See
+ * float_raise in lib/libc/softfloat/softfloat-specialize for
+ * details.)
+ *
+ * Since this is probably not worthwhile to address (it only
+ * affects an obscure detail of how the process state manifests
+ * to a debugger), we just pretend that SIGFPE didn't change in
+ * p_sigmask.
+ */
+ if (sig == SIGFPE)
+ softfloat_fudge_sigs(&kp_sigmask, &kp.p_sigmask);
+#endif
+
+ TEST_CHECK_MEMEQ(&kp_sigmask, &kp.p_sigmask, sizeof(kp_sigmask));
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sig);
switch (sig) {
case SIGTRAP:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
break;
case SIGSEGV:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
break;
case SIGILL:
- ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
- info.psi_siginfo.si_code <= ILL_BADSTK);
+ ATF_CHECK_MSG((info.psi_siginfo.si_code >= ILL_ILLOPC &&
+ info.psi_siginfo.si_code <= ILL_BADSTK),
+ "info.psi_siginfo.si_code=%d ILL_ILLOPC=%d ILL_BADSTK=%d",
+ info.psi_siginfo.si_code, ILL_ILLOPC, ILL_BADSTK);
break;
case SIGFPE:
-// XXXQEMU ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
+// XXXQEMU TEST_CHECK_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
break;
case SIGBUS:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
break;
}
@@ -669,10 +744,19 @@ traceme_signalignored_crash(int sig)
if (sig == SIGFPE && !are_fpu_exceptions_supported())
atf_tc_skip("FP exceptions are not supported");
+#ifdef SOFTFLOAT
+ /*
+ * Let's try to track down the dregs of PR misc/56820: Many FPE
+ * related tests fail on softfloat machines.
+ */
+ if (sig == SIGFPE)
+ debug = 1;
+#endif
+
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -725,7 +809,7 @@ traceme_signalignored_crash(int sig)
name[4] = sizeof(kp);
name[5] = 1;
- ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
+ RL(sysctl(name, namelen, &kp, &len, NULL, 0));
kp_sigignore = kp.p_sigignore;
@@ -738,8 +822,8 @@ traceme_signalignored_crash(int sig)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and "
"without signal to be sent\n");
@@ -759,7 +843,7 @@ traceme_signalignored_crash(int sig)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(sysctl(name, namelen, &kp, &len, NULL, 0), 0);
+ RL(sysctl(name, namelen, &kp, &len, NULL, 0));
DPRINTF("kp_sigignore="
"%#02" PRIx32 "%02" PRIx32 "%02" PRIx32 "%02" PRIx32"\n",
@@ -771,25 +855,55 @@ traceme_signalignored_crash(int sig)
kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
- ATF_REQUIRE(!memcmp(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore)));
+#ifdef SOFTFLOAT
+ /*
+ * Hardfloat floating-point exception traps raise SIGFPE even
+ * if the process has set the signal disposition of SIGFPE to
+ * SIG_IGN. As a side effect, delivery of the signal on trap
+ * changes the disposition from SIG_IGN to SIG_DFL -- but as a
+ * special case, if the process is traced, it first stops and
+ * notifies the tracer _before_ changing the disposition and
+ * removing SIGFPE from p_sigignore.
+ *
+ * Softfloat floating-point exception traps try to mimic this
+ * behaviour by sigaction and sigqueueinfo in userland, but it
+ * is difficult -- and likely not worthwhile -- to emulate the
+ * special case of a traced process. So when the tracer is
+ * notified of the child's signal, its disposition has
+ * _already_ been changed to SIG_DFL and so SIGFPE is no longer
+ * in p_sigignore. (See float_raise in
+ * lib/libc/softfloat/softfloat-specialize for details.)
+ *
+ * Since this is probably not worthwhile to address (it only
+ * affects an obscure detail of how the process state manifests
+ * to a debugger), we just pretend that nothing changeed in
+ * whether SIGFPE is ignored or not.
+ */
+ if (sig == SIGFPE)
+ softfloat_fudge_sigs(&kp_sigignore, &kp.p_sigignore);
+#endif
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sig);
+ TEST_CHECK_MEMEQ(&kp_sigignore, &kp.p_sigignore, sizeof(kp_sigignore));
+
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sig);
switch (sig) {
case SIGTRAP:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, TRAP_BRKPT);
break;
case SIGSEGV:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SEGV_MAPERR);
break;
case SIGILL:
- ATF_REQUIRE(info.psi_siginfo.si_code >= ILL_ILLOPC &&
- info.psi_siginfo.si_code <= ILL_BADSTK);
+ ATF_CHECK_MSG((info.psi_siginfo.si_code >= ILL_ILLOPC &&
+ info.psi_siginfo.si_code <= ILL_BADSTK),
+ "info.psi_siginfo.si_code=%d ILL_ILLOPC=%d ILL_BADSTK=%d",
+ info.psi_siginfo.si_code, ILL_ILLOPC, ILL_BADSTK);
break;
case SIGFPE:
-// XXXQEMU ATF_REQUIRE_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
+// XXXQEMU TEST_CHECK_EQ(info.psi_siginfo.si_code, FPE_FLTDIV);
break;
case SIGBUS:
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, BUS_ADRERR);
break;
}
@@ -842,7 +956,7 @@ traceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -877,8 +991,8 @@ traceme_sendsignal_handle(int sigsent, void (*sah)(int a), int *traceme_caught)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and with "
"signal %s to be sent\n", strsignal(sigsent));
@@ -945,7 +1059,7 @@ traceme_sendsignal_masked(int sigsent)
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -975,8 +1089,8 @@ traceme_sendsignal_masked(int sigsent)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and with "
"signal %s to be sent\n", strsignal(sigsent));
@@ -1033,10 +1147,10 @@ traceme_sendsignal_ignored(int sigsent)
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
-
+
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
memset(&sa, 0, sizeof(sa));
@@ -1065,8 +1179,8 @@ traceme_sendsignal_ignored(int sigsent)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and with "
"signal %s to be sent\n", strsignal(sigsent));
@@ -1137,7 +1251,7 @@ traceme_sendsignal_simple(int sigsent)
memset(&info, 0, sizeof(info));
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -1170,8 +1284,8 @@ traceme_sendsignal_simple(int sigsent)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off and with "
"signal %s to be sent\n", strsignal(sigsent));
@@ -1194,8 +1308,8 @@ traceme_sendsignal_simple(int sigsent)
info.psi_siginfo.si_signo, info.psi_siginfo.si_code,
info.psi_siginfo.si_errno);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval);
- ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP);
+ TEST_CHECK_EQ(info.psi_siginfo.si_signo, sigval);
+ TEST_CHECK_EQ(info.psi_siginfo.si_code, SI_LWP);
DPRINTF("Before resuming the child process where it left off "
"and with signal %s to be sent\n", strsignal(sigsent));
@@ -1282,7 +1396,7 @@ traceme_vfork_raise(int sigval)
if (sigval == SIGSTOP) {
parent = getpid();
- watcher = fork();
+ RL(watcher = fork());
ATF_REQUIRE(watcher != 1);
if (watcher == 0) {
/* Double fork(2) trick to reparent to initproc */
@@ -1313,7 +1427,7 @@ traceme_vfork_raise(int sigval)
}
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = vfork()) != -1);
+ RL(child = vfork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -1422,7 +1536,7 @@ traceme_vfork_crash(int sig)
atf_tc_skip("FP exceptions are not supported");
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = vfork()) != -1);
+ RL(child = vfork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -1504,7 +1618,7 @@ traceme_vfork_signalmasked_crash(int sig)
atf_tc_skip("FP exceptions are not supported");
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = vfork()) != -1);
+ RL(child = vfork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -1590,7 +1704,7 @@ traceme_vfork_signalignored_crash(int sig)
atf_tc_skip("FP exceptions are not supported");
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = vfork()) != -1);
+ RL(child = vfork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
@@ -1857,8 +1971,20 @@ unrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
kp.p_sigmask.__bits[0], kp.p_sigmask.__bits[1],
kp.p_sigmask.__bits[2], kp.p_sigmask.__bits[3]);
- FORKEE_ASSERTX(!memcmp(&kp_sigmask, &kp.p_sigmask,
- sizeof(kp_sigmask)));
+#ifdef SOFTFLOAT
+ /*
+ * See above in traceme_signalmasked_crash
+ * about the softfloat trap SIGFPE delivery
+ * quirk that requires us to fudge this test.
+ */
+ if (sig == SIGFPE) {
+ softfloat_fudge_sigs(&kp_sigmask,
+ &kp.p_sigmask);
+ }
+#endif
+
+ FORKEE_ASSERT_MEMEQ(&kp_sigmask, &kp.p_sigmask,
+ sizeof(kp_sigmask));
}
if (ignored) {
@@ -1874,8 +2000,20 @@ unrelated_tracer_sees_crash(int sig, bool masked, bool ignored)
kp.p_sigignore.__bits[0], kp.p_sigignore.__bits[1],
kp.p_sigignore.__bits[2], kp.p_sigignore.__bits[3]);
- FORKEE_ASSERTX(!memcmp(&kp_sigignore, &kp.p_sigignore,
- sizeof(kp_sigignore)));
+#ifdef SOFTFLOAT
+ /*
+ * See above in traceme_signalignored_crash
+ * about the softfloat trap SIGFPE delivery
+ * quirk that requires us to fudge this test.
+ */
+ if (sig == SIGFPE) {
+ softfloat_fudge_sigs(&kp_sigignore,
+ &kp.p_sigignore);
+ }
+#endif
+
+ FORKEE_ASSERT_MEMEQ(&kp_sigignore, &kp.p_sigignore,
+ sizeof(kp_sigignore));
}
switch (sig) {
@@ -2042,7 +2180,7 @@ ATF_TC_BODY(signal_mask_unrelated, tc)
sigset_t intmask;
DPRINTF("Before forking process PID=%d\n", getpid());
- SYSCALL_REQUIRE((child = fork()) != -1);
+ RL(child = fork());
if (child == 0) {
DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid());
FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1);
diff --git a/lib/libc/sys/t_ptrace_syscall_wait.h b/lib/libc/sys/t_ptrace_syscall_wait.h
index bb6b4d431357..f7e0afde03fa 100644
--- a/lib/libc/sys/t_ptrace_syscall_wait.h
+++ b/lib/libc/sys/t_ptrace_syscall_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_syscall_wait.h,v 1.3 2023/03/20 11:19:30 hannken Exp $ */
+/* $NetBSD: t_ptrace_syscall_wait.h,v 1.4 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
static int test_syscall_caught;
static void
diff --git a/lib/libc/sys/t_ptrace_threads_wait.h b/lib/libc/sys/t_ptrace_threads_wait.h
index e87ba74cb99c..5beb0f159dad 100644
--- a/lib/libc/sys/t_ptrace_threads_wait.h
+++ b/lib/libc/sys/t_ptrace_threads_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_threads_wait.h,v 1.1 2020/05/05 00:50:39 kamil Exp $ */
+/* $NetBSD: t_ptrace_threads_wait.h,v 1.3 2025/05/02 02:24:44 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
#define TRACE_THREADS_NUM 100
static volatile int done;
@@ -292,8 +291,8 @@ threads_and_exec(void)
DPRINTF("Before raising %s from child\n", strsignal(sigval));
FORKEE_ASSERT(raise(sigval) == 0);
- FORKEE_ASSERT(pthread_create(&t, NULL,
- thread_and_exec_thread_cb, NULL) == 0);
+ FORKEE_PTHREAD(pthread_create(&t, NULL,
+ thread_and_exec_thread_cb, NULL));
for (;;)
continue;
@@ -566,7 +565,7 @@ ATF_TC_BODY(resume, tc)
FORKEE_ASSERT(raise(sigval) == 0);
DPRINTF("Before creating new thread in child\n");
- FORKEE_ASSERT(pthread_create(&t, NULL, resume_thread, NULL) == 0);
+ FORKEE_PTHREAD(pthread_create(&t, NULL, resume_thread, NULL));
pthread_barrier_wait(&barrier1_resume);
@@ -699,8 +698,8 @@ thread_concurrent_sig_handler(int sig)
{
void *tls_val = pthread_getspecific(thread_concurrent_key);
DPRINTF("Before increment, LWP %d tls_val=%p\n", _lwp_self(), tls_val);
- FORKEE_ASSERT(pthread_setspecific(thread_concurrent_key,
- (void*)((uintptr_t)tls_val + 1)) == 0);
+ FORKEE_PTHREAD(pthread_setspecific(thread_concurrent_key,
+ (void*)((uintptr_t)tls_val + 1)));
}
static void *
@@ -809,41 +808,40 @@ thread_concurrent_test(enum thread_concurrent_signal_handling signal_handle,
}
DPRINTF("Before starting threads from the child\n");
- FORKEE_ASSERT(pthread_barrier_init(
+ FORKEE_PTHREAD(pthread_barrier_init(
&thread_concurrent_barrier, NULL,
- breakpoint_threads + signal_threads + watchpoint_threads)
- == 0);
- FORKEE_ASSERT(pthread_key_create(&thread_concurrent_key, NULL)
- == 0);
+ breakpoint_threads + signal_threads + watchpoint_threads));
+ FORKEE_PTHREAD(pthread_key_create(&thread_concurrent_key,
+ NULL));
for (i = 0; i < signal_threads; i++) {
- FORKEE_ASSERT(pthread_create(&sig_threads[i], NULL,
+ FORKEE_PTHREAD(pthread_create(&sig_threads[i], NULL,
thread_concurrent_signals_thread,
- &signal_handle) == 0);
+ &signal_handle));
}
for (i = 0; i < breakpoint_threads; i++) {
- FORKEE_ASSERT(pthread_create(&bp_threads[i], NULL,
- thread_concurrent_breakpoint_thread, NULL) == 0);
+ FORKEE_PTHREAD(pthread_create(&bp_threads[i], NULL,
+ thread_concurrent_breakpoint_thread, NULL));
}
for (i = 0; i < watchpoint_threads; i++) {
- FORKEE_ASSERT(pthread_create(&wp_threads[i], NULL,
- thread_concurrent_watchpoint_thread, NULL) == 0);
+ FORKEE_PTHREAD(pthread_create(&wp_threads[i], NULL,
+ thread_concurrent_watchpoint_thread, NULL));
}
DPRINTF("Before joining threads from the child\n");
for (i = 0; i < watchpoint_threads; i++) {
- FORKEE_ASSERT(pthread_join(wp_threads[i], NULL) == 0);
+ FORKEE_PTHREAD(pthread_join(wp_threads[i], NULL));
}
for (i = 0; i < breakpoint_threads; i++) {
- FORKEE_ASSERT(pthread_join(bp_threads[i], NULL) == 0);
+ FORKEE_PTHREAD(pthread_join(bp_threads[i], NULL));
}
for (i = 0; i < signal_threads; i++) {
- FORKEE_ASSERT(pthread_join(sig_threads[i], NULL) == 0);
+ FORKEE_PTHREAD(pthread_join(sig_threads[i], NULL));
}
- FORKEE_ASSERT(pthread_key_delete(thread_concurrent_key) == 0);
- FORKEE_ASSERT(pthread_barrier_destroy(
- &thread_concurrent_barrier) == 0);
+ FORKEE_PTHREAD(pthread_key_delete(thread_concurrent_key));
+ FORKEE_PTHREAD(pthread_barrier_destroy(
+ &thread_concurrent_barrier));
DPRINTF("Before exiting of the child process\n");
_exit(exitval);
diff --git a/lib/libc/sys/t_ptrace_topology_wait.h b/lib/libc/sys/t_ptrace_topology_wait.h
index 01bfba0ba108..8bb58414823a 100644
--- a/lib/libc/sys/t_ptrace_topology_wait.h
+++ b/lib/libc/sys/t_ptrace_topology_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_topology_wait.h,v 1.1 2020/05/05 00:33:37 kamil Exp $ */
+/* $NetBSD: t_ptrace_topology_wait.h,v 1.2 2025/05/02 02:24:32 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -26,7 +26,6 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-
ATF_TC(traceme_pid1_parent);
ATF_TC_HEAD(traceme_pid1_parent, tc)
{
diff --git a/lib/libc/sys/t_ptrace_wait.c b/lib/libc/sys/t_ptrace_wait.c
index 69874423d2ee..a1cbcccdeb4a 100644
--- a/lib/libc/sys/t_ptrace_wait.c
+++ b/lib/libc/sys/t_ptrace_wait.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_wait.c,v 1.191 2020/05/05 02:06:08 kamil Exp $ */
+/* $NetBSD: t_ptrace_wait.c,v 1.196 2025/11/18 13:02:13 jkoshy Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019, 2020 The NetBSD Foundation, Inc.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_ptrace_wait.c,v 1.191 2020/05/05 02:06:08 kamil Exp $");
+__RCSID("$NetBSD: t_ptrace_wait.c,v 1.196 2025/11/18 13:02:13 jkoshy Exp $");
#define __LEGACY_PT_LWPINFO
@@ -96,9 +96,14 @@ __CTASSERT(sizeof(((struct ptrace_state *)0)->pe_other_pid) ==
static int debug = 0;
#define DPRINTF(a, ...) do \
- if (debug) \
- printf("%s() %d.%d %s:%d " a, \
- __func__, getpid(), _lwp_self(), __FILE__, __LINE__, ##__VA_ARGS__); \
+ if (debug) { \
+ const char *file = __FILE__, *slash = strrchr(file, '/'); \
+ if (slash) \
+ file = slash + 1; \
+ printf("%s() %d.%d %s:%d " a, \
+ __func__, getpid(), _lwp_self(), file, __LINE__, \
+ ##__VA_ARGS__); \
+ } \
while (/*CONSTCOND*/0)
/// ----------------------------------------------------------------------------
diff --git a/lib/libc/sys/t_ptrace_wait.h b/lib/libc/sys/t_ptrace_wait.h
index 2e40a6533285..2cab30d122b6 100644
--- a/lib/libc/sys/t_ptrace_wait.h
+++ b/lib/libc/sys/t_ptrace_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_wait.h,v 1.34 2022/05/24 20:08:38 andvar Exp $ */
+/* $NetBSD: t_ptrace_wait.h,v 1.42 2025/05/09 01:32:25 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -135,8 +135,33 @@ do { \
uintmax_t vy = (y); \
int ret = vx == vy; \
if (!ret) \
- ATF_REQUIRE_EQ_MSG(vx, vy, "%s(%ju) == %s(%ju)", \
- #x, vx, #y, vy); \
+ ATF_REQUIRE_EQ_MSG(vx, vy, \
+ "%s(%ju=0x%jx) == %s(%ju=0x%jx)", \
+ #x, vx, vx, #y, vy, vy); \
+} while (/*CONSTCOND*/0)
+
+#define TEST_CHECK_EQ(x, y) \
+do { \
+ uintmax_t vx = (x); \
+ uintmax_t vy = (y); \
+ int ret = vx == vy; \
+ if (!ret) \
+ ATF_CHECK_EQ_MSG(vx, vy, \
+ "%s(%ju=0x%jx) == %s(%ju=0x%jx)", \
+ #x, vx, vx, #y, vy, vy); \
+} while (/*CONSTCOND*/0)
+
+#define TEST_CHECK_MEMEQ(x, y, n) \
+do { \
+ const void *vx = (x); \
+ const void *vy = (y); \
+ const size_t vn = (n); \
+ if (__predict_true(memcmp(vx, vy, vn) == 0)) \
+ break; \
+ hexdump(#x, vx, vn); \
+ hexdump(#y, vy, vn); \
+ atf_tc_fail_nonfatal("%s != %s (%s = %zu bytes)", \
+ #x, #y, #n, vn); \
} while (/*CONSTCOND*/0)
/*
@@ -154,8 +179,9 @@ do { \
int ret = vx == vy; \
if (!ret) \
errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \
- "%s(%ju) == %s(%ju)", __FILE__, __LINE__, __func__, \
- #x, vx, #y, vy); \
+ "%s(%jd=0x%jx) == %s(%jd=0x%jx)", \
+ __FILE__, __LINE__, __func__, \
+ #x, vx, vx, #y, vy, vy); \
} while (/*CONSTCOND*/0)
#define FORKEE_ASSERT_NEQ(x, y) \
@@ -165,8 +191,43 @@ do { \
int ret = vx != vy; \
if (!ret) \
errx(EXIT_FAILURE, "%s:%d %s(): Assertion failed for: " \
- "%s(%ju) != %s(%ju)", __FILE__, __LINE__, __func__, \
- #x, vx, #y, vy); \
+ "%s(%ju=0x%jx) != %s(%ju=0x%jx)", \
+ __FILE__, __LINE__, __func__, \
+ #x, vx, vx, #y, vy, vy); \
+} while (/*CONSTCOND*/0)
+
+__unused /* used by FORKEE_ASSERT_MEMEQ, otherwise not used */
+static void
+hexdump(const char *title, const void *buf, size_t len)
+{
+ const unsigned char *p = buf;
+ size_t i;
+
+ fprintf(stderr, "%s (%zu bytes)\n", title, len);
+ for (i = 0; i < len; i++) {
+ if ((i % 8) == 0)
+ fprintf(stderr, " ");
+ fprintf(stderr, " %02hhx", p[i]);
+ if ((i % 16) == 15)
+ fprintf(stderr, "\n");
+ }
+ if (i % 16)
+ fprintf(stderr, "\n");
+}
+
+#define FORKEE_ASSERT_MEMEQ(x, y, n) \
+do { \
+ const void *const vx = (x); \
+ const void *const vy = (y); \
+ const size_t vn = (n); \
+ \
+ if (__predict_true(memcmp(vx, vy, vn) == 0)) \
+ break; \
+ fprintf(stderr, "%s != %s (%s = %zu bytes)\n", #x, #y, #n, vn); \
+ hexdump(#x, vx, vn); \
+ hexdump(#y, vy, vn); \
+ errx(EXIT_FAILURE, "%s:%d %s(): failed", \
+ __FILE__, __LINE__, __func__); \
} while (/*CONSTCOND*/0)
#define FORKEE_ASSERTX(x) \
@@ -185,6 +246,16 @@ do { \
__FILE__, __LINE__, __func__, #x); \
} while (/*CONSTCOND*/0)
+#define FORKEE_PTHREAD(x) \
+do { \
+ int _forkee_pthread_error = (x); \
+ if (_forkee_pthread_error) { \
+ errno = _forkee_pthread_error; \
+ err(EXIT_FAILURE, "%s:%d %s(): %s", __FILE__, __LINE__, \
+ __func__, #x); \
+ } \
+} while (/*CONSTCOND*/0)
+
/*
* Simplify logic for functions using general purpose registers add HAVE_GPREGS
*
@@ -673,10 +744,14 @@ are_fpu_exceptions_supported(void)
return false;
return true;
}
+#elif defined __riscv__
+#define are_fpu_exceptions_supported() 0
#else
#define are_fpu_exceptions_supported() 1
#endif
+volatile double ignore_result;
+
static void __used
trigger_fpe(void)
{
@@ -701,7 +776,7 @@ trigger_fpe(void)
#endif
/* Division by zero causes CPU trap, translated to SIGFPE */
- usleep((int)(a / b));
+ ignore_result = (int)(a / b);
}
static void __used
@@ -750,7 +825,6 @@ find_event_count(struct lwp_event_count list[], lwpid_t lwp, size_t max_lwps)
#define FIND_EVENT_COUNT(list, lwp) \
find_event_count(list, lwp, __arraycount(list))
-
#if defined(TWAIT_HAVE_PID)
#define ATF_TP_ADD_TC_HAVE_PID(a,b) ATF_TP_ADD_TC(a,b)
#else
diff --git a/lib/libc/sys/t_ptrace_x86_wait.h b/lib/libc/sys/t_ptrace_x86_wait.h
index eb0e1928786f..05b2d71d5f80 100644
--- a/lib/libc/sys/t_ptrace_x86_wait.h
+++ b/lib/libc/sys/t_ptrace_x86_wait.h
@@ -1,4 +1,4 @@
-/* $NetBSD: t_ptrace_x86_wait.h,v 1.31 2020/10/27 08:32:36 mgorny Exp $ */
+/* $NetBSD: t_ptrace_x86_wait.h,v 1.33 2025/05/02 02:24:44 riastradh Exp $ */
/*-
* Copyright (c) 2016, 2017, 2018, 2019 The NetBSD Foundation, Inc.
@@ -92,7 +92,7 @@ ATF_TC_BODY(dbregs_print, tc)
DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME);
TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child);
- validate_status_stopped(status, sigval);
+ validate_status_stopped(status, sigval);
DPRINTF("Call GETDBREGS for the child process\n");
SYSCALL_REQUIRE(ptrace(PT_GETDBREGS, child, &r, 0) != -1);
@@ -114,7 +114,6 @@ ATF_TC_BODY(dbregs_print, tc)
TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
}
-
enum dbreg_preserve_mode {
dbreg_preserve_mode_none,
dbreg_preserve_mode_yield,
@@ -222,7 +221,6 @@ dbreg_preserve(int reg, enum dbreg_preserve_mode mode)
TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0));
}
-
ATF_TC(dbregs_preserve_dr0);
ATF_TC_HEAD(dbregs_preserve_dr0, tc)
{
@@ -310,7 +308,6 @@ ATF_TC_BODY(dbregs_preserve_dr2_yield, tc)
dbreg_preserve(0, dbreg_preserve_mode_yield);
}
-
ATF_TC(dbregs_preserve_dr3_yield);
ATF_TC_HEAD(dbregs_preserve_dr3_yield, tc)
{
@@ -376,7 +373,6 @@ ATF_TC_BODY(dbregs_preserve_dr3_continued, tc)
dbreg_preserve(3, dbreg_preserve_mode_continued);
}
-
static void
dbregs_trap_variable(int reg, int cond, int len, bool write)
{
@@ -575,7 +571,7 @@ ATF_TC_BODY(dbregs_dr3_trap_variable_writeonly_byte, tc)
/* 0b00 -- 1 byte */
dbregs_trap_variable(3, 1, 0, true);
-}
+}
ATF_TC(dbregs_dr0_trap_variable_writeonly_2bytes);
ATF_TC_HEAD(dbregs_dr0_trap_variable_writeonly_2bytes, tc)
@@ -2015,7 +2011,7 @@ x86_cve_2018_8897_trigger(void)
*
* It means that, in the first instruction of the $4 handler, we
* think we are safe with interrupts disabled. But we aren't, and
- * just got interrupted.
+ * just got interrupted.
*
* The new interrupt handler doesn't handle this particular context:
* we are entered in kernel mode, the previous context was kernel
@@ -2093,7 +2089,6 @@ ATF_TC_BODY(x86_cve_2018_8897, tc)
#endif
char *trap_page;
struct dbreg db;
-
if (!can_we_set_dbregs()) {
atf_tc_skip("Either run this test as root or set sysctl(3) "
@@ -2469,8 +2464,8 @@ static __inline void get_fpu_regs(struct x86_test_fpu_registers *out)
: "st", "memory"
);
- FORKEE_ASSERT(fsave.s87_cw == fxsave.fx_cw);
- FORKEE_ASSERT(fsave.s87_sw == fxsave.fx_sw);
+ FORKEE_ASSERT_EQ(fsave.s87_cw, fxsave.fx_cw);
+ FORKEE_ASSERT_EQ(fsave.s87_sw, fxsave.fx_sw);
/* fsave contains full tw */
out->cw = fsave.s87_cw;
@@ -3283,230 +3278,238 @@ x86_register_test(enum x86_test_regset regset, enum x86_test_registers regs,
DPRINTF("Before comparing results\n");
switch (regs) {
case GPREGS_32:
- FORKEE_ASSERT(!memcmp(&vals[5].u32,
- &expected[5].u32, sizeof(vals->u32)));
- FORKEE_ASSERT(!memcmp(&vals[4].u32,
- &expected[4].u32, sizeof(vals->u32)));
- FORKEE_ASSERT(!memcmp(&vals[3].u32,
- &expected[3].u32, sizeof(vals->u32)));
- FORKEE_ASSERT(!memcmp(&vals[2].u32,
- &expected[2].u32, sizeof(vals->u32)));
+ FORKEE_ASSERT_MEMEQ(&vals[5].u32,
+ &expected[5].u32, sizeof(vals->u32));
+ FORKEE_ASSERT_MEMEQ(&vals[4].u32,
+ &expected[4].u32, sizeof(vals->u32));
+ FORKEE_ASSERT_MEMEQ(&vals[3].u32,
+ &expected[3].u32, sizeof(vals->u32));
+ FORKEE_ASSERT_MEMEQ(&vals[2].u32,
+ &expected[2].u32, sizeof(vals->u32));
/*FALLTHROUGH*/
case GPREGS_32_EBP_ESP:
- FORKEE_ASSERT(!memcmp(&vals[1].u32,
- &expected[1].u32, sizeof(vals->u32)));
- FORKEE_ASSERT(!memcmp(&vals[0].u32,
- &expected[0].u32, sizeof(vals->u32)));
+ FORKEE_ASSERT_MEMEQ(&vals[1].u32,
+ &expected[1].u32, sizeof(vals->u32));
+ FORKEE_ASSERT_MEMEQ(&vals[0].u32,
+ &expected[0].u32, sizeof(vals->u32));
break;
case GPREGS_64:
case GPREGS_64_R8:
case FPREGS_MM:
- FORKEE_ASSERT(!memcmp(&vals[0].u64,
- &expected[0].u64, sizeof(vals->u64)));
- FORKEE_ASSERT(!memcmp(&vals[1].u64,
- &expected[1].u64, sizeof(vals->u64)));
- FORKEE_ASSERT(!memcmp(&vals[2].u64,
- &expected[2].u64, sizeof(vals->u64)));
- FORKEE_ASSERT(!memcmp(&vals[3].u64,
- &expected[3].u64, sizeof(vals->u64)));
- FORKEE_ASSERT(!memcmp(&vals[4].u64,
- &expected[4].u64, sizeof(vals->u64)));
- FORKEE_ASSERT(!memcmp(&vals[5].u64,
- &expected[5].u64, sizeof(vals->u64)));
- FORKEE_ASSERT(!memcmp(&vals[6].u64,
- &expected[6].u64, sizeof(vals->u64)));
- FORKEE_ASSERT(!memcmp(&vals[7].u64,
- &expected[7].u64, sizeof(vals->u64)));
+ FORKEE_ASSERT_MEMEQ(&vals[0].u64,
+ &expected[0].u64, sizeof(vals->u64));
+ FORKEE_ASSERT_MEMEQ(&vals[1].u64,
+ &expected[1].u64, sizeof(vals->u64));
+ FORKEE_ASSERT_MEMEQ(&vals[2].u64,
+ &expected[2].u64, sizeof(vals->u64));
+ FORKEE_ASSERT_MEMEQ(&vals[3].u64,
+ &expected[3].u64, sizeof(vals->u64));
+ FORKEE_ASSERT_MEMEQ(&vals[4].u64,
+ &expected[4].u64, sizeof(vals->u64));
+ FORKEE_ASSERT_MEMEQ(&vals[5].u64,
+ &expected[5].u64, sizeof(vals->u64));
+ FORKEE_ASSERT_MEMEQ(&vals[6].u64,
+ &expected[6].u64, sizeof(vals->u64));
+ FORKEE_ASSERT_MEMEQ(&vals[7].u64,
+ &expected[7].u64, sizeof(vals->u64));
break;
case FPREGS_FPU:
- FORKEE_ASSERT(vals_fpu.cw == expected_fpu.cw);
- FORKEE_ASSERT(vals_fpu.sw == expected_fpu.sw);
- FORKEE_ASSERT(vals_fpu.tw == expected_fpu.tw);
- FORKEE_ASSERT(vals_fpu.tw_abridged
- == expected_fpu.tw_abridged);
- FORKEE_ASSERT(vals_fpu.ip.fa_64
- == expected_fpu.ip.fa_64);
- FORKEE_ASSERT(vals_fpu.dp.fa_64
- == expected_fpu.dp.fa_64);
+ FORKEE_ASSERT_EQ(vals_fpu.cw, expected_fpu.cw);
+ FORKEE_ASSERT_EQ(vals_fpu.sw, expected_fpu.sw);
+ FORKEE_ASSERT_EQ(vals_fpu.tw, expected_fpu.tw);
+ FORKEE_ASSERT_EQ(vals_fpu.tw_abridged,
+ expected_fpu.tw_abridged);
+ FORKEE_ASSERT_EQ(vals_fpu.ip.fa_64,
+ expected_fpu.ip.fa_64);
+ FORKEE_ASSERT_EQ(vals_fpu.dp.fa_64,
+ expected_fpu.dp.fa_64);
- FORKEE_ASSERT(vals_fpu.st[0].sign_exp
- == expected_fpu.st[0].sign_exp);
- FORKEE_ASSERT(vals_fpu.st[0].mantissa
- == expected_fpu.st[0].mantissa);
- FORKEE_ASSERT(vals_fpu.st[1].sign_exp
- == expected_fpu.st[1].sign_exp);
- FORKEE_ASSERT(vals_fpu.st[1].mantissa
- == expected_fpu.st[1].mantissa);
- FORKEE_ASSERT(vals_fpu.st[2].sign_exp
- == expected_fpu.st[2].sign_exp);
- FORKEE_ASSERT(vals_fpu.st[2].mantissa
- == expected_fpu.st[2].mantissa);
- FORKEE_ASSERT(vals_fpu.st[3].sign_exp
- == expected_fpu.st[3].sign_exp);
- FORKEE_ASSERT(vals_fpu.st[3].mantissa
- == expected_fpu.st[3].mantissa);
- FORKEE_ASSERT(vals_fpu.st[4].sign_exp
- == expected_fpu.st[4].sign_exp);
- FORKEE_ASSERT(vals_fpu.st[4].mantissa
- == expected_fpu.st[4].mantissa);
- FORKEE_ASSERT(vals_fpu.st[5].sign_exp
- == expected_fpu.st[5].sign_exp);
- FORKEE_ASSERT(vals_fpu.st[5].mantissa
- == expected_fpu.st[5].mantissa);
- FORKEE_ASSERT(vals_fpu.st[6].sign_exp
- == expected_fpu.st[6].sign_exp);
- FORKEE_ASSERT(vals_fpu.st[6].mantissa
- == expected_fpu.st[6].mantissa);
+ FORKEE_ASSERT_EQ(vals_fpu.st[0].sign_exp,
+ expected_fpu.st[0].sign_exp);
+ FORKEE_ASSERT_EQ(vals_fpu.st[0].mantissa,
+ expected_fpu.st[0].mantissa);
+ FORKEE_ASSERT_EQ(vals_fpu.st[1].sign_exp,
+ expected_fpu.st[1].sign_exp);
+ FORKEE_ASSERT_EQ(vals_fpu.st[1].mantissa,
+ expected_fpu.st[1].mantissa);
+ FORKEE_ASSERT_EQ(vals_fpu.st[2].sign_exp,
+ expected_fpu.st[2].sign_exp);
+ FORKEE_ASSERT_EQ(vals_fpu.st[2].mantissa,
+ expected_fpu.st[2].mantissa);
+ FORKEE_ASSERT_EQ(vals_fpu.st[3].sign_exp,
+ expected_fpu.st[3].sign_exp);
+ FORKEE_ASSERT_EQ(vals_fpu.st[3].mantissa,
+ expected_fpu.st[3].mantissa);
+ FORKEE_ASSERT_EQ(vals_fpu.st[4].sign_exp,
+ expected_fpu.st[4].sign_exp);
+ FORKEE_ASSERT_EQ(vals_fpu.st[4].mantissa,
+ expected_fpu.st[4].mantissa);
+ FORKEE_ASSERT_EQ(vals_fpu.st[5].sign_exp,
+ expected_fpu.st[5].sign_exp);
+ FORKEE_ASSERT_EQ(vals_fpu.st[5].mantissa,
+ expected_fpu.st[5].mantissa);
+ FORKEE_ASSERT_EQ(vals_fpu.st[6].sign_exp,
+ expected_fpu.st[6].sign_exp);
+ FORKEE_ASSERT_EQ(vals_fpu.st[6].mantissa,
+ expected_fpu.st[6].mantissa);
/* st(7) is left empty == undefined */
break;
case FPREGS_XMM:
- FORKEE_ASSERT(!memcmp(&vals[0].xmm,
- &expected[0].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[1].xmm,
- &expected[1].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[2].xmm,
- &expected[2].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[3].xmm,
- &expected[3].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[4].xmm,
- &expected[4].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[5].xmm,
- &expected[5].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[6].xmm,
- &expected[6].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[7].xmm,
- &expected[7].xmm, sizeof(vals->xmm)));
+ FORKEE_ASSERT_MEMEQ(&vals[0].xmm,
+ &expected[0].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[1].xmm,
+ &expected[1].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[2].xmm,
+ &expected[2].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[3].xmm,
+ &expected[3].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[4].xmm,
+ &expected[4].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[5].xmm,
+ &expected[5].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[6].xmm,
+ &expected[6].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[7].xmm,
+ &expected[7].xmm, sizeof(vals->xmm));
#if defined(__x86_64__)
- FORKEE_ASSERT(!memcmp(&vals[8].xmm,
- &expected[8].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[9].xmm,
- &expected[9].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[10].xmm,
- &expected[10].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[11].xmm,
- &expected[11].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[12].xmm,
- &expected[12].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[13].xmm,
- &expected[13].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[14].xmm,
- &expected[14].xmm, sizeof(vals->xmm)));
- FORKEE_ASSERT(!memcmp(&vals[15].xmm,
- &expected[15].xmm, sizeof(vals->xmm)));
+ FORKEE_ASSERT_MEMEQ(&vals[8].xmm,
+ &expected[8].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[9].xmm,
+ &expected[9].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[10].xmm,
+ &expected[10].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[11].xmm,
+ &expected[11].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[12].xmm,
+ &expected[12].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[13].xmm,
+ &expected[13].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[14].xmm,
+ &expected[14].xmm, sizeof(vals->xmm));
+ FORKEE_ASSERT_MEMEQ(&vals[15].xmm,
+ &expected[15].xmm, sizeof(vals->xmm));
#endif
break;
case FPREGS_YMM:
- FORKEE_ASSERT(!memcmp(&vals[0].ymm,
- &expected[0].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[1].ymm,
- &expected[1].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[2].ymm,
- &expected[2].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[3].ymm,
- &expected[3].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[4].ymm,
- &expected[4].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[5].ymm,
- &expected[5].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[6].ymm,
- &expected[6].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[7].ymm,
- &expected[7].ymm, sizeof(vals->ymm)));
+ FORKEE_ASSERT_MEMEQ(&vals[0].ymm,
+ &expected[0].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[1].ymm,
+ &expected[1].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[2].ymm,
+ &expected[2].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[3].ymm,
+ &expected[3].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[4].ymm,
+ &expected[4].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[5].ymm,
+ &expected[5].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[6].ymm,
+ &expected[6].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[7].ymm,
+ &expected[7].ymm, sizeof(vals->ymm));
#if defined(__x86_64__)
- FORKEE_ASSERT(!memcmp(&vals[8].ymm,
- &expected[8].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[9].ymm,
- &expected[9].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[10].ymm,
- &expected[10].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[11].ymm,
- &expected[11].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[12].ymm,
- &expected[12].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[13].ymm,
- &expected[13].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[14].ymm,
- &expected[14].ymm, sizeof(vals->ymm)));
- FORKEE_ASSERT(!memcmp(&vals[15].ymm,
- &expected[15].ymm, sizeof(vals->ymm)));
+ FORKEE_ASSERT_MEMEQ(&vals[8].ymm,
+ &expected[8].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[9].ymm,
+ &expected[9].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[10].ymm,
+ &expected[10].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[11].ymm,
+ &expected[11].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[12].ymm,
+ &expected[12].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[13].ymm,
+ &expected[13].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[14].ymm,
+ &expected[14].ymm, sizeof(vals->ymm));
+ FORKEE_ASSERT_MEMEQ(&vals[15].ymm,
+ &expected[15].ymm, sizeof(vals->ymm));
#endif
break;
case FPREGS_ZMM:
- FORKEE_ASSERT(!memcmp(&vals[0].zmm,
- &expected[0].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[1].zmm,
- &expected[1].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[2].zmm,
- &expected[2].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[3].zmm,
- &expected[3].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[4].zmm,
- &expected[4].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[5].zmm,
- &expected[5].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[6].zmm,
- &expected[6].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[7].zmm,
- &expected[7].zmm, sizeof(vals->zmm)));
+ FORKEE_ASSERT_MEMEQ(&vals[0].zmm,
+ &expected[0].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[1].zmm,
+ &expected[1].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[2].zmm,
+ &expected[2].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[3].zmm,
+ &expected[3].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[4].zmm,
+ &expected[4].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[5].zmm,
+ &expected[5].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[6].zmm,
+ &expected[6].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[7].zmm,
+ &expected[7].zmm, sizeof(vals->zmm));
#if defined(__x86_64__)
- FORKEE_ASSERT(!memcmp(&vals[8].zmm,
- &expected[8].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[9].zmm,
- &expected[9].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[10].zmm,
- &expected[10].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[11].zmm,
- &expected[11].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[12].zmm,
- &expected[12].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[13].zmm,
- &expected[13].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[14].zmm,
- &expected[14].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[15].zmm,
- &expected[15].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[16].zmm,
- &expected[16].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[17].zmm,
- &expected[17].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[18].zmm,
- &expected[18].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[19].zmm,
- &expected[19].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[20].zmm,
- &expected[20].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[21].zmm,
- &expected[21].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[22].zmm,
- &expected[22].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[23].zmm,
- &expected[23].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[24].zmm,
- &expected[24].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[25].zmm,
- &expected[25].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[26].zmm,
- &expected[26].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[27].zmm,
- &expected[27].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[28].zmm,
- &expected[28].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[29].zmm,
- &expected[29].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[30].zmm,
- &expected[30].zmm, sizeof(vals->zmm)));
- FORKEE_ASSERT(!memcmp(&vals[31].zmm,
- &expected[31].zmm, sizeof(vals->zmm)));
+ FORKEE_ASSERT_MEMEQ(&vals[8].zmm,
+ &expected[8].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[9].zmm,
+ &expected[9].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[10].zmm,
+ &expected[10].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[11].zmm,
+ &expected[11].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[12].zmm,
+ &expected[12].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[13].zmm,
+ &expected[13].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[14].zmm,
+ &expected[14].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[15].zmm,
+ &expected[15].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[16].zmm,
+ &expected[16].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[17].zmm,
+ &expected[17].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[18].zmm,
+ &expected[18].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[19].zmm,
+ &expected[19].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[20].zmm,
+ &expected[20].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[21].zmm,
+ &expected[21].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[22].zmm,
+ &expected[22].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[23].zmm,
+ &expected[23].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[24].zmm,
+ &expected[24].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[25].zmm,
+ &expected[25].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[26].zmm,
+ &expected[26].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[27].zmm,
+ &expected[27].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[28].zmm,
+ &expected[28].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[29].zmm,
+ &expected[29].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[30].zmm,
+ &expected[30].zmm, sizeof(vals->zmm));
+ FORKEE_ASSERT_MEMEQ(&vals[31].zmm,
+ &expected[31].zmm, sizeof(vals->zmm));
#endif
/* k0..k7 */
- FORKEE_ASSERT(vals[32].zmm.a == expected[32].zmm.a);
- FORKEE_ASSERT(vals[32].zmm.b == expected[32].zmm.b);
- FORKEE_ASSERT(vals[32].zmm.c == expected[32].zmm.c);
- FORKEE_ASSERT(vals[32].zmm.d == expected[32].zmm.d);
- FORKEE_ASSERT(vals[32].zmm.e == expected[32].zmm.e);
- FORKEE_ASSERT(vals[32].zmm.f == expected[32].zmm.f);
- FORKEE_ASSERT(vals[32].zmm.g == expected[32].zmm.g);
- FORKEE_ASSERT(vals[32].zmm.h == expected[32].zmm.h);
+ FORKEE_ASSERT_EQ(vals[32].zmm.a,
+ expected[32].zmm.a);
+ FORKEE_ASSERT_EQ(vals[32].zmm.b,
+ expected[32].zmm.b);
+ FORKEE_ASSERT_EQ(vals[32].zmm.c,
+ expected[32].zmm.c);
+ FORKEE_ASSERT_EQ(vals[32].zmm.d,
+ expected[32].zmm.d);
+ FORKEE_ASSERT_EQ(vals[32].zmm.e,
+ expected[32].zmm.e);
+ FORKEE_ASSERT_EQ(vals[32].zmm.f,
+ expected[32].zmm.f);
+ FORKEE_ASSERT_EQ(vals[32].zmm.g,
+ expected[32].zmm.g);
+ FORKEE_ASSERT_EQ(vals[32].zmm.h,
+ expected[32].zmm.h);
break;
}
break;
diff --git a/lib/libc/sys/t_select.c b/lib/libc/sys/t_select.c
index 04a684a8cdea..8559ccd65e73 100644
--- a/lib/libc/sys/t_select.c
+++ b/lib/libc/sys/t_select.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_select.c,v 1.4 2017/01/13 21:18:33 christos Exp $ */
+/* $NetBSD: t_select.c,v 1.5 2024/10/18 16:39:41 riastradh Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,18 +29,20 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <assert.h>
#include <sys/types.h>
+
#include <sys/select.h>
#include <sys/wait.h>
+
+#include <assert.h>
#include <err.h>
-#include <stdio.h>
-#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
#include <signal.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
#include <atf-c.h>
@@ -207,11 +209,42 @@ ATF_TC_BODY(pselect_timeout, tc)
}
}
+ATF_TC(select_badfd);
+ATF_TC_HEAD(select_badfd, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr", "Checks select rejects bad fds");
+}
+
+ATF_TC_BODY(select_badfd, tc)
+{
+ int fd;
+
+ for (fd = 0; fd < FD_SETSIZE; fd++) {
+ fd_set readfds;
+ int ret, error;
+
+ if (fcntl(fd, F_GETFL) != -1 || errno != EBADF)
+ continue;
+
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ alarm(5);
+ errno = 0;
+ ret = select(fd + 1, &readfds, NULL, NULL, NULL);
+ error = errno;
+ alarm(0);
+ errno = error;
+ ATF_CHECK_ERRNO(EBADF, ret == -1);
+ }
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, pselect_sigmask);
ATF_TP_ADD_TC(tp, pselect_timeout);
+ ATF_TP_ADD_TC(tp, select_badfd);
return atf_no_error();
}
diff --git a/lib/libc/sys/t_setrlimit.c b/lib/libc/sys/t_setrlimit.c
index 092b19b9fa39..2bcf4812d8d9 100644
--- a/lib/libc/sys/t_setrlimit.c
+++ b/lib/libc/sys/t_setrlimit.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $ */
+/* $NetBSD: t_setrlimit.c,v 1.11 2023/12/07 16:54:44 riastradh Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $");
+__RCSID("$NetBSD: t_setrlimit.c,v 1.11 2023/12/07 16:54:44 riastradh Exp $");
#include <sys/resource.h>
#include <sys/mman.h>
@@ -48,6 +48,8 @@ __RCSID("$NetBSD: t_setrlimit.c,v 1.7 2020/10/13 06:58:57 rin Exp $");
#include <ucontext.h>
#include <unistd.h>
+#include "h_macros.h"
+
static void sighandler(int);
static const char path[] = "setrlimit";
@@ -524,6 +526,148 @@ ATF_TC_BODY(setrlimit_stack, tc)
}
+ATF_TC(setrlimit_stack_growshrink);
+ATF_TC_HEAD(setrlimit_stack_growshrink, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test that setrlimit(2), RLIMIT_STACK, grows & shrinks the stack");
+}
+
+/*
+ * checkstackchild(n)
+ *
+ * Allocate an array of size n on the stack, and verify it can be
+ * used. If it can't be used, this will crash with SIGSEGV,
+ * deliberately.
+ */
+_Pragma("GCC diagnostic push")
+_Pragma("GCC diagnostic ignored \"-Wstack-protector\"")
+static void
+checkstackchild(size_t n)
+{
+ volatile char *const x = alloca(n);
+ size_t i;
+
+ for (i = 0; i < n; i++)
+ x[i] = 0x1a;
+}
+_Pragma("GCC diagnostic pop")
+
+/*
+ * checkstack(n, expectsegv)
+ *
+ * Check whether we can allocate an array of size n on the stack.
+ *
+ * - If expectsegv, verify that access fails with SIGSEGV.
+ * - If not expectsegv, verify that access succeeds.
+ *
+ * Do this in a subprocess rather than with a SIGSEGV handler,
+ * because once we've allocated an array of size n on the stack,
+ * in the case where the stack is inaccessible, we have just
+ * trashed the stack pointer so badly we can't make function calls
+ * like to a SIGSEGV handler.
+ *
+ * (We could use an alternate signal stack, but I already wrote it
+ * this way, and this is a little simpler and more robust than
+ * juggling signals, setjmp/longjmp, and sigaltstack.)
+ */
+static void
+checkstack(size_t n, int expectsegv)
+{
+ pid_t forked, waited;
+ int status;
+
+ RL(forked = fork());
+ if (forked == 0) { /* child */
+ checkstackchild(n);
+ _exit(expectsegv);
+ }
+
+ /* parent */
+ RL(waited = waitpid(forked, &status, 0));
+ ATF_REQUIRE_EQ_MSG(waited, forked, "waited=%jd forked=%jd",
+ (intmax_t)waited, (intmax_t)forked);
+ if (expectsegv) {
+ ATF_REQUIRE_MSG(!WIFEXITED(status),
+ "expected signal but exited normally with status %d",
+ WEXITSTATUS(status));
+ ATF_REQUIRE_MSG(WIFSIGNALED(status), "status=0x%x", status);
+ ATF_REQUIRE_EQ_MSG(WTERMSIG(status), SIGSEGV, "termsig=%d",
+ WTERMSIG(status));
+ } else {
+ ATF_REQUIRE_MSG(!WIFSIGNALED(status),
+ "expected normal exit but terminated on signal %d",
+ WTERMSIG(status));
+ ATF_REQUIRE_MSG(WIFEXITED(status), "status=0x%x", status);
+ ATF_REQUIRE_EQ_MSG(WEXITSTATUS(status), 0, "exitstatus=%d",
+ WEXITSTATUS(status));
+ }
+}
+
+ATF_TC_BODY(setrlimit_stack_growshrink, tc)
+{
+ struct rlimit res;
+ size_t n;
+
+ /*
+ * Disable core dumps -- we're going to deliberately cause
+ * SIGSEGV to test stack accessibility (which breaks even
+ * calling a function so we can't just use a SIGSEGV handler),
+ * so let's not waste time dumping core.
+ */
+ res = (struct rlimit){ .rlim_cur = 0, .rlim_max = 0 };
+ RL(setrlimit(RLIMIT_CORE, &res));
+
+ /*
+ * Get the current stack size and hard limit.
+ */
+ RL(getrlimit(RLIMIT_STACK, &res));
+ n = res.rlim_cur;
+
+ /*
+ * Verify that we can't get at pages past the end of the stack
+ * right now.
+ */
+ checkstack(n, /*expectsegv*/1);
+
+ /*
+ * Stop if the hard limit is too small to test. Not sure
+ * exactly how much more space we need to verify that setrlimit
+ * actually expands the stack without examining the current
+ * stack pointer relative to the process's stack base, so we'll
+ * just double the stack size -- definitely enough to test
+ * stack growth -- and hope the hard rlimit is big enough to
+ * let us double it.
+ */
+ if (n > res.rlim_max/2)
+ atf_tc_skip("hard stack rlimit is too small");
+
+ /*
+ * Double the stack size. This way we can allocate an array of
+ * length equal to the current stack size and be guaranteed
+ * that (a) it can be allocated, and (b) access to it requires
+ * the stack to have grown.
+ */
+ res.rlim_cur = 2*n;
+ RL(setrlimit(RLIMIT_STACK, &res));
+
+ /*
+ * Verify that we can now get at pages past the end of the new
+ * stack but not beyond that.
+ */
+ checkstack(n, /*expectsegv*/0);
+ if (n < SIZE_MAX/2)
+ checkstack(2*n, /*expectsegv*/1);
+
+ /*
+ * Restore the stack size and verify that we can no longer
+ * access an array of length equal to the whole stack size.
+ */
+ res.rlim_cur = n;
+ RL(setrlimit(RLIMIT_STACK, &res));
+ checkstack(n, /*expectsegv*/1);
+}
+
ATF_TP_ADD_TCS(tp)
{
@@ -538,6 +682,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, setrlimit_perm);
ATF_TP_ADD_TC(tp, setrlimit_nthr);
ATF_TP_ADD_TC(tp, setrlimit_stack);
+ ATF_TP_ADD_TC(tp, setrlimit_stack_growshrink);
return atf_no_error();
}
diff --git a/lib/libc/sys/t_sigtimedwait.c b/lib/libc/sys/t_sigtimedwait.c
index 64b68d9a0607..36304b6c2d11 100644
--- a/lib/libc/sys/t_sigtimedwait.c
+++ b/lib/libc/sys/t_sigtimedwait.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_sigtimedwait.c,v 1.2 2013/03/08 23:18:00 martin Exp $ */
+/* $NetBSD: t_sigtimedwait.c,v 1.5 2025/12/19 04:41:02 riastradh Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -27,15 +27,26 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_sigtimedwait.c,v 1.2 2013/03/08 23:18:00 martin Exp $");
+__RCSID("$NetBSD: t_sigtimedwait.c,v 1.5 2025/12/19 04:41:02 riastradh Exp $");
#include <sys/time.h>
+
+#include <atf-c.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
-#include <atf-c.h>
+#include <unistd.h>
+
+#include "h_macros.h"
+static void
+on_alarm(int signo)
+{
+ const char msg[] = "SIGALRM delivered\n";
+
+ (void)write(STDERR_FILENO, msg, strlen(msg));
+}
ATF_TC(sigtimedwait_all0timeout);
@@ -51,16 +62,20 @@ ATF_TC_BODY(sigtimedwait_all0timeout, tc)
sigset_t block;
struct timespec ts, before, after, len;
siginfo_t info;
- int r;
+ int signo, error;
- sigemptyset(&block);
+ RL(sigemptyset(&block));
ts.tv_sec = 0;
ts.tv_nsec = 0;
- clock_gettime(CLOCK_MONOTONIC, &before);
- r = sigtimedwait(&block, &info, &ts);
- clock_gettime(CLOCK_MONOTONIC, &after);
- ATF_REQUIRE(r == -1);
- ATF_REQUIRE_ERRNO(EAGAIN, errno);
+ RL(clock_gettime(CLOCK_MONOTONIC, &before));
+ signo = sigtimedwait(&block, &info, &ts);
+ error = errno;
+ RL(clock_gettime(CLOCK_MONOTONIC, &after));
+ ATF_REQUIRE_MSG(signo == -1, "signo=%d, expected -1/EAGAIN=%d",
+ signo, EAGAIN);
+ errno = error;
+ ATF_REQUIRE_MSG(errno == EAGAIN, "errno=%d (%s), expected EAGAIN=%d",
+ error, strerror(error), EAGAIN);
timespecsub(&after, &before, &len);
ATF_REQUIRE(len.tv_sec < 1);
}
@@ -78,18 +93,19 @@ ATF_TC_BODY(sigtimedwait_NULL_timeout, tc)
sigset_t sig;
siginfo_t info;
struct itimerval it;
- int r;
+ int signo;
/* arrange for a SIGALRM signal in a few seconds */
memset(&it, 0, sizeof it);
it.it_value.tv_sec = 5;
- ATF_REQUIRE(setitimer(ITIMER_REAL, &it, NULL) == 0);
+ RL(setitimer(ITIMER_REAL, &it, NULL));
/* wait without timeout */
- sigemptyset(&sig);
- sigaddset(&sig, SIGALRM);
- r = sigtimedwait(&sig, &info, NULL);
- ATF_REQUIRE(r == SIGALRM);
+ RL(sigemptyset(&sig));
+ RL(sigaddset(&sig, SIGALRM));
+ RL(signo = sigtimedwait(&sig, &info, NULL));
+ ATF_REQUIRE_MSG(signo == SIGALRM, "signo=%d, expected SIGALRM=%d",
+ signo, SIGALRM);
}
ATF_TC(sigtimedwait_small_timeout);
@@ -106,14 +122,114 @@ ATF_TC_BODY(sigtimedwait_small_timeout, tc)
sigset_t block;
struct timespec ts;
siginfo_t info;
- int r;
+ int signo, error;
+
+ RL(sigemptyset(&block));
+ ts.tv_sec = 5;
+ ts.tv_nsec = 0;
+ signo = sigtimedwait(&block, &info, &ts);
+ ATF_REQUIRE_MSG(signo == -1, "signo=%d, expected -1/EAGAIN=%d",
+ signo, EAGAIN);
+ error = errno;
+ ATF_REQUIRE_MSG(errno == EAGAIN, "errno=%d (%s), expected EAGAIN=%d",
+ error, strerror(error), EAGAIN);
+}
+
+ATF_TC(sigtimedwait_small_timeout_alarm);
+
+ATF_TC_HEAD(sigtimedwait_small_timeout_alarm, tc)
+{
+ atf_tc_set_md_var(tc, "timeout", "15");
+ atf_tc_set_md_var(tc, "descr", "Test sigtimedwait with a small "
+ "timeout");
+}
+
+ATF_TC_BODY(sigtimedwait_small_timeout_alarm, tc)
+{
+ sigset_t block;
+ struct sigaction sa = {.sa_handler = &on_alarm}; /* no SA_RESTART */
+ struct timespec ts;
+ siginfo_t info;
+ int signo;
- sigemptyset(&block);
+ RL(sigaction(SIGALRM, &sa, NULL));
+
+ RL(sigemptyset(&block));
ts.tv_sec = 5;
ts.tv_nsec = 0;
- r = sigtimedwait(&block, &info, &ts);
- ATF_REQUIRE(r == -1);
- ATF_REQUIRE_ERRNO(EAGAIN, errno);
+ RL(sigaddset(&block, SIGALRM));
+ RL(sigprocmask(SIG_BLOCK, &block, NULL));
+ REQUIRE_LIBC(alarm(1), (unsigned)-1);
+ RL(signo = sigtimedwait(&block, &info, &ts));
+ ATF_REQUIRE_MSG(signo == SIGALRM, "signo=%d, expected SIGALRM=%d",
+ signo, SIGALRM);
+}
+
+ATF_TC(sigtimedwait_small_timeout_other_sig);
+
+ATF_TC_HEAD(sigtimedwait_small_timeout_other_sig, tc)
+{
+ atf_tc_set_md_var(tc, "timeout", "15");
+ atf_tc_set_md_var(tc, "descr", "Test sigtimedwait interruption "
+ "by a signal it's not waiting for");
+}
+
+ATF_TC_BODY(sigtimedwait_small_timeout_other_sig, tc)
+{
+ sigset_t sig;
+ struct sigaction sa = {.sa_handler = &on_alarm}; /* no SA_RESTART */
+ struct timespec ts;
+ siginfo_t info;
+ int signo, error;
+
+ RL(sigaction(SIGALRM, &sa, NULL));
+
+ RL(sigemptyset(&sig));
+ ts.tv_sec = 5;
+ ts.tv_nsec = 0;
+ RL(sigaddset(&sig, SIGUSR1));
+ RL(sigprocmask(SIG_BLOCK, &sig, NULL));
+ REQUIRE_LIBC(alarm(1), (unsigned)-1);
+ /*
+ * This returns 0 sometimes, when it should return -1/EINTR
+ * because some signal unblocked was delivered.
+ */
+ signo = sigtimedwait(&sig, &info, &ts);
+ ATF_REQUIRE_MSG(signo == -1, "signo=%d, expected -1/EINTR=%d",
+ signo, EINTR);
+ error = errno;
+ ATF_REQUIRE_MSG(errno == EINTR, "errno=%d (%s), expected EINTR=%d",
+ error, strerror(error), EINTR);
+}
+
+ATF_TC(sigwaitinfo_other_sig);
+
+ATF_TC_HEAD(sigwaitinfo_other_sig, tc)
+{
+ atf_tc_set_md_var(tc, "timeout", "15");
+ atf_tc_set_md_var(tc, "descr", "Test sigwaitinfo interruption "
+ "by a signal it's not waiting for");
+}
+
+ATF_TC_BODY(sigwaitinfo_other_sig, tc)
+{
+ sigset_t sig;
+ struct sigaction sa = {.sa_handler = &on_alarm}; /* no SA_RESTART */
+ siginfo_t info;
+ int signo, error;
+
+ RL(sigaction(SIGALRM, &sa, NULL));
+
+ RL(sigemptyset(&sig));
+ RL(sigaddset(&sig, SIGUSR1));
+ RL(sigprocmask(SIG_BLOCK, &sig, NULL));
+ REQUIRE_LIBC(alarm(1), (unsigned)-1);
+ signo = sigwaitinfo(&sig, &info);
+ ATF_REQUIRE_MSG(signo == -1, "signo=%d, expected -1/EINTR=%d",
+ signo, EINTR);
+ error = errno;
+ ATF_REQUIRE_MSG(errno == EINTR, "errno=%d (%s), expected EINTR=%d",
+ error, strerror(error), EINTR);
}
ATF_TP_ADD_TCS(tp)
@@ -121,6 +237,9 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, sigtimedwait_all0timeout);
ATF_TP_ADD_TC(tp, sigtimedwait_NULL_timeout);
ATF_TP_ADD_TC(tp, sigtimedwait_small_timeout);
+ ATF_TP_ADD_TC(tp, sigtimedwait_small_timeout_alarm);
+ ATF_TP_ADD_TC(tp, sigtimedwait_small_timeout_other_sig);
+ ATF_TP_ADD_TC(tp, sigwaitinfo_other_sig);
return atf_no_error();
}
diff --git a/lib/libc/sys/t_socketpair.c b/lib/libc/sys/t_socketpair.c
index 266d738ccb0f..28246712ccdc 100644
--- a/lib/libc/sys/t_socketpair.c
+++ b/lib/libc/sys/t_socketpair.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_socketpair.c,v 1.2 2017/01/13 20:04:52 christos Exp $ */
+/* $NetBSD: t_socketpair.c,v 1.3 2025/07/17 19:50:40 kre Exp $ */
/*-
* Copyright (c) 2011 The NetBSD Foundation, Inc.
@@ -36,7 +36,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_socketpair.c,v 1.2 2017/01/13 20:04:52 christos Exp $");
+__RCSID("$NetBSD: t_socketpair.c,v 1.3 2025/07/17 19:50:40 kre Exp $");
#include <atf-c.h>
#include <fcntl.h>
@@ -46,6 +46,13 @@ __RCSID("$NetBSD: t_socketpair.c,v 1.2 2017/01/13 20:04:52 christos Exp $");
#include <sys/un.h>
#include <errno.h>
+#ifndef SOCK_CLOFORK
+#define SOCK_CLOFORK 0
+#endif
+#ifndef FD_CLOFORK
+#define FD_CLOFORK 0
+#endif
+
static void
connected(int fd)
{
@@ -81,6 +88,14 @@ run(int flags)
ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOEXEC) == 0);
}
+ if (flags & SOCK_CLOFORK) {
+ ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOFORK) != 0);
+ ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOFORK) != 0);
+ } else {
+ ATF_REQUIRE((fcntl(fd[0], F_GETFD) & FD_CLOFORK) == 0);
+ ATF_REQUIRE((fcntl(fd[1], F_GETFD) & FD_CLOFORK) == 0);
+ }
+
if (flags & SOCK_NONBLOCK) {
ATF_REQUIRE((fcntl(fd[0], F_GETFL) & O_NONBLOCK) != 0);
ATF_REQUIRE((fcntl(fd[1], F_GETFL) & O_NONBLOCK) != 0);
@@ -126,12 +141,28 @@ ATF_TC_BODY(socketpair_cloexec, tc)
run(SOCK_CLOEXEC);
}
+ATF_TC(socketpair_clofork);
+ATF_TC_HEAD(socketpair_clofork, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "A close-on-fork of socketpair(2)");
+}
+
+ATF_TC_BODY(socketpair_clofork, tc)
+{
+#if defined(SOCK_CLOFORK) && SOCK_CLOFORK != 0
+ run(SOCK_CLOFORK);
+#else
+ atf_tc_skip("SOCK_CLOFORK not defined");
+#endif
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, socketpair_basic);
ATF_TP_ADD_TC(tp, socketpair_nonblock);
ATF_TP_ADD_TC(tp, socketpair_cloexec);
+ ATF_TP_ADD_TC(tp, socketpair_clofork);
return atf_no_error();
}
diff --git a/lib/libc/sys/t_swapcontext.c b/lib/libc/sys/t_swapcontext.c
index 82090f785761..75c310fdca3a 100644
--- a/lib/libc/sys/t_swapcontext.c
+++ b/lib/libc/sys/t_swapcontext.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_swapcontext.c,v 1.4 2023/08/01 20:09:12 andvar Exp $ */
+/* $NetBSD: t_swapcontext.c,v 1.5 2024/05/27 22:03:21 thorpej Exp $ */
/*
* Copyright (c) 2012 Emmanuel Dreyfus. All rights reserved.
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: t_swapcontext.c,v 1.4 2023/08/01 20:09:12 andvar Exp $");
+__RCSID("$NetBSD: t_swapcontext.c,v 1.5 2024/05/27 22:03:21 thorpej Exp $");
#include <ucontext.h>
#include <stdio.h>
@@ -81,13 +81,9 @@ mainfunc(void)
nctx.uc_stack.ss_sp = stack;
nctx.uc_stack.ss_size = sizeof(stack);
-#ifndef _UC_TLSBASE
- ATF_REQUIRE_MSG(0, "_UC_TLSBASE is not defined");
-#else /* _UC_TLSBASE */
ATF_REQUIRE(nctx.uc_flags & _UC_TLSBASE);
if (!alter_tlsbase)
nctx.uc_flags &= ~_UC_TLSBASE;
-#endif /* _UC_TLSBASE */
makecontext(&nctx, swapfunc, 0);
@@ -108,6 +104,9 @@ ATF_TC_HEAD(swapcontext1, tc)
}
ATF_TC_BODY(swapcontext1, tc)
{
+#ifdef __vax__
+ atf_tc_expect_fail("PR port-vax/58290");
+#endif
alter_tlsbase = 0;
mainfunc();
}
@@ -120,6 +119,9 @@ ATF_TC_HEAD(swapcontext2, tc)
}
ATF_TC_BODY(swapcontext2, tc)
{
+#ifdef __vax__
+ atf_tc_expect_fail("PR port-vax/58290");
+#endif
alter_tlsbase = 1;
mainfunc();
}
diff --git a/lib/libc/sys/t_timer_create.c b/lib/libc/sys/t_timer_create.c
index e8a6acd08efc..403413b6a808 100644
--- a/lib/libc/sys/t_timer_create.c
+++ b/lib/libc/sys/t_timer_create.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_timer_create.c,v 1.5 2017/01/16 16:32:13 christos Exp $ */
+/* $NetBSD: t_timer_create.c,v 1.11 2026/02/07 01:47:23 riastradh Exp $ */
/*-
* Copyright (c) 2010 The NetBSD Foundation, Inc.
@@ -34,32 +34,45 @@
#include <time.h>
#include <unistd.h>
+#include "h_macros.h"
+
+#define TIME_MAX __type_max(time_t)
+
static timer_t t;
-static bool fail = true;
+static sig_atomic_t expired;
+
+enum mode {
+ PAST,
+ EXPIRE,
+ NOEXPIRE,
+};
static void
timer_signal_handler(int signo, siginfo_t *si, void *osi __unused)
{
+ const int errno_save = errno;
timer_t *tp;
tp = si->si_value.sival_ptr;
if (*tp == t && signo == SIGALRM)
- fail = false;
+ expired = 1;
(void)fprintf(stderr, "%s: %s\n", __func__, strsignal(signo));
+ errno = errno_save;
}
static void
-timer_signal_create(clockid_t cid, bool expire)
+timer_signal_create(clockid_t cid, enum mode mode, int flags)
{
- struct itimerspec tim;
+ struct itimerspec tim, rtim, otim;
+ struct timespec t0, t1, dt;
struct sigaction act;
struct sigevent evt;
sigset_t set;
t = 0;
- fail = true;
+ expired = 0;
(void)memset(&evt, 0, sizeof(struct sigevent));
(void)memset(&act, 0, sizeof(struct sigaction));
@@ -91,22 +104,143 @@ timer_signal_create(clockid_t cid, bool expire)
ATF_REQUIRE(timer_create(cid, &evt, &t) == 0);
/*
- * Start the timer. After this, unblock the signal.
+ * Configure the timer for -1, 1, or 5 sec from now, depending
+ * on whether we want it to have fired, to fire within 2sec, or
+ * to not fire within 2sec.
*/
- tim.it_value.tv_sec = expire ? 5 : 1;
+ switch (mode) {
+ case PAST:
+ ATF_REQUIRE(flags & TIMER_ABSTIME);
+ tim.it_value.tv_sec = -1;
+ break;
+ case EXPIRE:
+ tim.it_value.tv_sec = 1;
+ break;
+ case NOEXPIRE:
+ tim.it_value.tv_sec = 5;
+ break;
+ }
tim.it_value.tv_nsec = 0;
- ATF_REQUIRE(timer_settime(t, 0, &tim, NULL) == 0);
+ /*
+ * Save the relative time and adjust for absolute time of
+ * requested.
+ */
+ rtim = tim;
+ RL(clock_gettime(cid, &t0));
+ if (flags & TIMER_ABSTIME)
+ timespecadd(&t0, &tim.it_value, &tim.it_value);
+
+ fprintf(stderr, "now is %lld sec %d nsec\n",
+ (long long)t0.tv_sec, (int)t0.tv_nsec);
+ fprintf(stderr, "expire at %lld sec %d nsec\n",
+ (long long)tim.it_value.tv_sec, (int)tim.it_value.tv_nsec);
+ RL(timer_settime(t, flags, &tim, NULL));
+ RL(timer_settime(t, flags, &tim, &otim));
- (void)sigprocmask(SIG_UNBLOCK, &set, NULL);
- (void)sleep(2);
+ RL(clock_gettime(cid, &t1));
+ timespecsub(&t1, &t0, &dt);
+ fprintf(stderr, "%lld sec %d nsec elapsed\n",
+ (long long)dt.tv_sec, (int)dt.tv_nsec);
- if (expire) {
- if (!fail)
- atf_tc_fail("timer fired too soon");
- } else {
- if (fail)
- atf_tc_fail("timer failed to fire");
+ /*
+ * Check to make sure the time remaining is at most the
+ * relative time we expected -- plus slop of up to 2sec,
+ * because timer_settime rounds the duration up to a multiple
+ * of a tick period, which is at most 1sec (usually more like
+ * 10ms or 1ms, and in the future with high-resolution timers
+ * it'll be more like clock_getres(cid), but we don't have a
+ * way to get this bound right now), and if we ask for a wakeup
+ * (say) 0.9tick at a time 0.8tick before the next tick, the
+ * next tick is too early so we have to wait two ticks.
+ *
+ * The main point of this is to make sure that we're not
+ * getting absolute time by mistake (PR 58917) so the slop of
+ * 2sec is fine.
+ *
+ * Parentheses are required around the argument
+ *
+ * &(const struct timespec){2, 0}
+ *
+ * to timespecadd because it's a macro and the brilliant C
+ * preprocessor splits arguments at a comma if they're not
+ * parenthesized.
+ */
+ if (flags & TIMER_ABSTIME) {
+ timespecadd(&rtim.it_value, (&(const struct timespec){2, 0}),
+ &rtim.it_value);
+ }
+ ATF_CHECK_MSG(timespeccmp(&otim.it_value, &rtim.it_value, <=),
+ "time remaining %lld sec %d nsec,"
+ " expected at most %lld sec %d nsec",
+ (long long)otim.it_value.tv_sec, (int)otim.it_value.tv_nsec,
+ (long long)rtim.it_value.tv_sec, (int)rtim.it_value.tv_nsec);
+
+#if 0
+ /*
+ * Check to make sure that the amount the time remaining has
+ * gone down is at most the time elapsed.
+ *
+ * XXX Currently the time returned by timer_settime is only
+ * good to the nearest kernel tick (typically 10ms or 1ms), not
+ * to the resolution of the underlying clock -- unlike
+ * clock_gettime. So we can't set this bound. Not sure
+ * whether this is a bug or not, hence #if 0 instead of
+ * atf_tc_expect_fail.
+ */
+ timespecsub(&t1, &t0, &dt);
+ timespecsub(&rtim.it_value, &otim.it_value, &rtim.it_value);
+ ATF_CHECK_MSG(timespeccmp(&rtim.it_value, &dt, <=),
+ "time remaining went down by %lld sec %d nsec,"
+ " expected at most %lld sec %d nsec",
+ (long long)rtim.it_value.tv_sec, (int)rtim.it_value.tv_nsec,
+ (long long)dt.tv_sec, (int)dt.tv_nsec);
+#endif
+
+ /*
+ * Check to make sure the reload interval is what we set.
+ */
+ ATF_CHECK_MSG(timespeccmp(&otim.it_interval, &rtim.it_interval, ==),
+ "interval %lld sec %d nsec,"
+ " expected %lld sec %d nsec",
+ (long long)otim.it_interval.tv_sec, (int)otim.it_interval.tv_nsec,
+ (long long)rtim.it_interval.tv_sec, (int)rtim.it_interval.tv_nsec);
+
+ (void)sigprocmask(SIG_UNBLOCK, &set, NULL);
+ switch (mode) {
+ case PAST:
+ /*
+ * Wait for at least one tick to pass.
+ *
+ * XXX This does not really follow POSIX, which says
+ * `If the specified time has already passed, the
+ * function shall succeed and the expiration
+ * notification shall be made.'
+ * (https://pubs.opengroup.org/onlinepubs/9799919799.2024edition/functions/timer_settime.html),
+ * suggesting that it should be immediate without any
+ * further delay, but other operating systems also
+ * sometimes have a small delay.
+ */
+ RL(clock_nanosleep(cid, 0, &(const struct timespec){0, 1},
+ NULL));
+ ATF_CHECK_MSG(expired, "timer failed to fire immediately");
+ break;
+ case EXPIRE:
+ case NOEXPIRE:
+ ATF_CHECK_MSG(!expired, "timer fired too soon");
+ (void)sleep(2);
+ switch (mode) {
+ case PAST:
+ __unreachable();
+ case EXPIRE:
+ ATF_CHECK_MSG(expired,
+ "timer failed to fire immediately");
+ break;
+ case NOEXPIRE:
+ ATF_CHECK_MSG(!expired, "timer fired too soon");
+ break;
+ }
+ break;
}
ATF_REQUIRE(timer_delete(t) == 0);
@@ -116,7 +250,7 @@ ATF_TC(timer_create_err);
ATF_TC_HEAD(timer_create_err, tc)
{
atf_tc_set_md_var(tc, "descr",
- "Check errors from timer_create(2) (PR lib/42434");
+ "Check errors from timer_create(2) (PR lib/42434)");
}
ATF_TC_BODY(timer_create_err, tc)
@@ -149,7 +283,21 @@ ATF_TC_HEAD(timer_create_real, tc)
ATF_TC_BODY(timer_create_real, tc)
{
- timer_signal_create(CLOCK_REALTIME, false);
+ timer_signal_create(CLOCK_REALTIME, NOEXPIRE, 0);
+}
+
+ATF_TC(timer_create_real_abs);
+ATF_TC_HEAD(timer_create_real_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), "
+ "SIGEV_SIGNAL, using absolute time");
+}
+
+ATF_TC_BODY(timer_create_real_abs, tc)
+{
+ timer_signal_create(CLOCK_REALTIME, NOEXPIRE, TIMER_ABSTIME);
}
ATF_TC(timer_create_mono);
@@ -163,7 +311,21 @@ ATF_TC_HEAD(timer_create_mono, tc)
ATF_TC_BODY(timer_create_mono, tc)
{
- timer_signal_create(CLOCK_MONOTONIC, false);
+ timer_signal_create(CLOCK_MONOTONIC, NOEXPIRE, 0);
+}
+
+ATF_TC(timer_create_mono_abs);
+ATF_TC_HEAD(timer_create_mono_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), "
+ "SIGEV_SIGNAL, using absolute time");
+}
+
+ATF_TC_BODY(timer_create_mono_abs, tc)
+{
+ timer_signal_create(CLOCK_MONOTONIC, NOEXPIRE, TIMER_ABSTIME);
}
ATF_TC(timer_create_real_expire);
@@ -177,7 +339,21 @@ ATF_TC_HEAD(timer_create_real_expire, tc)
ATF_TC_BODY(timer_create_real_expire, tc)
{
- timer_signal_create(CLOCK_REALTIME, true);
+ timer_signal_create(CLOCK_REALTIME, EXPIRE, 0);
+}
+
+ATF_TC(timer_create_real_expire_abs);
+ATF_TC_HEAD(timer_create_real_expire_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), "
+ "SIGEV_SIGNAL, with expiration, using absolute time");
+}
+
+ATF_TC_BODY(timer_create_real_expire_abs, tc)
+{
+ timer_signal_create(CLOCK_REALTIME, EXPIRE, TIMER_ABSTIME);
}
ATF_TC(timer_create_mono_expire);
@@ -191,7 +367,111 @@ ATF_TC_HEAD(timer_create_mono_expire, tc)
ATF_TC_BODY(timer_create_mono_expire, tc)
{
- timer_signal_create(CLOCK_MONOTONIC, true);
+ timer_signal_create(CLOCK_MONOTONIC, EXPIRE, 0);
+}
+
+ATF_TC(timer_create_mono_expire_abs);
+ATF_TC_HEAD(timer_create_mono_expire_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), "
+ "SIGEV_SIGNAL, with expiration, using absolute time");
+}
+
+ATF_TC_BODY(timer_create_mono_expire_abs, tc)
+{
+ timer_signal_create(CLOCK_MONOTONIC, EXPIRE, TIMER_ABSTIME);
+}
+
+ATF_TC(timer_create_real_past_abs);
+ATF_TC_HEAD(timer_create_real_past_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Checks timer_create(2) with CLOCK_REALTIME and sigevent(3), "
+ "SIGEV_SIGNAL, with expiration passed before timer_settime(2),"
+ " using absolute time");
+}
+
+ATF_TC_BODY(timer_create_real_past_abs, tc)
+{
+ timer_signal_create(CLOCK_REALTIME, PAST, TIMER_ABSTIME);
+}
+
+ATF_TC(timer_create_mono_past_abs);
+ATF_TC_HEAD(timer_create_mono_past_abs, tc)
+{
+
+ atf_tc_set_md_var(tc, "descr",
+ "Checks timer_create(2) with CLOCK_MONOTONIC and sigevent(3), "
+ "SIGEV_SIGNAL, with expiration passed before timer_settime(2),"
+ " using absolute time");
+}
+
+ATF_TC_BODY(timer_create_mono_past_abs, tc)
+{
+ timer_signal_create(CLOCK_MONOTONIC, PAST, TIMER_ABSTIME);
+}
+
+ATF_TC(timer_invalidtime);
+ATF_TC_HEAD(timer_invalidtime, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Verify timer_settime(2) rejects invalid times");
+}
+
+ATF_TC_BODY(timer_invalidtime, tc)
+{
+ const struct itimerspec einval_its[] = {
+ [0] = { .it_value = {-1, 0} },
+ [1] = { .it_value = {0, -1} },
+ [2] = { .it_value = {0, 1000000001} },
+ [3] = { .it_value = {1, 0}, .it_interval = {-1, 0} },
+ [4] = { .it_value = {1, 0}, .it_interval = {0, -1} },
+ [5] = { .it_value = {1, 0}, .it_interval = {0, 1000000001} },
+ [6] = { .it_value = {TIME_MAX - 1, 0}, .it_interval = {0, 0} },
+ [7] = { .it_value = {TIME_MAX, 0}, .it_interval = {0, 0} },
+ };
+ struct timespec now;
+ sigset_t sigs, mask;
+ unsigned i;
+
+ RL(sigemptyset(&sigs));
+ RL(sigaddset(&sigs, SIGALRM));
+ RL(sigprocmask(SIG_BLOCK, &sigs, &mask));
+
+ RL(clock_gettime(CLOCK_MONOTONIC, &now));
+
+ RL(timer_create(CLOCK_MONOTONIC, NULL, &t));
+
+ for (i = 0; i < __arraycount(einval_its); i++) {
+ struct itimerspec its;
+
+ fprintf(stderr, "case %u\n", i);
+
+ ATF_CHECK_ERRNO(EINVAL,
+ timer_settime(t, 0, &einval_its[i], NULL) == -1);
+
+ /*
+ * Try the same with an absolute time near now (unless
+ * that makes it a valid time, in case 0).
+ */
+ if (i == 0)
+ continue;
+ its.it_value = einval_its[i].it_value;
+ its.it_value.tv_sec += now.tv_sec;
+ its.it_interval = einval_its[i].it_interval;
+ ATF_CHECK_ERRNO(EINVAL,
+ timer_settime(t, TIMER_ABSTIME, &its, NULL) == -1);
+ }
+
+ /* Wait up to 2sec to make sure no timer got set anyway. */
+ ATF_CHECK_ERRNO(EAGAIN,
+ sigtimedwait(&sigs, NULL, &(const struct timespec){2, 0}) == -1);
+ RL(sigprocmask(SIG_SETMASK, &mask, NULL));
+
+ RL(timer_delete(t));
}
ATF_TP_ADD_TCS(tp)
@@ -199,9 +479,16 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, timer_create_err);
ATF_TP_ADD_TC(tp, timer_create_real);
+ ATF_TP_ADD_TC(tp, timer_create_real_abs);
ATF_TP_ADD_TC(tp, timer_create_mono);
+ ATF_TP_ADD_TC(tp, timer_create_mono_abs);
ATF_TP_ADD_TC(tp, timer_create_real_expire);
+ ATF_TP_ADD_TC(tp, timer_create_real_expire_abs);
ATF_TP_ADD_TC(tp, timer_create_mono_expire);
+ ATF_TP_ADD_TC(tp, timer_create_mono_expire_abs);
+ ATF_TP_ADD_TC(tp, timer_create_real_past_abs);
+ ATF_TP_ADD_TC(tp, timer_create_mono_past_abs);
+ ATF_TP_ADD_TC(tp, timer_invalidtime);
return atf_no_error();
}
diff --git a/lib/libc/sys/t_timerfd.c b/lib/libc/sys/t_timerfd.c
index e3a4652e39a0..2e57ceba5813 100644
--- a/lib/libc/sys/t_timerfd.c
+++ b/lib/libc/sys/t_timerfd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: t_timerfd.c,v 1.5 2023/07/08 15:32:58 riastradh Exp $ */
+/* $NetBSD: t_timerfd.c,v 1.12 2025/04/16 01:32:48 riastradh Exp $ */
/*-
* Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -29,25 +29,28 @@
#include <sys/cdefs.h>
__COPYRIGHT("@(#) Copyright (c) 2020\
The NetBSD Foundation, inc. All rights reserved.");
-__RCSID("$NetBSD: t_timerfd.c,v 1.5 2023/07/08 15:32:58 riastradh Exp $");
+__RCSID("$NetBSD: t_timerfd.c,v 1.12 2025/04/16 01:32:48 riastradh Exp $");
#include <sys/types.h>
+
#include <sys/event.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/timerfd.h>
+
#include <errno.h>
#include <poll.h>
#include <pthread.h>
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <atf-c.h>
+#include "h_macros.h"
#include "isqemu.h"
struct helper_context {
@@ -145,6 +148,24 @@ ATF_TC_BODY(timerfd_create, tc)
/*****************************************************************************/
+ATF_TC(timerfd_write);
+ATF_TC_HEAD(timerfd_write, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "validates rejection of writes to timerfds");
+}
+ATF_TC_BODY(timerfd_write, tc)
+{
+ int fd;
+ char c = 1;
+
+ RL(fd = timerfd_create(CLOCK_REALTIME, 0));
+ ATF_CHECK_ERRNO(EBADF, write(fd, &c, 1) == -1);
+ RL(close(fd));
+}
+
+/*****************************************************************************/
+
ATF_TC(timerfd_bogusfd);
ATF_TC_HEAD(timerfd_bogusfd, tc)
{
@@ -170,6 +191,106 @@ ATF_TC_BODY(timerfd_bogusfd, tc)
/*****************************************************************************/
+ATF_TC(timerfd_invalidtime);
+ATF_TC_HEAD(timerfd_invalidtime, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "validates rejection of invalid itimerspec by timerfd_settime()");
+}
+ATF_TC_BODY(timerfd_invalidtime, tc)
+{
+ const struct itimerspec einval_its[] = {
+ [0] = { .it_value = {-1, 0} },
+ [1] = { .it_value = {0, -1} },
+ [2] = { .it_value = {0, 1000000001} },
+ [3] = { .it_value = {1, 0}, .it_interval = {-1, 0} },
+ [4] = { .it_value = {1, 0}, .it_interval = {0, -1} },
+ [5] = { .it_value = {1, 0}, .it_interval = {0, 1000000001} },
+ };
+ struct timespec now;
+ unsigned i;
+ fd_set readfds;
+ uint64_t val;
+ int fd;
+
+ RL(clock_gettime(CLOCK_MONOTONIC, &now));
+ RL(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK));
+
+ for (i = 0; i < __arraycount(einval_its); i++) {
+ struct itimerspec its;
+
+ fprintf(stderr, "case %u\n", i);
+
+ ATF_CHECK_ERRNO(EINVAL,
+ timerfd_settime(fd, 0, &einval_its[i], NULL) == -1);
+
+ /*
+ * Try the same with an absolute time near now (unless
+ * that makes it a valid time, in case 0).
+ */
+ if (i == 0)
+ continue;
+ its.it_value = einval_its[i].it_value;
+ its.it_value.tv_sec += now.tv_sec;
+ its.it_interval = einval_its[i].it_interval;
+ ATF_CHECK_ERRNO(EINVAL,
+ timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == -1);
+ }
+
+ /* Wait up to 2sec to make sure no timer got set anyway. */
+ FD_ZERO(&readfds);
+ FD_SET(fd, &readfds);
+ RL(select(fd + 1, &readfds, NULL, NULL, &(struct timeval){2, 0}));
+ ATF_CHECK(!FD_ISSET(fd, &readfds));
+ ATF_CHECK_ERRNO(EAGAIN, timerfd_read(fd, &val) == -1);
+
+ RL(close(fd));
+}
+
+/*****************************************************************************/
+
+ATF_TC(timerfd_past);
+ATF_TC_HEAD(timerfd_past, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "validates trigger on past time");
+}
+ATF_TC_BODY(timerfd_past, tc)
+{
+ struct itimerspec its = {.it_value = {-1, 0}, .it_interval = {0, 0}};
+ struct timespec then, now, delta;
+ uint64_t val;
+ int fd;
+
+ RL(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK));
+
+ RL(clock_gettime(CLOCK_MONOTONIC, &then));
+ timespecadd(&then, &its.it_value, &its.it_value);
+ RL(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL));
+
+ /*
+ * Wait for one tick to pass.
+ *
+ * XXX Having to do this seems silly, but it matches Linux, so.
+ */
+ RL(clock_nanosleep(CLOCK_MONOTONIC, 0, &(const struct timespec){0, 1},
+ NULL));
+
+ RL(timerfd_read(fd, &val));
+ RL(clock_gettime(CLOCK_MONOTONIC, &now));
+ ATF_REQUIRE(check_value_against_bounds(val, 1, 1));
+
+ timespecsub(&now, &then, &delta);
+ ATF_CHECK_MSG(check_value_against_bounds(delta.tv_sec, 0, 0),
+ "then=%jd.%09lu now=%jd.%09lu delta=%jd.%09lu",
+ (intmax_t)then.tv_sec, then.tv_nsec,
+ (intmax_t)now.tv_sec, now.tv_nsec,
+ (intmax_t)delta.tv_sec, delta.tv_nsec);
+
+ RL(close(fd));
+}
+
+/*****************************************************************************/
+
ATF_TC(timerfd_block);
ATF_TC_HEAD(timerfd_block, tc)
{
@@ -183,6 +304,7 @@ ATF_TC_BODY(timerfd_block, tc)
ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
+ struct itimerspec oits;
const struct itimerspec its = {
.it_value = { .tv_sec = 1, .tv_nsec = 0 },
.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
@@ -190,6 +312,12 @@ ATF_TC_BODY(timerfd_block, tc)
ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
ATF_REQUIRE(timerfd_settime(fd, 0, &its, NULL) == 0);
+ ATF_REQUIRE(timerfd_settime(fd, 0, &its, &oits) == 0);
+ ATF_CHECK_MSG(timespeccmp(&oits.it_value, &its.it_value, <=),
+ "timerfd_settime returned %jd.%09lu remaining,"
+ " expected at most %jd.%09lu",
+ (intmax_t)oits.it_value.tv_sec, oits.it_value.tv_nsec,
+ (intmax_t)its.it_value.tv_sec, its.it_value.tv_nsec);
ATF_REQUIRE(timerfd_read(fd, &val) == 0);
ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
ATF_REQUIRE(check_value_against_bounds(val, 1, 1));
@@ -258,15 +386,23 @@ ATF_TC_BODY(timerfd_abstime, tc)
ATF_REQUIRE((fd = timerfd_create(CLOCK_MONOTONIC, 0)) >= 0);
- struct itimerspec its = {
+ struct itimerspec oits, its = {
.it_value = { .tv_sec = 0, .tv_nsec = 0 },
.it_interval = { .tv_sec = 0, .tv_nsec = 0 },
};
ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &then) == 0);
- its.it_value = then;
- its.it_value.tv_sec += 1;
+ delta = (struct timespec){1, 0};
+ timespecadd(&then, &delta, &its.it_value);
ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL) == 0);
+ ATF_REQUIRE(timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, &oits) == 0);
+ timespecadd(&delta, (&(const struct timespec){2, 0}), /* tick slop */
+ &delta);
+ ATF_CHECK_MSG(timespeccmp(&oits.it_value, &delta, <=),
+ "timerfd_settime returned %jd.%09lu remaining,"
+ " expected at most %jd.%09lu",
+ (intmax_t)oits.it_value.tv_sec, oits.it_value.tv_nsec,
+ (intmax_t)delta.tv_sec, delta.tv_nsec);
ATF_REQUIRE(timerfd_read(fd, &val) == 0);
ATF_REQUIRE(clock_gettime(CLOCK_MONOTONIC, &now) == 0);
ATF_REQUIRE(check_value_against_bounds(val, 1, 1));
@@ -389,22 +525,22 @@ ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc)
ATF_REQUIRE((kq = kqueue()) >= 0);
EV_SET(&kev[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
ATF_REQUIRE(kevent(kq, kev, 1, NULL, 0, &ts) == 0);
+ EV_SET(&kev[0], fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+ ATF_CHECK_ERRNO(EINVAL, kevent(kq, kev, 1, NULL, 0, &ts) == -1);
/*
- * fd should be writable but not readable. Pass all of the
- * event bits; we should only get back POLLOUT | POLLWRNORM.
- * (It's writable only in so far as we'll get an error if we try.)
+ * fd should not be ready for anything. Pass all of the event
+ * bits; we should get back nothing.
*/
fds[0].fd = fd;
fds[0].events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI |
POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP;
fds[0].revents = 0;
- ATF_REQUIRE(poll(fds, 1, 0) == 1);
- ATF_REQUIRE(fds[0].revents == (POLLOUT | POLLWRNORM));
+ ATF_REQUIRE(poll(fds, 1, 0) == 0);
/*
- * As above; fd should only be set in writefds upon return
- * from the select() call.
+ * As above; fd should not be set on return from the select()
+ * call.
*/
FD_ZERO(&readfds);
FD_ZERO(&writefds);
@@ -414,9 +550,9 @@ ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc)
FD_SET(fd, &readfds);
FD_SET(fd, &writefds);
FD_SET(fd, &exceptfds);
- ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 1);
+ ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 0);
ATF_REQUIRE(!FD_ISSET(fd, &readfds));
- ATF_REQUIRE(FD_ISSET(fd, &writefds));
+ ATF_REQUIRE(!FD_ISSET(fd, &writefds));
ATF_REQUIRE(!FD_ISSET(fd, &exceptfds));
/*
@@ -438,8 +574,7 @@ ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc)
POLLOUT | POLLWRNORM | POLLWRBAND | POLLHUP;
fds[0].revents = 0;
ATF_REQUIRE(poll(fds, 1, 0) == 1);
- ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM |
- POLLOUT | POLLWRNORM));
+ ATF_REQUIRE(fds[0].revents == (POLLIN | POLLRDNORM));
FD_ZERO(&readfds);
FD_ZERO(&writefds);
@@ -449,9 +584,9 @@ ATF_TC_BODY(timerfd_select_poll_kevent_immed, tc)
FD_SET(fd, &readfds);
FD_SET(fd, &writefds);
FD_SET(fd, &exceptfds);
- ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 2);
+ ATF_REQUIRE(select(fd + 1, &readfds, &writefds, &exceptfds, &tv) == 1);
ATF_REQUIRE(FD_ISSET(fd, &readfds));
- ATF_REQUIRE(FD_ISSET(fd, &writefds));
+ ATF_REQUIRE(!FD_ISSET(fd, &writefds));
ATF_REQUIRE(!FD_ISSET(fd, &exceptfds));
/*
@@ -662,8 +797,12 @@ ATF_TC_BODY(timerfd_fcntl, tc)
ATF_TP_ADD_TCS(tp)
{
+
ATF_TP_ADD_TC(tp, timerfd_create);
+ ATF_TP_ADD_TC(tp, timerfd_write);
ATF_TP_ADD_TC(tp, timerfd_bogusfd);
+ ATF_TP_ADD_TC(tp, timerfd_invalidtime);
+ ATF_TP_ADD_TC(tp, timerfd_past);
ATF_TP_ADD_TC(tp, timerfd_block);
ATF_TP_ADD_TC(tp, timerfd_repeating);
ATF_TP_ADD_TC(tp, timerfd_abstime);