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