xref: /freebsd/tools/test/stress2/misc/minherit.sh (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1#!/bin/sh
2
3#
4# SPDX-License-Identifier: BSD-2-Clause
5#
6# Copyright (c) 2019 Peter Holm
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# minherit() test scenario inspired by Jeff's collapse.sh test.
31# No problems seen.
32
33. ../default.cfg
34[ `id -u` -ne 0 ] && echo "Must be root!" && exit 1
35
36dir=/tmp
37odir=`pwd`
38cd $dir
39sed '1,/^EOF/d' < $odir/$0 > $dir/minherit.c
40mycc -o minherit -Wall -Wextra -O0 -g minherit.c || exit 1
41rm -f minherit.c
42cd $odir
43
44(cd $odir/../testcases/swap; ./swap -t 5m -i 10 -l 50) &
45pid=$!
46cd /tmp
47$dir/minherit
48s=$?
49while pkill swap; do :; done
50wait $oid
51[ -f minherit.core -a $s -eq 0 ] &&
52    { ls -l minherit.core; mv minherit.core $dir; s=1; }
53cd $odir
54
55rm -rf $dir/minherit
56exit $s
57
58EOF
59#include <sys/param.h>
60#include <sys/mman.h>
61#include <sys/stat.h>
62#include <sys/wait.h>
63
64#include <err.h>
65#include <errno.h>
66#include <fcntl.h>
67#include <stdatomic.h>
68#include <stdio.h>
69#include <stdlib.h>
70#include <string.h>
71#include <time.h>
72#include <unistd.h>
73
74static _Atomic(int) *share;
75
76#define ADRSPACE  (1024 * 1024)
77#define CHILDREN 200
78#define PARALLEL 10
79#define RUNTIME (5 * 60)
80#define SYNC 0
81
82static void
83test(void)
84{
85	pid_t pids[CHILDREN];
86	off_t len;
87	void *p;
88	int i, ix, j, n, shared;
89	char *cp;
90
91	(void)atomic_fetch_add(&share[SYNC], 1);
92	while (atomic_load(&share[SYNC]) != PARALLEL)
93		;
94
95	if ((p = mmap(NULL, ADRSPACE, PROT_READ | PROT_WRITE,
96	    MAP_SHARED | MAP_ANON, -1, 0)) == MAP_FAILED) {
97		if (errno == ENOMEM)
98			return;
99		err(1, "mmap()");
100	}
101
102	/* Pick a random bit of address space to change inherit on. */
103	for (i = 0; i < ADRSPACE; i += len) {
104		shared = arc4random() & 0x1;
105		len = roundup2(arc4random() % ((ADRSPACE - i) / 4),
106		    PAGE_SIZE);
107		if (minherit(p + i, len, shared ? INHERIT_SHARE :
108		    INHERIT_COPY) != 0)
109			err(1, "minherit");
110	}
111
112	n = arc4random() % CHILDREN + 1;
113	for (i = 0; i < n; i++) {
114		pids[i] = fork();
115		if (pids[i] == -1)
116			err(1, "fork()");
117		if (pids[i] == 0) {
118			usleep(arc4random() % 100);
119			for (j = 0; j < 10; j++) {
120				cp = p;
121				for (ix = 0; ix < ADRSPACE; ix += PAGE_SIZE) {
122					cp[ix] = 1;
123					if (arc4random() % 100 < 5)
124						usleep(arc4random() % 50);
125				}
126			}
127			_exit(0);
128		}
129	}
130	for (i = 0; i < n; i++) {
131		if (waitpid(pids[i], NULL, 0) == -1)
132			err(1, "waitpid(%d)", pids[i]);
133	}
134
135	_exit(0);
136}
137
138int
139main(void)
140{
141	pid_t pids[PARALLEL];
142	size_t len;
143	time_t start;
144	int e, i, status;
145
146	e = 0;
147	len = PAGE_SIZE;
148	if ((share = mmap(NULL, len, PROT_READ | PROT_WRITE,
149	    MAP_ANON | MAP_SHARED, -1, 0)) == MAP_FAILED)
150		err(1, "mmap");
151
152	start = time(NULL);
153	while ((time(NULL) - start) < RUNTIME && e == 0) {
154		share[SYNC] = 0;
155		for (i = 0; i < PARALLEL; i++) {
156			if ((pids[i] = fork()) == 0)
157				test();
158			if (pids[i] == -1)
159				err(1, "fork()");
160		}
161		for (i = 0; i < PARALLEL; i++) {
162			if (waitpid(pids[i], &status, 0) == -1)
163				err(1, "waitpid(%d)", pids[i]);
164			if (status != 0) {
165				if (WIFSIGNALED(status))
166					fprintf(stderr,
167					    "pid %d exit signal %d\n",
168					    pids[i], WTERMSIG(status));
169				e = status;
170				break;
171			}
172		}
173	}
174
175	return (e);
176}
177