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