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