1#!/bin/sh 2 3# 4# Copyright (c) 2025 Peter Holm <pho@FreeBSD.org> 5# 6# SPDX-License-Identifier: BSD-2-Clause 7# 8 9# A kqueuex(KQUEUE_CPONFORK) test scenario 10# Test scenario suggestion by: kib 11 12. ../default.cfg 13[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1 14 15dir=/tmp 16odir=`pwd` 17prog=$(basename "$0" .sh) 18cd $dir 19sed '1,/^EOF/d' < $odir/$0 > $dir/$prog.c 20mycc -o $prog -Wall -Wextra -O0 -g $prog.c || exit 1 21rm -f $prog.c 22cd $odir 23 24set -e 25mount | grep "on $mntpoint " | grep -q /dev/md && umount -f $mntpoint 26[ -c /dev/md$mdstart ] && mdconfig -d -u $mdstart 27mdconfig -a -t swap -s 2g -u $mdstart 28newfs $newfs_flags md$mdstart > /dev/null 29mount /dev/md$mdstart $mntpoint 30set +e 31 32(cd $odir/../testcases/swap; ./swap -t 5m -i 20 -h -l 100 > /dev/null) & 33cd $mntpoint 34$dir/$prog 35s=$? 36[ -f $prog.core -a $s -eq 0 ] && 37 { ls -l $prog.core; mv $prog.core /tmp; s=1; } 38cd $odir 39while pkill -9 swap; do :; done 40wait 41 42for i in `jot 6`; do 43 mount | grep -q "on $mntpoint " || break 44 umount $mntpoint && break || sleep 10 45done 46[ $i -eq 6 ] && exit 1 47mdconfig -d -u $mdstart 48rm -rf $dir/$prog 49exit $s 50 51EOF 52#include <sys/param.h> 53#include <sys/event.h> 54#include <sys/mman.h> 55#include <sys/stat.h> 56#include <sys/wait.h> 57 58#include <machine/atomic.h> 59 60#include <err.h> 61#include <errno.h> 62#include <fcntl.h> 63#include <stdio.h> 64#include <stdlib.h> 65#include <string.h> 66#include <time.h> 67#include <unistd.h> 68 69static volatile u_int *share; 70static int loops; 71static char *file = "file"; 72 73#define MAXLOOPS 100 74#define PARALLEL 1 75#define RUNTIME (2 * 60) 76#define SYNC 0 77 78static void 79test(void) 80{ 81 pid_t pid; 82 struct kevent ev[2]; 83 struct timespec ts; 84 int kq, fd, n; 85 86 if ((fd = open(file, O_RDONLY, 0)) == -1) 87 err(1, "open(%s). %s:%d", file, __func__, __LINE__); 88 89 atomic_add_int(&share[SYNC], 1); 90 while (share[SYNC] != PARALLEL) 91 usleep(10000); 92 93 if ((kq = kqueuex(KQUEUE_CPONFORK)) < 0) 94 err(1, "kqueuex"); 95 96 ts.tv_sec = 5; 97 ts.tv_nsec = 0; 98 n = 0; 99 EV_SET(&ev[n], fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR, 100 NOTE_DELETE, 0, 0); 101 n++; 102 103 if (kevent(kq, ev, n, NULL, 0, NULL) < 0) 104 err(1, "kevent()"); 105 if (loops >= MAXLOOPS) { /* start using fork(2) */ 106 if ((pid = fork()) == 0) { 107 n = kevent(kq, NULL, 0, ev, 1, &ts); 108 if (n == -1) 109 err(1, "kevent() in fork\n"); 110 close(fd); 111 close(kq); 112 _exit(0); 113 } 114 if (waitpid(pid, NULL, 0) != pid) 115 err(1, "waitpid(%d)\n", pid); 116 } 117 118 n = kevent(kq, NULL, 0, ev, 1, &ts); 119 if (n == -1) 120 err(1, "kevent()"); 121 close(fd); 122 close(kq); 123 124 _exit(0); 125} 126 127int 128main(void) 129{ 130 pid_t pids[PARALLEL]; 131 size_t len; 132 time_t start; 133 int e, fd, i, status; 134 135 e = 0; 136 len = PAGE_SIZE; 137 loops = 0; 138 if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE, 139 MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED) 140 err(1, "mmap"); 141 142 start = time(NULL); 143 while ((time(NULL) - start) < RUNTIME && e == 0) { 144 loops++; 145 if ((fd = open(file, O_CREAT | O_TRUNC | O_RDWR, 0660)) == 146 -1) 147 err(1, "open(%s)", file); 148 close(fd); 149 share[SYNC] = 0; 150 for (i = 0; i < PARALLEL; i++) { 151 152 if ((pids[i] = fork()) == 0) 153 test(); 154 if (pids[i] == -1) 155 err(1, "fork()"); 156 } 157 while (share[SYNC] != PARALLEL) 158 usleep(10000); 159 if (unlink(file) == -1) 160 err(1, "unlink(%s). %s:%d\n", file, 161 __FILE__, __LINE__); 162 for (i = 0; i < PARALLEL; i++) { 163 if (waitpid(pids[i], &status, 0) == -1) 164 err(1, "waitpid(%d)", pids[i]); 165 if (status != 0) { 166 if (WIFSIGNALED(status)) 167 fprintf(stderr, 168 "pid %d exit signal %d\n", 169 pids[i], WTERMSIG(status)); 170 } 171 e += status == 0 ? 0 : 1; 172 } 173 } 174 175 return (e); 176} 177