xref: /freebsd/tools/test/stress2/misc/killpg3.sh (revision 02e9120893770924227138ba49df1edb3896112a)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6# Copyright (c) 2023 Peter Holm <pho@FreeBSD.org>
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# killpg(2) version of reaper.sh. No problems seen.
31
32. ../default.cfg
33
34prog=$(basename "$0" .sh)
35cat > /tmp/$prog.c <<EOF
36#include <sys/param.h>
37#include <sys/mman.h>
38#include <sys/wait.h>
39
40
41#include <err.h>
42#include <errno.h>
43#include <pwd.h>
44#include <signal.h>
45#include <stdatomic.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <time.h>
49#include <unistd.h>
50
51static _Atomic(int) *share;
52
53#define GID 0
54#define PARALLEL 10
55#define RDY 1
56#define MAXP 7000
57
58static void
59hand(int i __unused) {
60	_exit(0);
61}
62
63static void
64innerloop(int parallel)
65{
66	pid_t pids[MAXP];
67	struct sigaction sa;
68	int i;
69
70	usleep(1000);
71	for (i = 0; i < parallel; i++) {
72		if ((pids[i] = fork()) == 0) {
73			sa.sa_handler = hand;
74			sigemptyset(&sa.sa_mask);
75			sa.sa_flags = 0;
76			if (sigaction(SIGUSR1, &sa, NULL) == -1)
77				err(1, "sigaction");
78			atomic_fetch_add(&share[RDY], 1);
79			setproctitle("child");
80			for (;;)
81				pause();
82			_exit(0); /* never reached */
83		}
84		if (pids[i] == -1)
85			err(1, "fork()");
86	}
87	for (i = 0; i < parallel; i++) {
88		if (waitpid(pids[i], NULL, 0) != pids[i])
89			err(1, "waitpid(%d) in looper", pids[i]);
90	}
91	_exit(0);
92}
93
94static void
95looper(void)
96{
97	struct sigaction sa;
98	struct passwd *pw;
99	pid_t pids[MAXP];
100	int i, parallel;
101
102	setproctitle("looper");
103	sa.sa_handler = SIG_IGN;
104	sigemptyset(&sa.sa_mask);
105	sa.sa_flags = 0;
106	if (sigaction(SIGUSR1, &sa, NULL) == -1)
107		err(1, "sigaction");
108
109	if ((pw = getpwnam("TUSER")) == NULL)
110		err(1, "no such user: TUSER");
111
112	if (setgroups(1, &pw->pw_gid) ||
113	    setegid(pw->pw_gid) || setgid(pw->pw_gid) ||
114	    seteuid(pw->pw_uid) || setuid(pw->pw_uid))
115		err(1, "Can't drop privileges to \"TUSER\"");
116	endpwent();
117	setpgrp(0, 0);
118	share[GID] = getpgrp();
119	parallel = arc4random() % MAXP + 1;
120	parallel = parallel / PARALLEL * PARALLEL;
121	for (i = 0; i < PARALLEL; i++) {
122		if ((pids[i] = fork()) == 0)
123			innerloop(parallel / PARALLEL);
124	}
125	while (atomic_load(&share[RDY]) != parallel)
126		usleep(10000);
127	if (killpg(share[GID], SIGUSR1) == -1)
128		err(1, "pgkill(%d)", share[GID]);
129	for (i = 0; i < 4; i++) {
130		if (waitpid(pids[i], NULL, 0) != pids[i])
131			err(1, "waitpid(%d) in looper", pids[i]);
132	}
133	_exit(0);
134}
135
136int
137main(void)
138{
139	size_t len;
140	time_t start;
141	int lpid, s1;
142
143	len = PAGE_SIZE;
144	if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE,
145	    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
146		err(1, "mmap");
147
148	start = time(NULL);
149	while (time(NULL) - start < 120) {
150		share[GID] = 0;
151		share[RDY] = 0;
152		if ((lpid = fork()) == 0)
153			looper();
154		if (waitpid(lpid, &s1, 0) != lpid)
155			err(1, "waitpid looper");
156	}
157
158	return (0);
159}
160EOF
161sed -i '' "s#TUSER#$testuser#" /tmp/$prog.c
162mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1
163rm /tmp/$prog.c
164
165export MAXSWAPPCT=70
166n=1
167start=`date +%s`
168while true; do
169	../testcases/swap/swap -t 2m -i 20 > /dev/null &
170	/tmp/$prog & pid=$!
171	st=`date +%s`
172	while kill -0 $pid > /dev/null 2>&1; do
173		e=$((`date +%s` - st))
174		if [ $e -ge 120 ]; then
175			while pgrep -q swap; do pkill swap; done
176		fi
177		if [ $e -ge 600 ]; then
178			echo "Failed in loop #$n after $e seconds."
179			ps -jU$testuser | head -20
180			kill $pid
181			pkill -U$testuser
182			wait
183			rm -f /tmp/$prog
184			exit 1
185		fi
186	done
187	wait
188	[ $((`date +%s` - start)) -ge 300 ] && break
189	n=$((n + 1))
190done
191rm /tmp/$prog
192exit 0
193