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