xref: /dragonfly/tools/regression/p1003_1b/fifo.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * Copyright (c) 1996 - 2000
3*86d7f5d3SJohn Marino  *	HD Associates, Inc.  All rights reserved.
4*86d7f5d3SJohn Marino  *
5*86d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
6*86d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
7*86d7f5d3SJohn Marino  * are met:
8*86d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
9*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
10*86d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
11*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
12*86d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
13*86d7f5d3SJohn Marino  * 3. All advertising materials mentioning features or use of this software
14*86d7f5d3SJohn Marino  *    must display the following acknowledgement:
15*86d7f5d3SJohn Marino  *	This product includes software developed by HD Associates, Inc
16*86d7f5d3SJohn Marino  * 4. Neither the name of the author nor the names of any co-contributors
17*86d7f5d3SJohn Marino  *    may be used to endorse or promote products derived from this software
18*86d7f5d3SJohn Marino  *    without specific prior written permission.
19*86d7f5d3SJohn Marino  *
20*86d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
21*86d7f5d3SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22*86d7f5d3SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23*86d7f5d3SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
24*86d7f5d3SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25*86d7f5d3SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26*86d7f5d3SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*86d7f5d3SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28*86d7f5d3SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29*86d7f5d3SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30*86d7f5d3SJohn Marino  * SUCH DAMAGE.
31*86d7f5d3SJohn Marino  *
32*86d7f5d3SJohn Marino  * $FreeBSD: src/tools/regression/p1003_1b/fifo.c,v 1.1 2000/02/16 14:28:40 dufault Exp $
33*86d7f5d3SJohn Marino  * $DragonFly: src/tools/regression/p1003_1b/fifo.c,v 1.3 2007/06/26 23:30:05 josepht Exp $
34*86d7f5d3SJohn Marino  */
35*86d7f5d3SJohn Marino #include <unistd.h>
36*86d7f5d3SJohn Marino #include <stdlib.h>
37*86d7f5d3SJohn Marino #include <stdio.h>
38*86d7f5d3SJohn Marino #include <errno.h>
39*86d7f5d3SJohn Marino #include <err.h>
40*86d7f5d3SJohn Marino #include <fcntl.h>
41*86d7f5d3SJohn Marino #include <sys/types.h>
42*86d7f5d3SJohn Marino #include <sys/mman.h>
43*86d7f5d3SJohn Marino #include <sys/time.h>
44*86d7f5d3SJohn Marino #include <sys/sched.h>
45*86d7f5d3SJohn Marino #include <signal.h>
46*86d7f5d3SJohn Marino 
47*86d7f5d3SJohn Marino volatile int ticked;
48*86d7f5d3SJohn Marino #define CAN_USE_ALARMS
49*86d7f5d3SJohn Marino 
50*86d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
tick(int arg)51*86d7f5d3SJohn Marino void tick(int arg)
52*86d7f5d3SJohn Marino {
53*86d7f5d3SJohn Marino 	ticked = 1;
54*86d7f5d3SJohn Marino }
55*86d7f5d3SJohn Marino #endif
56*86d7f5d3SJohn Marino 
57*86d7f5d3SJohn Marino /* Fifo: Verify that fifo and round-robin scheduling seem to work.
58*86d7f5d3SJohn Marino  *
59*86d7f5d3SJohn Marino  * This tests:
60*86d7f5d3SJohn Marino  * 1. That sched_rr_get_interval seems to work;
61*86d7f5d3SJohn Marino  * 2. That FIFO scheduling doesn't seeem to be round-robin;
62*86d7f5d3SJohn Marino  * 3. That round-robin scheduling seems to work.
63*86d7f5d3SJohn Marino  *
64*86d7f5d3SJohn Marino  */
65*86d7f5d3SJohn Marino static pid_t child;
tidyup(void)66*86d7f5d3SJohn Marino static void tidyup(void)
67*86d7f5d3SJohn Marino {
68*86d7f5d3SJohn Marino 	if (child)
69*86d7f5d3SJohn Marino 		kill(child, SIGHUP);
70*86d7f5d3SJohn Marino }
71*86d7f5d3SJohn Marino 
72*86d7f5d3SJohn Marino static double
tvsub(const struct timeval * a,const struct timeval * b)73*86d7f5d3SJohn Marino tvsub(const struct timeval *a, const struct timeval *b)
74*86d7f5d3SJohn Marino {
75*86d7f5d3SJohn Marino 	long sdiff;
76*86d7f5d3SJohn Marino 	long udiff;
77*86d7f5d3SJohn Marino 
78*86d7f5d3SJohn Marino 	sdiff = a->tv_sec - b->tv_sec;
79*86d7f5d3SJohn Marino 	udiff = a->tv_usec - b->tv_usec;
80*86d7f5d3SJohn Marino 
81*86d7f5d3SJohn Marino 	return (double)(sdiff * 1000000 + udiff) / 1e6;
82*86d7f5d3SJohn Marino }
83*86d7f5d3SJohn Marino 
fifo(int argc,char * argv[])84*86d7f5d3SJohn Marino int fifo(int argc, char *argv[])
85*86d7f5d3SJohn Marino {
86*86d7f5d3SJohn Marino 	int e = 0;
87*86d7f5d3SJohn Marino 	volatile long *p, pid;
88*86d7f5d3SJohn Marino 	int i;
89*86d7f5d3SJohn Marino 	struct sched_param fifo_param;
90*86d7f5d3SJohn Marino 	struct timespec interval;
91*86d7f5d3SJohn Marino #define MAX_RANAT 32
92*86d7f5d3SJohn Marino 	struct timeval ranat[MAX_RANAT];
93*86d7f5d3SJohn Marino 
94*86d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
95*86d7f5d3SJohn Marino 	static struct itimerval itimerval;
96*86d7f5d3SJohn Marino #endif
97*86d7f5d3SJohn Marino 
98*86d7f5d3SJohn Marino 	/* What is the round robin interval?
99*86d7f5d3SJohn Marino 	 */
100*86d7f5d3SJohn Marino 
101*86d7f5d3SJohn Marino 	if (sched_rr_get_interval(0, &interval) == -1) {
102*86d7f5d3SJohn Marino 		perror("sched_rr_get_interval");
103*86d7f5d3SJohn Marino 		exit(errno);
104*86d7f5d3SJohn Marino 	}
105*86d7f5d3SJohn Marino 
106*86d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
107*86d7f5d3SJohn Marino 	signal(SIGALRM, tick);
108*86d7f5d3SJohn Marino #endif
109*86d7f5d3SJohn Marino 
110*86d7f5d3SJohn Marino 	fifo_param.sched_priority = 1;
111*86d7f5d3SJohn Marino 
112*86d7f5d3SJohn Marino 	p = (long *)mmap(0, sizeof(*p),
113*86d7f5d3SJohn Marino 	PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED|MAP_INHERIT, -1, 0);
114*86d7f5d3SJohn Marino 
115*86d7f5d3SJohn Marino 	if (p == (long *)-1)
116*86d7f5d3SJohn Marino 		err(errno, "mmap");
117*86d7f5d3SJohn Marino 
118*86d7f5d3SJohn Marino 	*p = 0;
119*86d7f5d3SJohn Marino 
120*86d7f5d3SJohn Marino 	if (sched_setscheduler(0, SCHED_FIFO, &fifo_param) == -1)
121*86d7f5d3SJohn Marino 	{
122*86d7f5d3SJohn Marino 		perror("sched_setscheduler");
123*86d7f5d3SJohn Marino 		return -1;
124*86d7f5d3SJohn Marino 	}
125*86d7f5d3SJohn Marino 
126*86d7f5d3SJohn Marino 	pid = getpid();
127*86d7f5d3SJohn Marino 
128*86d7f5d3SJohn Marino 	if ((child = fork()) == 0)
129*86d7f5d3SJohn Marino 	{
130*86d7f5d3SJohn Marino 		/* Child process.  Just keep setting the pointer to our
131*86d7f5d3SJohn Marino 		 * PID.  The parent will kill us when it wants to.
132*86d7f5d3SJohn Marino 		 */
133*86d7f5d3SJohn Marino 
134*86d7f5d3SJohn Marino 		pid = getpid();
135*86d7f5d3SJohn Marino 		while (1)
136*86d7f5d3SJohn Marino 			*p = pid;
137*86d7f5d3SJohn Marino 	}
138*86d7f5d3SJohn Marino 	else
139*86d7f5d3SJohn Marino 	{
140*86d7f5d3SJohn Marino 		atexit(tidyup);
141*86d7f5d3SJohn Marino 		*p = pid;
142*86d7f5d3SJohn Marino 
143*86d7f5d3SJohn Marino 
144*86d7f5d3SJohn Marino 		ticked = 0;
145*86d7f5d3SJohn Marino 
146*86d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
147*86d7f5d3SJohn Marino 		/* Set an alarm for 250 times the round-robin interval.
148*86d7f5d3SJohn Marino 		 * Then we will verify that a similar priority process
149*86d7f5d3SJohn Marino 		 * will not run when we are using the FIFO scheduler.
150*86d7f5d3SJohn Marino 		 */
151*86d7f5d3SJohn Marino 		itimerval.it_value.tv_usec = interval.tv_nsec / (1000 / 250);
152*86d7f5d3SJohn Marino 
153*86d7f5d3SJohn Marino 		itimerval.it_value.tv_sec = itimerval.it_value.tv_usec / 1000000;
154*86d7f5d3SJohn Marino 		itimerval.it_value.tv_usec %= 1000000;
155*86d7f5d3SJohn Marino 
156*86d7f5d3SJohn Marino 
157*86d7f5d3SJohn Marino 		if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) {
158*86d7f5d3SJohn Marino 			perror("setitimer");
159*86d7f5d3SJohn Marino 			exit(errno);
160*86d7f5d3SJohn Marino 		}
161*86d7f5d3SJohn Marino #endif
162*86d7f5d3SJohn Marino 
163*86d7f5d3SJohn Marino 
164*86d7f5d3SJohn Marino 		gettimeofday(ranat, 0);
165*86d7f5d3SJohn Marino 		i = 1;
166*86d7f5d3SJohn Marino 		while (!ticked && i < MAX_RANAT)
167*86d7f5d3SJohn Marino 			if (*p == child) {
168*86d7f5d3SJohn Marino 				gettimeofday(ranat + i, 0);
169*86d7f5d3SJohn Marino 				*p = 0;
170*86d7f5d3SJohn Marino 				e = -1;
171*86d7f5d3SJohn Marino 				i++;
172*86d7f5d3SJohn Marino 			}
173*86d7f5d3SJohn Marino 
174*86d7f5d3SJohn Marino 		if (e) {
175*86d7f5d3SJohn Marino 			int j;
176*86d7f5d3SJohn Marino 
177*86d7f5d3SJohn Marino 			fprintf(stderr,
178*86d7f5d3SJohn Marino 			"SCHED_FIFO had erroneous context switches:\n");
179*86d7f5d3SJohn Marino 			for (j = 1; j < i; j++) {
180*86d7f5d3SJohn Marino 				fprintf(stderr, "%d %g\n", j,
181*86d7f5d3SJohn Marino 					tvsub(ranat + j, ranat + j - 1));
182*86d7f5d3SJohn Marino 			}
183*86d7f5d3SJohn Marino 			return e;
184*86d7f5d3SJohn Marino 		}
185*86d7f5d3SJohn Marino 
186*86d7f5d3SJohn Marino 		/* Switch to the round robin scheduler and the child
187*86d7f5d3SJohn Marino 		 * should run within twice the interval.
188*86d7f5d3SJohn Marino 		 */
189*86d7f5d3SJohn Marino 		if (sched_setscheduler(child, SCHED_RR, &fifo_param) == -1 ||
190*86d7f5d3SJohn Marino 		sched_setscheduler(0, SCHED_RR, &fifo_param) == -1)
191*86d7f5d3SJohn Marino 		{
192*86d7f5d3SJohn Marino 			perror("sched_setscheduler");
193*86d7f5d3SJohn Marino 			return -1;
194*86d7f5d3SJohn Marino 		}
195*86d7f5d3SJohn Marino 
196*86d7f5d3SJohn Marino 		e = -1;
197*86d7f5d3SJohn Marino 
198*86d7f5d3SJohn Marino 		ticked = 0;
199*86d7f5d3SJohn Marino 
200*86d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
201*86d7f5d3SJohn Marino 
202*86d7f5d3SJohn Marino 		/* Now we do want to see it run.  But only set
203*86d7f5d3SJohn Marino 		 * the alarm for twice the interval:
204*86d7f5d3SJohn Marino 		 */
205*86d7f5d3SJohn Marino 		itimerval.it_value.tv_usec = interval.tv_nsec / 500;
206*86d7f5d3SJohn Marino 
207*86d7f5d3SJohn Marino 		if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) {
208*86d7f5d3SJohn Marino 			perror("setitimer");
209*86d7f5d3SJohn Marino 			exit(errno);
210*86d7f5d3SJohn Marino 		}
211*86d7f5d3SJohn Marino #endif
212*86d7f5d3SJohn Marino 
213*86d7f5d3SJohn Marino 		for (i = 0; !ticked; i++)
214*86d7f5d3SJohn Marino 			if (*p == child) {
215*86d7f5d3SJohn Marino 				e = 0;
216*86d7f5d3SJohn Marino 				break;
217*86d7f5d3SJohn Marino 			}
218*86d7f5d3SJohn Marino 
219*86d7f5d3SJohn Marino 		if (e)
220*86d7f5d3SJohn Marino 			fprintf(stderr,"Child never ran when it should have.\n");
221*86d7f5d3SJohn Marino 	}
222*86d7f5d3SJohn Marino 
223*86d7f5d3SJohn Marino 	exit(e);
224*86d7f5d3SJohn Marino }
225*86d7f5d3SJohn Marino 
226*86d7f5d3SJohn Marino #ifdef STANDALONE_TESTS
main(int argc,char * argv[])227*86d7f5d3SJohn Marino int main(int argc, char *argv[]) { return fifo(argc, argv); }
228*86d7f5d3SJohn Marino #endif
229