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 */
buzz(int n)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 */
yield(int argc,char * argv[])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
main(int argc,char * argv[])197 int main(int argc, char *argv[]) { return yield(argc, argv); }
198 #endif
199