157257Sdufault/* 257257Sdufault * Copyright (c) 1996 - 2000 357257Sdufault * HD Associates, Inc. All rights reserved. 457257Sdufault * 557257Sdufault * Redistribution and use in source and binary forms, with or without 657257Sdufault * modification, are permitted provided that the following conditions 757257Sdufault * are met: 857257Sdufault * 1. Redistributions of source code must retain the above copyright 957257Sdufault * notice, this list of conditions and the following disclaimer. 1057257Sdufault * 2. Redistributions in binary form must reproduce the above copyright 1157257Sdufault * notice, this list of conditions and the following disclaimer in the 1257257Sdufault * documentation and/or other materials provided with the distribution. 1357257Sdufault * 3. All advertising materials mentioning features or use of this software 1457257Sdufault * must display the following acknowledgement: 1557257Sdufault * This product includes software developed by HD Associates, Inc 1657257Sdufault * 4. Neither the name of the author nor the names of any co-contributors 1757257Sdufault * may be used to endorse or promote products derived from this software 1857257Sdufault * without specific prior written permission. 1957257Sdufault * 2057257Sdufault * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND 2157257Sdufault * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2257257Sdufault * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2357257Sdufault * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE 2457257Sdufault * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2557257Sdufault * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2657257Sdufault * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2757257Sdufault * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2857257Sdufault * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2957257Sdufault * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3057257Sdufault * SUCH DAMAGE. 3157257Sdufault * 3257257Sdufault * $FreeBSD$ 3357257Sdufault */ 3457257Sdufault#include <unistd.h> 3557257Sdufault#include <stdlib.h> 3657257Sdufault#include <stdio.h> 3757257Sdufault#include <errno.h> 3857257Sdufault#include <err.h> 3957257Sdufault#include <fcntl.h> 4057257Sdufault#include <sys/types.h> 4157257Sdufault#include <sys/mman.h> 4257257Sdufault#include <sys/time.h> 4357257Sdufault#include <sched.h> 4457257Sdufault#include <signal.h> 4557257Sdufault 4657257Sdufaultvolatile int ticked; 4757257Sdufault#define CAN_USE_ALARMS 4857257Sdufault 4957257Sdufault#ifdef CAN_USE_ALARMS 5057257Sdufaultvoid tick(int arg) 5157257Sdufault{ 5257257Sdufault ticked = 1; 5357257Sdufault} 5457257Sdufault#endif 5557257Sdufault 5657257Sdufault/* Fifo: Verify that fifo and round-robin scheduling seem to work. 5757257Sdufault * 5857257Sdufault * This tests: 5957257Sdufault * 1. That sched_rr_get_interval seems to work; 6057257Sdufault * 2. That FIFO scheduling doesn't seeem to be round-robin; 6157257Sdufault * 3. That round-robin scheduling seems to work. 6257257Sdufault * 6357257Sdufault */ 6457257Sdufaultstatic pid_t child; 6557257Sdufaultstatic void tidyup(void) 6657257Sdufault{ 6757257Sdufault if (child) 6857257Sdufault kill(child, SIGHUP); 6957257Sdufault} 7057257Sdufault 7157257Sdufaultstatic double 7257257Sdufaulttvsub(const struct timeval *a, const struct timeval *b) 7357257Sdufault{ 7457257Sdufault long sdiff; 7557257Sdufault long udiff; 7657257Sdufault 7757257Sdufault sdiff = a->tv_sec - b->tv_sec; 7857257Sdufault udiff = a->tv_usec - b->tv_usec; 7957257Sdufault 8057257Sdufault return (double)(sdiff * 1000000 + udiff) / 1e6; 8157257Sdufault} 8257257Sdufault 8357257Sdufaultint fifo(int argc, char *argv[]) 8457257Sdufault{ 8557257Sdufault int e = 0; 8657257Sdufault volatile long *p, pid; 8757257Sdufault int i; 8857257Sdufault struct sched_param fifo_param; 8957257Sdufault struct timespec interval; 9057257Sdufault#define MAX_RANAT 32 9157257Sdufault struct timeval ranat[MAX_RANAT]; 9257257Sdufault 9357257Sdufault#ifdef CAN_USE_ALARMS 9457257Sdufault static struct itimerval itimerval; 9557257Sdufault#endif 9657257Sdufault 9757257Sdufault /* What is the round robin interval? 9857257Sdufault */ 9957257Sdufault 10057257Sdufault if (sched_rr_get_interval(0, &interval) == -1) { 10157257Sdufault perror("sched_rr_get_interval"); 10257257Sdufault exit(errno); 10357257Sdufault } 10457257Sdufault 10557257Sdufault#ifdef CAN_USE_ALARMS 10657257Sdufault signal(SIGALRM, tick); 10757257Sdufault#endif 10857257Sdufault 10957257Sdufault fifo_param.sched_priority = 1; 11057257Sdufault 11157257Sdufault p = (long *)mmap(0, sizeof(*p), 11257257Sdufault PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED|MAP_INHERIT, -1, 0); 11357257Sdufault 11457257Sdufault if (p == (long *)-1) 11557257Sdufault err(errno, "mmap"); 11657257Sdufault 11757257Sdufault *p = 0; 11857257Sdufault 11957257Sdufault if (sched_setscheduler(0, SCHED_FIFO, &fifo_param) == -1) 12057257Sdufault { 12157257Sdufault perror("sched_setscheduler"); 12257257Sdufault return -1; 12357257Sdufault } 12457257Sdufault 12557257Sdufault pid = getpid(); 12657257Sdufault 12757257Sdufault if ((child = fork()) == 0) 12857257Sdufault { 12957257Sdufault /* Child process. Just keep setting the pointer to our 13057257Sdufault * PID. The parent will kill us when it wants to. 13157257Sdufault */ 13257257Sdufault 13357257Sdufault pid = getpid(); 13457257Sdufault while (1) 13557257Sdufault *p = pid; 13657257Sdufault } 13757257Sdufault else 13857257Sdufault { 13957257Sdufault atexit(tidyup); 14057257Sdufault *p = pid; 14157257Sdufault 14257257Sdufault 14357257Sdufault ticked = 0; 14457257Sdufault 14557257Sdufault#ifdef CAN_USE_ALARMS 14657257Sdufault /* Set an alarm for 250 times the round-robin interval. 14757257Sdufault * Then we will verify that a similar priority process 14857257Sdufault * will not run when we are using the FIFO scheduler. 14957257Sdufault */ 15057257Sdufault itimerval.it_value.tv_usec = interval.tv_nsec / (1000 / 250); 15157257Sdufault 15257257Sdufault itimerval.it_value.tv_sec = itimerval.it_value.tv_usec / 1000000; 15357257Sdufault itimerval.it_value.tv_usec %= 1000000; 15457257Sdufault 15557257Sdufault 15657257Sdufault if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) { 15757257Sdufault perror("setitimer"); 15857257Sdufault exit(errno); 15957257Sdufault } 16057257Sdufault#endif 16157257Sdufault 16257257Sdufault 16357257Sdufault gettimeofday(ranat, 0); 16457257Sdufault i = 1; 16557257Sdufault while (!ticked && i < MAX_RANAT) 16657257Sdufault if (*p == child) { 16757257Sdufault gettimeofday(ranat + i, 0); 16857257Sdufault *p = 0; 16957257Sdufault e = -1; 17057257Sdufault i++; 17157257Sdufault } 17257257Sdufault 17357257Sdufault if (e) { 17457257Sdufault int j; 17557257Sdufault 17657257Sdufault fprintf(stderr, 17757257Sdufault "SCHED_FIFO had erroneous context switches:\n"); 17857257Sdufault for (j = 1; j < i; j++) { 17957257Sdufault fprintf(stderr, "%d %g\n", j, 18057257Sdufault tvsub(ranat + j, ranat + j - 1)); 18157257Sdufault } 18257257Sdufault return e; 18357257Sdufault } 18457257Sdufault 18557257Sdufault /* Switch to the round robin scheduler and the child 18657257Sdufault * should run within twice the interval. 18757257Sdufault */ 18857257Sdufault if (sched_setscheduler(child, SCHED_RR, &fifo_param) == -1 || 18957257Sdufault sched_setscheduler(0, SCHED_RR, &fifo_param) == -1) 19057257Sdufault { 19157257Sdufault perror("sched_setscheduler"); 19257257Sdufault return -1; 19357257Sdufault } 19457257Sdufault 19557257Sdufault e = -1; 19657257Sdufault 19757257Sdufault ticked = 0; 19857257Sdufault 19957257Sdufault#ifdef CAN_USE_ALARMS 20057257Sdufault 20157257Sdufault /* Now we do want to see it run. But only set 20257257Sdufault * the alarm for twice the interval: 20357257Sdufault */ 20457257Sdufault itimerval.it_value.tv_usec = interval.tv_nsec / 500; 20557257Sdufault 20657257Sdufault if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) { 20757257Sdufault perror("setitimer"); 20857257Sdufault exit(errno); 20957257Sdufault } 21057257Sdufault#endif 21157257Sdufault 21257257Sdufault for (i = 0; !ticked; i++) 21357257Sdufault if (*p == child) { 21457257Sdufault e = 0; 21557257Sdufault break; 21657257Sdufault } 21757257Sdufault 21857257Sdufault if (e) 21957257Sdufault fprintf(stderr,"Child never ran when it should have.\n"); 22057257Sdufault } 22157257Sdufault 22257257Sdufault exit(e); 22357257Sdufault} 22457257Sdufault 22557257Sdufault#ifdef STANDALONE_TESTS 22657257Sdufaultint main(int argc, char *argv[]) { return fifo(argc, argv); } 22757257Sdufault#endif 228