yield.c revision 289954
1/*
2 * Copyright (c) 1996-1999
3 *	HD Associates, Inc.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by HD Associates, Inc
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 * $FreeBSD: stable/10/tools/regression/p1003_1b/yield.c 289954 2015-10-25 22:30:45Z ngie $
32 *
33 */
34#include <sys/types.h>
35#include <unistd.h>
36#include <stdlib.h>
37#include <stdio.h>
38#include <errno.h>
39#include <err.h>
40#include <fcntl.h>
41#include <sys/types.h>
42#include <sys/mman.h>
43#include <sched.h>
44#include <stdlib.h>
45#include <sys/wait.h>
46
47#include "prutil.h"
48
49/* buzz: busy wait a random amount of time.
50 */
51static void buzz(int n)
52{
53	volatile int i;
54	int m = random() & 0x0ffff;
55	for (i = 0; i < m; i++)
56		;
57}
58
59/* Yield: Verify that "sched_yield" works for the FIFO case.
60 * This runs several processes and verifies that the yield seems
61 * to permit the next one on the ready queue to run.
62 */
63int yield(int argc, char *argv[])
64{
65	volatile int *p;
66	int i;
67	int nslaves, n;
68	int master, slave;
69	pid_t youngest = !0;	/* Our youngest child */
70	struct sched_param set, got;
71	int nloops = 1000;
72
73	errno = 0;
74
75	set.sched_priority = sched_get_priority_max(SCHED_FIFO);
76	if (set.sched_priority == -1 && errno) {
77		perror("sched_get_priority_max");
78		exit(errno);
79	}
80
81	if (argc == 1)
82		n = nslaves = 10;
83
84	else if (argc != 2) {
85		fprintf(stderr, "usage: prog [n_instances]\n");
86		exit(-1);
87	}
88	else
89		n = nslaves = atoi(argv[1]);
90
91	p = (int *)mmap(0, sizeof(int),
92	PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
93
94	if (p == (int *)-1)
95		err(errno, "mmap");
96
97	*p = 0;
98
99	if (sched_setscheduler(0, SCHED_FIFO, &set) == -1)
100		err(errno, "sched_setscheduler");
101
102	/* I better still be SCHED_FIFO and RT_PRIO_MAX:
103	 */
104	(void)sched_is(__LINE__, &got, SCHED_FIFO);
105	if (got.sched_priority != set.sched_priority) {
106		fprintf(stderr, "line %d: scheduler screwup\n",
107		__LINE__);
108		exit(-1);
109	}
110
111	slave = 0;
112	master = 1;
113
114	/* Fork off the slaves.
115	 */
116	for (i = 0; i < nslaves; i++) {
117		if ((youngest = fork()) == 0) {
118			/* I better still be SCHED_FIFO and RT_PRIO_MAX:
119			 */
120			(void)sched_is(__LINE__, &got, SCHED_FIFO);
121
122			if (got.sched_priority != set.sched_priority) {
123				fprintf(stderr, "line %d: scheduler screwup\n",
124				__LINE__);
125				exit(-1);
126			}
127
128			master = 0;	/* I'm a slave */
129			slave = i + 1;	/* With this flag */
130			*p = slave;	/* And I live */
131			break;
132		}
133	}
134
135	if (master) {
136		/* If we conform the slave processes haven't run yet.
137		 * The master must yield to let the first slave run.
138		 */
139		if (*p != 0) {
140			fprintf(stderr,
141			"Error at line %d: Writer %d has run\n", __LINE__, *p);
142			exit(-1);
143		}
144	}
145
146	/* Now the master yields, the first slave runs, and yields,
147	 * next runs, yields, ...
148	 *
149	 * So the master should get through this first.
150	 */
151
152	if (sched_yield() == -1)
153		err(errno, "sched_yield");
154
155	if (master) {
156		int status;
157
158		/* The final slave process should be the last one started.
159		 */
160		if (*p != nslaves) {
161			fprintf(stderr,
162			"Error at line %d: Final slave is %d not %d.\n",
163			__LINE__, *p, nslaves);
164			exit(-1);
165		}
166
167		/* Wait for our youngest to exit:
168		 */
169		waitpid(youngest, &status, 0);
170
171		exit(WEXITSTATUS(status));	/* Let the slaves continue */
172	}
173
174	/* Now the first one has started up.
175	 */
176	for (i = 0; i < nloops; i++) {
177		if (((*p) % nslaves) !=
178		((slave + nslaves - 1) % nslaves)) {
179			fprintf(stderr, "%d ran before %d on iteration %d.\n",
180			*p, slave, i);
181			exit(-1);
182		}
183		*p = slave;
184
185		/* Delay some random amount of time.
186		 */
187		buzz(slave);
188
189		if (sched_yield() == -1)
190			err(errno, "sched_yield");
191	}
192
193	exit(0);
194}
195#ifdef STANDALONE_TESTS
196int main(int argc, char *argv[]) { return yield(argc, argv); }
197#endif
198