xref: /freebsd/tools/regression/p1003_1b/fifo.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1*df57947fSPedro F. Giffuni /*-
2*df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3*df57947fSPedro F. Giffuni  *
4e5f1b1b1SPeter Dufault  * Copyright (c) 1996 - 2000
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 #include <sys/types.h>
35e5f1b1b1SPeter Dufault #include <sys/mman.h>
36e5f1b1b1SPeter Dufault #include <sys/time.h>
37a39b8b86SEnji Cooper #include <err.h>
38a39b8b86SEnji Cooper #include <errno.h>
39a39b8b86SEnji Cooper #include <fcntl.h>
40e5f1b1b1SPeter Dufault #include <sched.h>
41e5f1b1b1SPeter Dufault #include <signal.h>
42a39b8b86SEnji Cooper #include <stdlib.h>
43a39b8b86SEnji Cooper #include <stdio.h>
44a39b8b86SEnji Cooper #include <unistd.h>
45e5f1b1b1SPeter Dufault 
46e5f1b1b1SPeter Dufault volatile int ticked;
47e5f1b1b1SPeter Dufault #define CAN_USE_ALARMS
48e5f1b1b1SPeter Dufault 
49e5f1b1b1SPeter Dufault #ifdef CAN_USE_ALARMS
tick(int arg)50e5f1b1b1SPeter Dufault void tick(int arg)
51e5f1b1b1SPeter Dufault {
52e5f1b1b1SPeter Dufault 	ticked = 1;
53e5f1b1b1SPeter Dufault }
54e5f1b1b1SPeter Dufault #endif
55e5f1b1b1SPeter Dufault 
56e5f1b1b1SPeter Dufault /* Fifo: Verify that fifo and round-robin scheduling seem to work.
57e5f1b1b1SPeter Dufault  *
58e5f1b1b1SPeter Dufault  * This tests:
59e5f1b1b1SPeter Dufault  * 1. That sched_rr_get_interval seems to work;
60e5f1b1b1SPeter Dufault  * 2. That FIFO scheduling doesn't seeem to be round-robin;
61e5f1b1b1SPeter Dufault  * 3. That round-robin scheduling seems to work.
62e5f1b1b1SPeter Dufault  *
63e5f1b1b1SPeter Dufault  */
64e5f1b1b1SPeter Dufault static pid_t child;
tidyup(void)65e5f1b1b1SPeter Dufault static void tidyup(void)
66e5f1b1b1SPeter Dufault {
67e5f1b1b1SPeter Dufault 	if (child)
68e5f1b1b1SPeter Dufault 		kill(child, SIGHUP);
69e5f1b1b1SPeter Dufault }
70e5f1b1b1SPeter Dufault 
71e5f1b1b1SPeter Dufault static double
tvsub(const struct timeval * a,const struct timeval * b)72e5f1b1b1SPeter Dufault tvsub(const struct timeval *a, const struct timeval *b)
73e5f1b1b1SPeter Dufault {
74e5f1b1b1SPeter Dufault 	long sdiff;
75e5f1b1b1SPeter Dufault 	long udiff;
76e5f1b1b1SPeter Dufault 
77e5f1b1b1SPeter Dufault 	sdiff = a->tv_sec - b->tv_sec;
78e5f1b1b1SPeter Dufault 	udiff = a->tv_usec - b->tv_usec;
79e5f1b1b1SPeter Dufault 
80e5f1b1b1SPeter Dufault 	return (double)(sdiff * 1000000 + udiff) / 1e6;
81e5f1b1b1SPeter Dufault }
82e5f1b1b1SPeter Dufault 
fifo(int argc,char * argv[])83e5f1b1b1SPeter Dufault int fifo(int argc, char *argv[])
84e5f1b1b1SPeter Dufault {
85e5f1b1b1SPeter Dufault 	int e = 0;
86e5f1b1b1SPeter Dufault 	volatile long *p, pid;
87e5f1b1b1SPeter Dufault 	int i;
88e5f1b1b1SPeter Dufault 	struct sched_param fifo_param;
89e5f1b1b1SPeter Dufault 	struct timespec interval;
90e5f1b1b1SPeter Dufault #define MAX_RANAT 32
91e5f1b1b1SPeter Dufault 	struct timeval ranat[MAX_RANAT];
92e5f1b1b1SPeter Dufault 
93e5f1b1b1SPeter Dufault #ifdef CAN_USE_ALARMS
94e5f1b1b1SPeter Dufault 	static struct itimerval itimerval;
95e5f1b1b1SPeter Dufault #endif
96e5f1b1b1SPeter Dufault 
97e5f1b1b1SPeter Dufault 	/* What is the round robin interval?
98e5f1b1b1SPeter Dufault 	 */
99e5f1b1b1SPeter Dufault 
100e5f1b1b1SPeter Dufault 	if (sched_rr_get_interval(0, &interval) == -1) {
101e5f1b1b1SPeter Dufault 		perror("sched_rr_get_interval");
102e5f1b1b1SPeter Dufault 		exit(errno);
103e5f1b1b1SPeter Dufault 	}
104e5f1b1b1SPeter Dufault 
105e5f1b1b1SPeter Dufault #ifdef CAN_USE_ALARMS
106e5f1b1b1SPeter Dufault 	signal(SIGALRM, tick);
107e5f1b1b1SPeter Dufault #endif
108e5f1b1b1SPeter Dufault 
109e5f1b1b1SPeter Dufault 	fifo_param.sched_priority = 1;
110e5f1b1b1SPeter Dufault 
111e5f1b1b1SPeter Dufault 	p = (long *)mmap(0, sizeof(*p),
112a39b8b86SEnji Cooper 	PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
113e5f1b1b1SPeter Dufault 
114e5f1b1b1SPeter Dufault 	if (p == (long *)-1)
115e5f1b1b1SPeter Dufault 		err(errno, "mmap");
116e5f1b1b1SPeter Dufault 
117e5f1b1b1SPeter Dufault 	*p = 0;
118e5f1b1b1SPeter Dufault 
119e5f1b1b1SPeter Dufault 	if (sched_setscheduler(0, SCHED_FIFO, &fifo_param) == -1)
120e5f1b1b1SPeter Dufault 	{
121e5f1b1b1SPeter Dufault 		perror("sched_setscheduler");
122e5f1b1b1SPeter Dufault 		return -1;
123e5f1b1b1SPeter Dufault 	}
124e5f1b1b1SPeter Dufault 
125e5f1b1b1SPeter Dufault 	pid = getpid();
126e5f1b1b1SPeter Dufault 
127e5f1b1b1SPeter Dufault 	if ((child = fork()) == 0)
128e5f1b1b1SPeter Dufault 	{
129e5f1b1b1SPeter Dufault 		/* Child process.  Just keep setting the pointer to our
130e5f1b1b1SPeter Dufault 		 * PID.  The parent will kill us when it wants to.
131e5f1b1b1SPeter Dufault 		 */
132e5f1b1b1SPeter Dufault 
133e5f1b1b1SPeter Dufault 		pid = getpid();
134e5f1b1b1SPeter Dufault 		while (1)
135e5f1b1b1SPeter Dufault 			*p = pid;
136e5f1b1b1SPeter Dufault 	}
137e5f1b1b1SPeter Dufault 	else
138e5f1b1b1SPeter Dufault 	{
139e5f1b1b1SPeter Dufault 		atexit(tidyup);
140e5f1b1b1SPeter Dufault 		*p = pid;
141e5f1b1b1SPeter Dufault 
142e5f1b1b1SPeter Dufault 
143e5f1b1b1SPeter Dufault 		ticked = 0;
144e5f1b1b1SPeter Dufault 
145e5f1b1b1SPeter Dufault #ifdef CAN_USE_ALARMS
146e5f1b1b1SPeter Dufault 		/* Set an alarm for 250 times the round-robin interval.
147e5f1b1b1SPeter Dufault 		 * Then we will verify that a similar priority process
148e5f1b1b1SPeter Dufault 		 * will not run when we are using the FIFO scheduler.
149e5f1b1b1SPeter Dufault 		 */
150e5f1b1b1SPeter Dufault 		itimerval.it_value.tv_usec = interval.tv_nsec / (1000 / 250);
151e5f1b1b1SPeter Dufault 
152e5f1b1b1SPeter Dufault 		itimerval.it_value.tv_sec = itimerval.it_value.tv_usec / 1000000;
153e5f1b1b1SPeter Dufault 		itimerval.it_value.tv_usec %= 1000000;
154e5f1b1b1SPeter Dufault 
155e5f1b1b1SPeter Dufault 
156e5f1b1b1SPeter Dufault 		if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) {
157e5f1b1b1SPeter Dufault 			perror("setitimer");
158e5f1b1b1SPeter Dufault 			exit(errno);
159e5f1b1b1SPeter Dufault 		}
160e5f1b1b1SPeter Dufault #endif
161e5f1b1b1SPeter Dufault 
162e5f1b1b1SPeter Dufault 
163e5f1b1b1SPeter Dufault 		gettimeofday(ranat, 0);
164e5f1b1b1SPeter Dufault 		i = 1;
165e5f1b1b1SPeter Dufault 		while (!ticked && i < MAX_RANAT)
166e5f1b1b1SPeter Dufault 			if (*p == child) {
167e5f1b1b1SPeter Dufault 				gettimeofday(ranat + i, 0);
168e5f1b1b1SPeter Dufault 				*p = 0;
169e5f1b1b1SPeter Dufault 				e = -1;
170e5f1b1b1SPeter Dufault 				i++;
171e5f1b1b1SPeter Dufault 			}
172e5f1b1b1SPeter Dufault 
173e5f1b1b1SPeter Dufault 		if (e) {
174e5f1b1b1SPeter Dufault 			int j;
175e5f1b1b1SPeter Dufault 
176e5f1b1b1SPeter Dufault 			fprintf(stderr,
177e5f1b1b1SPeter Dufault 			"SCHED_FIFO had erroneous context switches:\n");
178e5f1b1b1SPeter Dufault 			for (j = 1; j < i; j++) {
179e5f1b1b1SPeter Dufault 				fprintf(stderr, "%d %g\n", j,
180e5f1b1b1SPeter Dufault 					tvsub(ranat + j, ranat + j - 1));
181e5f1b1b1SPeter Dufault 			}
182e5f1b1b1SPeter Dufault 			return e;
183e5f1b1b1SPeter Dufault 		}
184e5f1b1b1SPeter Dufault 
185e5f1b1b1SPeter Dufault 		/* Switch to the round robin scheduler and the child
186e5f1b1b1SPeter Dufault 		 * should run within twice the interval.
187e5f1b1b1SPeter Dufault 		 */
188e5f1b1b1SPeter Dufault 		if (sched_setscheduler(child, SCHED_RR, &fifo_param) == -1 ||
189e5f1b1b1SPeter Dufault 		sched_setscheduler(0, SCHED_RR, &fifo_param) == -1)
190e5f1b1b1SPeter Dufault 		{
191e5f1b1b1SPeter Dufault 			perror("sched_setscheduler");
192e5f1b1b1SPeter Dufault 			return -1;
193e5f1b1b1SPeter Dufault 		}
194e5f1b1b1SPeter Dufault 
195e5f1b1b1SPeter Dufault 		e = -1;
196e5f1b1b1SPeter Dufault 
197e5f1b1b1SPeter Dufault 		ticked = 0;
198e5f1b1b1SPeter Dufault 
199e5f1b1b1SPeter Dufault #ifdef CAN_USE_ALARMS
200e5f1b1b1SPeter Dufault 
201e5f1b1b1SPeter Dufault 		/* Now we do want to see it run.  But only set
202e5f1b1b1SPeter Dufault 		 * the alarm for twice the interval:
203e5f1b1b1SPeter Dufault 		 */
204e5f1b1b1SPeter Dufault 		itimerval.it_value.tv_usec = interval.tv_nsec / 500;
205e5f1b1b1SPeter Dufault 
206e5f1b1b1SPeter Dufault 		if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) {
207e5f1b1b1SPeter Dufault 			perror("setitimer");
208e5f1b1b1SPeter Dufault 			exit(errno);
209e5f1b1b1SPeter Dufault 		}
210e5f1b1b1SPeter Dufault #endif
211e5f1b1b1SPeter Dufault 
212e5f1b1b1SPeter Dufault 		for (i = 0; !ticked; i++)
213e5f1b1b1SPeter Dufault 			if (*p == child) {
214e5f1b1b1SPeter Dufault 				e = 0;
215e5f1b1b1SPeter Dufault 				break;
216e5f1b1b1SPeter Dufault 			}
217e5f1b1b1SPeter Dufault 
218e5f1b1b1SPeter Dufault 		if (e)
219e5f1b1b1SPeter Dufault 			fprintf(stderr,"Child never ran when it should have.\n");
220e5f1b1b1SPeter Dufault 	}
221e5f1b1b1SPeter Dufault 
222e5f1b1b1SPeter Dufault 	exit(e);
223e5f1b1b1SPeter Dufault }
224e5f1b1b1SPeter Dufault 
225e5f1b1b1SPeter Dufault #ifdef STANDALONE_TESTS
main(int argc,char * argv[])226e5f1b1b1SPeter Dufault int main(int argc, char *argv[]) { return fifo(argc, argv); }
227e5f1b1b1SPeter Dufault #endif
228