xref: /freebsd/tools/test/stress2/misc/kevent12.sh (revision 4543ef516683042d46f3bd3bb8a4f3f746e00499)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6# Copyright (c) 2018 Dell EMC Isilon
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27# SUCH DAMAGE.
28#
29
30# Bug 228858 - panic when delivering knote to a process who has opened a
31# kqueue() is dying
32# Page fault seen: https://people.freebsd.org/~pho/stress/log/mark052.txt
33# Fixed by r340897.
34
35# Test scenario based on analysis by siddharthtuli gmail com
36
37. ../default.cfg
38
39odir=`pwd`
40
41cd /tmp
42sed '1,/^EOF/d' < $odir/$0 > kevent12.c
43mycc -o kevent12 -Wall -Wextra -O2 -g kevent12.c || exit 1
44rm -f kevent12.c
45cd $odir
46
47(cd $odir/../testcases/swap; ./swap -t 5m -i 20 -l 100 > /dev/null 2>&1) &
48pid=$!
49/tmp/kevent12
50while pgrep -q swap; do
51	pkill -9 swap
52done
53wait $pid
54
55rm -f /tmp/kevent12
56exit 0
57EOF
58#include <sys/types.h>
59#include <sys/event.h>
60#include <sys/wait.h>
61
62#include <err.h>
63#include <errno.h>
64#include <signal.h>
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68#include <time.h>
69#include <unistd.h>
70
71#define PARALLEL 64
72#define RUNTIME (5 * 60)
73
74static pid_t parent;
75static int kq;
76
77static void
78hand(int i __unused) {	/* handler */
79	kill(parent, SIGINT);
80	_exit(1);
81}
82
83static void
84init_kq()
85{
86	kq = kqueue();
87	if (kq == -1)
88		err(1, "kqueue");
89}
90
91static void
92add_watch(pid_t pid)
93{
94	struct kevent kev;
95	char msg[64];
96
97	bzero(&kev, sizeof(kev));
98	kev.ident = pid;
99	kev.flags = EV_ADD | EV_ENABLE;
100	kev.filter = EVFILT_PROC;
101	kev.fflags = NOTE_EXIT | NOTE_EXEC | NOTE_TRACK | NOTE_TRACKERR;
102
103	for (;;) {
104		int res = kevent(kq, &kev, 1, NULL, 0, NULL);
105		if (res == -1) {
106			if (errno == EINTR)
107				continue;
108			if (errno == ESRCH)
109				break;
110
111			snprintf(msg, sizeof(msg),
112				 "kevent - add watch for pid %u", pid);
113			err(1, "%s", msg);
114		}
115		else
116			break;
117	}
118}
119
120static void
121polling()
122{
123	struct kevent kev[10];
124#if defined(DEBUG)
125	pid_t pid;
126	int i;
127#endif
128
129	for (;;) {
130		bzero(&kev, sizeof(kev));
131		if (arc4random() % 100 < 10) {
132			signal(SIGALRM, hand);
133			ualarm(10000, 0);
134		}
135		int res = kevent(kq, NULL, 0, kev,
136				 sizeof(kev) / sizeof(kev[0]), NULL);
137		if (res == -1) {
138			if (errno == EINTR)
139				continue;
140
141			if (errno == ESRCH)
142				continue;
143
144			err(1, "kevent");
145		}
146
147#if defined(DEBUG)
148		for (i = 0; i < res; i++) {
149			pid = kev[i].ident;
150			if (kev[i].fflags & NOTE_CHILD) {
151				add_watch(pid);
152				printf("%u - new process, parent %u\n", pid,
153				    (unsigned int)kev[i].data);
154			}
155			if (kev[i].fflags & NOTE_FORK) {
156				printf("%u forked\n", pid);
157			}
158			if (kev[i].fflags & NOTE_EXEC) {
159				printf("%u called exec\n", pid);
160			}
161			if (kev[i].fflags & NOTE_EXIT) {
162				printf("%u exited\n", pid);
163				if (parent == pid)
164					return;
165			}
166			if (kev[i].fflags & NOTE_TRACK) {
167				printf("%u forked - track\n", pid);
168			}
169			if (kev[i].fflags & NOTE_TRACKERR) {
170				fprintf(stderr, "%u - track error\n", pid);
171			}
172		}
173#endif
174	}
175}
176
177void
178churn(void)
179{
180	pid_t pid;
181	time_t  start;
182	char *cmdline[] = { "/usr/bin/true", NULL };
183
184	start = time(NULL);
185	while (time(NULL) - start < RUNTIME) {
186		if ((pid = fork()) == -1)
187			err(1, "fork");
188		if (pid == 0) {
189			if (execve(cmdline[0], cmdline, NULL) == -1)
190				err(1, "execve");
191		}
192		if (waitpid(pid, NULL, 0) != pid)
193			err(1, "waitpid(%d):%d", pid, __LINE__);
194	}
195
196	_exit(0);
197}
198
199int
200test(void)
201{
202	if ((parent = fork()) == 0)
203		churn();
204
205	init_kq();
206	add_watch(parent);
207	polling();
208	if (waitpid(parent, NULL, 0) != parent)
209		err(1, "waitpid(%d):%d", parent, __LINE__);
210
211	_exit(0);
212}
213
214int
215main(void)
216{
217	pid_t pids[PARALLEL];
218	time_t start;
219	int i;
220
221	start = time(NULL);
222	while (time(NULL) - start < RUNTIME) {
223		for (i = 0; i < PARALLEL; i++) {
224			if ((pids[i] = fork()) == 0)
225				test();
226		}
227		for (i = 0; i < PARALLEL; i++)
228			if (waitpid(pids[i], NULL, 0) != pids[i])
229				err(1, "waitpid(%d):%d", pids[i], __LINE__);
230	}
231
232	return (0);
233}
234