xref: /dflybsd-src/tools/regression/p1003_1b/fifo.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
186d7f5d3SJohn Marino /*
286d7f5d3SJohn Marino  * Copyright (c) 1996 - 2000
386d7f5d3SJohn Marino  *	HD Associates, Inc.  All rights reserved.
486d7f5d3SJohn Marino  *
586d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
686d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
786d7f5d3SJohn Marino  * are met:
886d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
986d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
1086d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
1186d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
1286d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
1386d7f5d3SJohn Marino  * 3. All advertising materials mentioning features or use of this software
1486d7f5d3SJohn Marino  *    must display the following acknowledgement:
1586d7f5d3SJohn Marino  *	This product includes software developed by HD Associates, Inc
1686d7f5d3SJohn Marino  * 4. Neither the name of the author nor the names of any co-contributors
1786d7f5d3SJohn Marino  *    may be used to endorse or promote products derived from this software
1886d7f5d3SJohn Marino  *    without specific prior written permission.
1986d7f5d3SJohn Marino  *
2086d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
2186d7f5d3SJohn Marino  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2286d7f5d3SJohn Marino  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2386d7f5d3SJohn Marino  * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
2486d7f5d3SJohn Marino  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2586d7f5d3SJohn Marino  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2686d7f5d3SJohn Marino  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2786d7f5d3SJohn Marino  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2886d7f5d3SJohn Marino  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2986d7f5d3SJohn Marino  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3086d7f5d3SJohn Marino  * SUCH DAMAGE.
3186d7f5d3SJohn Marino  *
3286d7f5d3SJohn Marino  * $FreeBSD: src/tools/regression/p1003_1b/fifo.c,v 1.1 2000/02/16 14:28:40 dufault Exp $
3386d7f5d3SJohn Marino  * $DragonFly: src/tools/regression/p1003_1b/fifo.c,v 1.3 2007/06/26 23:30:05 josepht Exp $
3486d7f5d3SJohn Marino  */
3586d7f5d3SJohn Marino #include <unistd.h>
3686d7f5d3SJohn Marino #include <stdlib.h>
3786d7f5d3SJohn Marino #include <stdio.h>
3886d7f5d3SJohn Marino #include <errno.h>
3986d7f5d3SJohn Marino #include <err.h>
4086d7f5d3SJohn Marino #include <fcntl.h>
4186d7f5d3SJohn Marino #include <sys/types.h>
4286d7f5d3SJohn Marino #include <sys/mman.h>
4386d7f5d3SJohn Marino #include <sys/time.h>
4486d7f5d3SJohn Marino #include <sys/sched.h>
4586d7f5d3SJohn Marino #include <signal.h>
4686d7f5d3SJohn Marino 
4786d7f5d3SJohn Marino volatile int ticked;
4886d7f5d3SJohn Marino #define CAN_USE_ALARMS
4986d7f5d3SJohn Marino 
5086d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
tick(int arg)5186d7f5d3SJohn Marino void tick(int arg)
5286d7f5d3SJohn Marino {
5386d7f5d3SJohn Marino 	ticked = 1;
5486d7f5d3SJohn Marino }
5586d7f5d3SJohn Marino #endif
5686d7f5d3SJohn Marino 
5786d7f5d3SJohn Marino /* Fifo: Verify that fifo and round-robin scheduling seem to work.
5886d7f5d3SJohn Marino  *
5986d7f5d3SJohn Marino  * This tests:
6086d7f5d3SJohn Marino  * 1. That sched_rr_get_interval seems to work;
6186d7f5d3SJohn Marino  * 2. That FIFO scheduling doesn't seeem to be round-robin;
6286d7f5d3SJohn Marino  * 3. That round-robin scheduling seems to work.
6386d7f5d3SJohn Marino  *
6486d7f5d3SJohn Marino  */
6586d7f5d3SJohn Marino static pid_t child;
tidyup(void)6686d7f5d3SJohn Marino static void tidyup(void)
6786d7f5d3SJohn Marino {
6886d7f5d3SJohn Marino 	if (child)
6986d7f5d3SJohn Marino 		kill(child, SIGHUP);
7086d7f5d3SJohn Marino }
7186d7f5d3SJohn Marino 
7286d7f5d3SJohn Marino static double
tvsub(const struct timeval * a,const struct timeval * b)7386d7f5d3SJohn Marino tvsub(const struct timeval *a, const struct timeval *b)
7486d7f5d3SJohn Marino {
7586d7f5d3SJohn Marino 	long sdiff;
7686d7f5d3SJohn Marino 	long udiff;
7786d7f5d3SJohn Marino 
7886d7f5d3SJohn Marino 	sdiff = a->tv_sec - b->tv_sec;
7986d7f5d3SJohn Marino 	udiff = a->tv_usec - b->tv_usec;
8086d7f5d3SJohn Marino 
8186d7f5d3SJohn Marino 	return (double)(sdiff * 1000000 + udiff) / 1e6;
8286d7f5d3SJohn Marino }
8386d7f5d3SJohn Marino 
fifo(int argc,char * argv[])8486d7f5d3SJohn Marino int fifo(int argc, char *argv[])
8586d7f5d3SJohn Marino {
8686d7f5d3SJohn Marino 	int e = 0;
8786d7f5d3SJohn Marino 	volatile long *p, pid;
8886d7f5d3SJohn Marino 	int i;
8986d7f5d3SJohn Marino 	struct sched_param fifo_param;
9086d7f5d3SJohn Marino 	struct timespec interval;
9186d7f5d3SJohn Marino #define MAX_RANAT 32
9286d7f5d3SJohn Marino 	struct timeval ranat[MAX_RANAT];
9386d7f5d3SJohn Marino 
9486d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
9586d7f5d3SJohn Marino 	static struct itimerval itimerval;
9686d7f5d3SJohn Marino #endif
9786d7f5d3SJohn Marino 
9886d7f5d3SJohn Marino 	/* What is the round robin interval?
9986d7f5d3SJohn Marino 	 */
10086d7f5d3SJohn Marino 
10186d7f5d3SJohn Marino 	if (sched_rr_get_interval(0, &interval) == -1) {
10286d7f5d3SJohn Marino 		perror("sched_rr_get_interval");
10386d7f5d3SJohn Marino 		exit(errno);
10486d7f5d3SJohn Marino 	}
10586d7f5d3SJohn Marino 
10686d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
10786d7f5d3SJohn Marino 	signal(SIGALRM, tick);
10886d7f5d3SJohn Marino #endif
10986d7f5d3SJohn Marino 
11086d7f5d3SJohn Marino 	fifo_param.sched_priority = 1;
11186d7f5d3SJohn Marino 
11286d7f5d3SJohn Marino 	p = (long *)mmap(0, sizeof(*p),
11386d7f5d3SJohn Marino 	PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED|MAP_INHERIT, -1, 0);
11486d7f5d3SJohn Marino 
11586d7f5d3SJohn Marino 	if (p == (long *)-1)
11686d7f5d3SJohn Marino 		err(errno, "mmap");
11786d7f5d3SJohn Marino 
11886d7f5d3SJohn Marino 	*p = 0;
11986d7f5d3SJohn Marino 
12086d7f5d3SJohn Marino 	if (sched_setscheduler(0, SCHED_FIFO, &fifo_param) == -1)
12186d7f5d3SJohn Marino 	{
12286d7f5d3SJohn Marino 		perror("sched_setscheduler");
12386d7f5d3SJohn Marino 		return -1;
12486d7f5d3SJohn Marino 	}
12586d7f5d3SJohn Marino 
12686d7f5d3SJohn Marino 	pid = getpid();
12786d7f5d3SJohn Marino 
12886d7f5d3SJohn Marino 	if ((child = fork()) == 0)
12986d7f5d3SJohn Marino 	{
13086d7f5d3SJohn Marino 		/* Child process.  Just keep setting the pointer to our
13186d7f5d3SJohn Marino 		 * PID.  The parent will kill us when it wants to.
13286d7f5d3SJohn Marino 		 */
13386d7f5d3SJohn Marino 
13486d7f5d3SJohn Marino 		pid = getpid();
13586d7f5d3SJohn Marino 		while (1)
13686d7f5d3SJohn Marino 			*p = pid;
13786d7f5d3SJohn Marino 	}
13886d7f5d3SJohn Marino 	else
13986d7f5d3SJohn Marino 	{
14086d7f5d3SJohn Marino 		atexit(tidyup);
14186d7f5d3SJohn Marino 		*p = pid;
14286d7f5d3SJohn Marino 
14386d7f5d3SJohn Marino 
14486d7f5d3SJohn Marino 		ticked = 0;
14586d7f5d3SJohn Marino 
14686d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
14786d7f5d3SJohn Marino 		/* Set an alarm for 250 times the round-robin interval.
14886d7f5d3SJohn Marino 		 * Then we will verify that a similar priority process
14986d7f5d3SJohn Marino 		 * will not run when we are using the FIFO scheduler.
15086d7f5d3SJohn Marino 		 */
15186d7f5d3SJohn Marino 		itimerval.it_value.tv_usec = interval.tv_nsec / (1000 / 250);
15286d7f5d3SJohn Marino 
15386d7f5d3SJohn Marino 		itimerval.it_value.tv_sec = itimerval.it_value.tv_usec / 1000000;
15486d7f5d3SJohn Marino 		itimerval.it_value.tv_usec %= 1000000;
15586d7f5d3SJohn Marino 
15686d7f5d3SJohn Marino 
15786d7f5d3SJohn Marino 		if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) {
15886d7f5d3SJohn Marino 			perror("setitimer");
15986d7f5d3SJohn Marino 			exit(errno);
16086d7f5d3SJohn Marino 		}
16186d7f5d3SJohn Marino #endif
16286d7f5d3SJohn Marino 
16386d7f5d3SJohn Marino 
16486d7f5d3SJohn Marino 		gettimeofday(ranat, 0);
16586d7f5d3SJohn Marino 		i = 1;
16686d7f5d3SJohn Marino 		while (!ticked && i < MAX_RANAT)
16786d7f5d3SJohn Marino 			if (*p == child) {
16886d7f5d3SJohn Marino 				gettimeofday(ranat + i, 0);
16986d7f5d3SJohn Marino 				*p = 0;
17086d7f5d3SJohn Marino 				e = -1;
17186d7f5d3SJohn Marino 				i++;
17286d7f5d3SJohn Marino 			}
17386d7f5d3SJohn Marino 
17486d7f5d3SJohn Marino 		if (e) {
17586d7f5d3SJohn Marino 			int j;
17686d7f5d3SJohn Marino 
17786d7f5d3SJohn Marino 			fprintf(stderr,
17886d7f5d3SJohn Marino 			"SCHED_FIFO had erroneous context switches:\n");
17986d7f5d3SJohn Marino 			for (j = 1; j < i; j++) {
18086d7f5d3SJohn Marino 				fprintf(stderr, "%d %g\n", j,
18186d7f5d3SJohn Marino 					tvsub(ranat + j, ranat + j - 1));
18286d7f5d3SJohn Marino 			}
18386d7f5d3SJohn Marino 			return e;
18486d7f5d3SJohn Marino 		}
18586d7f5d3SJohn Marino 
18686d7f5d3SJohn Marino 		/* Switch to the round robin scheduler and the child
18786d7f5d3SJohn Marino 		 * should run within twice the interval.
18886d7f5d3SJohn Marino 		 */
18986d7f5d3SJohn Marino 		if (sched_setscheduler(child, SCHED_RR, &fifo_param) == -1 ||
19086d7f5d3SJohn Marino 		sched_setscheduler(0, SCHED_RR, &fifo_param) == -1)
19186d7f5d3SJohn Marino 		{
19286d7f5d3SJohn Marino 			perror("sched_setscheduler");
19386d7f5d3SJohn Marino 			return -1;
19486d7f5d3SJohn Marino 		}
19586d7f5d3SJohn Marino 
19686d7f5d3SJohn Marino 		e = -1;
19786d7f5d3SJohn Marino 
19886d7f5d3SJohn Marino 		ticked = 0;
19986d7f5d3SJohn Marino 
20086d7f5d3SJohn Marino #ifdef CAN_USE_ALARMS
20186d7f5d3SJohn Marino 
20286d7f5d3SJohn Marino 		/* Now we do want to see it run.  But only set
20386d7f5d3SJohn Marino 		 * the alarm for twice the interval:
20486d7f5d3SJohn Marino 		 */
20586d7f5d3SJohn Marino 		itimerval.it_value.tv_usec = interval.tv_nsec / 500;
20686d7f5d3SJohn Marino 
20786d7f5d3SJohn Marino 		if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) {
20886d7f5d3SJohn Marino 			perror("setitimer");
20986d7f5d3SJohn Marino 			exit(errno);
21086d7f5d3SJohn Marino 		}
21186d7f5d3SJohn Marino #endif
21286d7f5d3SJohn Marino 
21386d7f5d3SJohn Marino 		for (i = 0; !ticked; i++)
21486d7f5d3SJohn Marino 			if (*p == child) {
21586d7f5d3SJohn Marino 				e = 0;
21686d7f5d3SJohn Marino 				break;
21786d7f5d3SJohn Marino 			}
21886d7f5d3SJohn Marino 
21986d7f5d3SJohn Marino 		if (e)
22086d7f5d3SJohn Marino 			fprintf(stderr,"Child never ran when it should have.\n");
22186d7f5d3SJohn Marino 	}
22286d7f5d3SJohn Marino 
22386d7f5d3SJohn Marino 	exit(e);
22486d7f5d3SJohn Marino }
22586d7f5d3SJohn Marino 
22686d7f5d3SJohn Marino #ifdef STANDALONE_TESTS
main(int argc,char * argv[])22786d7f5d3SJohn Marino int main(int argc, char *argv[]) { return fifo(argc, argv); }
22886d7f5d3SJohn Marino #endif
229