1210284Sjmallett/*-
2232812Sjmallett * SPDX-License-Identifier: BSD-4-Clause
3215990Sjmallett *
4210284Sjmallett * Copyright (c) 1996-1999
5210284Sjmallett *	HD Associates, Inc.  All rights reserved.
6215990Sjmallett *
7215990Sjmallett * Redistribution and use in source and binary forms, with or without
8215990Sjmallett * modification, are permitted provided that the following conditions
9210284Sjmallett * are met:
10215990Sjmallett * 1. Redistributions of source code must retain the above copyright
11215990Sjmallett *    notice, this list of conditions and the following disclaimer.
12210284Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
13215990Sjmallett *    notice, this list of conditions and the following disclaimer in the
14215990Sjmallett *    documentation and/or other materials provided with the distribution.
15215990Sjmallett * 3. All advertising materials mentioning features or use of this software
16215990Sjmallett *    must display the following acknowledgement:
17215990Sjmallett *	This product includes software developed by HD Associates, Inc
18232812Sjmallett * 4. Neither the name of the author nor the names of any co-contributors
19215990Sjmallett *    may be used to endorse or promote products derived from this software
20215990Sjmallett *    without specific prior written permission.
21215990Sjmallett *
22215990Sjmallett * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
23215990Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24215990Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25215990Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
26215990Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27215990Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28215990Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29232812Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30215990Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31215990Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32215990Sjmallett * SUCH DAMAGE.
33215990Sjmallett *
34215990Sjmallett */
35215990Sjmallett#include <sys/types.h>
36215990Sjmallett#include <unistd.h>
37215990Sjmallett#include <stdlib.h>
38210284Sjmallett#include <stdio.h>
39210284Sjmallett#include <errno.h>
40210284Sjmallett#include <err.h>
41210284Sjmallett#include <fcntl.h>
42210284Sjmallett#include <sys/types.h>
43210284Sjmallett#include <sys/mman.h>
44210284Sjmallett#include <sched.h>
45215990Sjmallett#include <stdlib.h>
46210284Sjmallett#include <sys/wait.h>
47210284Sjmallett
48210284Sjmallett#include "prutil.h"
49210284Sjmallett
50210284Sjmallett/* buzz: busy wait a random amount of time.
51210284Sjmallett */
52210284Sjmallettstatic void buzz(int n)
53210284Sjmallett{
54232812Sjmallett	volatile int i;
55210284Sjmallett	int m = random() & 0x0ffff;
56210284Sjmallett	for (i = 0; i < m; i++)
57210284Sjmallett		;
58210284Sjmallett}
59210284Sjmallett
60210284Sjmallett/* Yield: Verify that "sched_yield" works for the FIFO case.
61210284Sjmallett * This runs several processes and verifies that the yield seems
62210284Sjmallett * to permit the next one on the ready queue to run.
63210284Sjmallett */
64210284Sjmallettint yield(int argc, char *argv[])
65210284Sjmallett{
66210284Sjmallett	volatile int *p;
67210284Sjmallett	int i;
68210284Sjmallett	int nslaves, n;
69210284Sjmallett	int master, slave;
70210284Sjmallett	pid_t youngest = !0;	/* Our youngest child */
71210284Sjmallett	struct sched_param set, got;
72210284Sjmallett	int nloops = 1000;
73210284Sjmallett
74210284Sjmallett	errno = 0;
75210284Sjmallett
76210284Sjmallett	set.sched_priority = sched_get_priority_max(SCHED_FIFO);
77210284Sjmallett	if (set.sched_priority == -1 && errno) {
78210284Sjmallett		perror("sched_get_priority_max");
79210284Sjmallett		exit(errno);
80210284Sjmallett	}
81210284Sjmallett
82210284Sjmallett	if (argc == 1)
83210284Sjmallett		n = nslaves = 10;
84210284Sjmallett
85210284Sjmallett	else if (argc != 2) {
86210284Sjmallett		fprintf(stderr, "usage: prog [n_instances]\n");
87210284Sjmallett		exit(-1);
88210284Sjmallett	}
89210284Sjmallett	else
90210284Sjmallett		n = nslaves = atoi(argv[1]);
91210284Sjmallett
92210284Sjmallett	p = (int *)mmap(0, sizeof(int),
93210284Sjmallett	PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
94210284Sjmallett
95210284Sjmallett	if (p == (int *)-1)
96210284Sjmallett		err(errno, "mmap");
97210284Sjmallett
98210284Sjmallett	*p = 0;
99210284Sjmallett
100210284Sjmallett	if (sched_setscheduler(0, SCHED_FIFO, &set) == -1)
101210284Sjmallett		err(errno, "sched_setscheduler");
102210284Sjmallett
103210284Sjmallett	/* I better still be SCHED_FIFO and RT_PRIO_MAX:
104210284Sjmallett	 */
105210284Sjmallett	(void)sched_is(__LINE__, &got, SCHED_FIFO);
106210284Sjmallett	if (got.sched_priority != set.sched_priority) {
107210284Sjmallett		fprintf(stderr, "line %d: scheduler screwup\n",
108210284Sjmallett		__LINE__);
109210284Sjmallett		exit(-1);
110210284Sjmallett	}
111210284Sjmallett
112210284Sjmallett	slave = 0;
113210284Sjmallett	master = 1;
114210284Sjmallett
115210284Sjmallett	/* Fork off the slaves.
116210284Sjmallett	 */
117210284Sjmallett	for (i = 0; i < nslaves; i++) {
118210284Sjmallett		if ((youngest = fork()) == 0) {
119210284Sjmallett			/* I better still be SCHED_FIFO and RT_PRIO_MAX:
120210284Sjmallett			 */
121210284Sjmallett			(void)sched_is(__LINE__, &got, SCHED_FIFO);
122210284Sjmallett
123210284Sjmallett			if (got.sched_priority != set.sched_priority) {
124210284Sjmallett				fprintf(stderr, "line %d: scheduler screwup\n",
125210284Sjmallett				__LINE__);
126210284Sjmallett				exit(-1);
127210284Sjmallett			}
128210284Sjmallett
129210284Sjmallett			master = 0;	/* I'm a slave */
130210284Sjmallett			slave = i + 1;	/* With this flag */
131210284Sjmallett			*p = slave;	/* And I live */
132210284Sjmallett			break;
133210284Sjmallett		}
134210284Sjmallett	}
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
197int main(int argc, char *argv[]) { return yield(argc, argv); }
198#endif
199