xref: /freebsd/tools/regression/p1003_1b/yield.c (revision 0b3105a37d7adcadcb720112fed4dc4e8040be99)
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$
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  */
51 static 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  */
63 int 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
196 int main(int argc, char *argv[]) { return yield(argc, argv); }
197 #endif
198