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$ 33 */ 34 #include <sys/types.h> 35 #include <sys/mman.h> 36 #include <sys/time.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <fcntl.h> 40 #include <sched.h> 41 #include <signal.h> 42 #include <stdlib.h> 43 #include <stdio.h> 44 #include <unistd.h> 45 46 volatile int ticked; 47 #define CAN_USE_ALARMS 48 49 #ifdef CAN_USE_ALARMS 50 void tick(int arg) 51 { 52 ticked = 1; 53 } 54 #endif 55 56 /* Fifo: Verify that fifo and round-robin scheduling seem to work. 57 * 58 * This tests: 59 * 1. That sched_rr_get_interval seems to work; 60 * 2. That FIFO scheduling doesn't seeem to be round-robin; 61 * 3. That round-robin scheduling seems to work. 62 * 63 */ 64 static pid_t child; 65 static void tidyup(void) 66 { 67 if (child) 68 kill(child, SIGHUP); 69 } 70 71 static double 72 tvsub(const struct timeval *a, const struct timeval *b) 73 { 74 long sdiff; 75 long udiff; 76 77 sdiff = a->tv_sec - b->tv_sec; 78 udiff = a->tv_usec - b->tv_usec; 79 80 return (double)(sdiff * 1000000 + udiff) / 1e6; 81 } 82 83 int fifo(int argc, char *argv[]) 84 { 85 int e = 0; 86 volatile long *p, pid; 87 int i; 88 struct sched_param fifo_param; 89 struct timespec interval; 90 #define MAX_RANAT 32 91 struct timeval ranat[MAX_RANAT]; 92 93 #ifdef CAN_USE_ALARMS 94 static struct itimerval itimerval; 95 #endif 96 97 /* What is the round robin interval? 98 */ 99 100 if (sched_rr_get_interval(0, &interval) == -1) { 101 perror("sched_rr_get_interval"); 102 exit(errno); 103 } 104 105 #ifdef CAN_USE_ALARMS 106 signal(SIGALRM, tick); 107 #endif 108 109 fifo_param.sched_priority = 1; 110 111 p = (long *)mmap(0, sizeof(*p), 112 PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); 113 114 if (p == (long *)-1) 115 err(errno, "mmap"); 116 117 *p = 0; 118 119 if (sched_setscheduler(0, SCHED_FIFO, &fifo_param) == -1) 120 { 121 perror("sched_setscheduler"); 122 return -1; 123 } 124 125 pid = getpid(); 126 127 if ((child = fork()) == 0) 128 { 129 /* Child process. Just keep setting the pointer to our 130 * PID. The parent will kill us when it wants to. 131 */ 132 133 pid = getpid(); 134 while (1) 135 *p = pid; 136 } 137 else 138 { 139 atexit(tidyup); 140 *p = pid; 141 142 143 ticked = 0; 144 145 #ifdef CAN_USE_ALARMS 146 /* Set an alarm for 250 times the round-robin interval. 147 * Then we will verify that a similar priority process 148 * will not run when we are using the FIFO scheduler. 149 */ 150 itimerval.it_value.tv_usec = interval.tv_nsec / (1000 / 250); 151 152 itimerval.it_value.tv_sec = itimerval.it_value.tv_usec / 1000000; 153 itimerval.it_value.tv_usec %= 1000000; 154 155 156 if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) { 157 perror("setitimer"); 158 exit(errno); 159 } 160 #endif 161 162 163 gettimeofday(ranat, 0); 164 i = 1; 165 while (!ticked && i < MAX_RANAT) 166 if (*p == child) { 167 gettimeofday(ranat + i, 0); 168 *p = 0; 169 e = -1; 170 i++; 171 } 172 173 if (e) { 174 int j; 175 176 fprintf(stderr, 177 "SCHED_FIFO had erroneous context switches:\n"); 178 for (j = 1; j < i; j++) { 179 fprintf(stderr, "%d %g\n", j, 180 tvsub(ranat + j, ranat + j - 1)); 181 } 182 return e; 183 } 184 185 /* Switch to the round robin scheduler and the child 186 * should run within twice the interval. 187 */ 188 if (sched_setscheduler(child, SCHED_RR, &fifo_param) == -1 || 189 sched_setscheduler(0, SCHED_RR, &fifo_param) == -1) 190 { 191 perror("sched_setscheduler"); 192 return -1; 193 } 194 195 e = -1; 196 197 ticked = 0; 198 199 #ifdef CAN_USE_ALARMS 200 201 /* Now we do want to see it run. But only set 202 * the alarm for twice the interval: 203 */ 204 itimerval.it_value.tv_usec = interval.tv_nsec / 500; 205 206 if (setitimer(ITIMER_REAL, &itimerval, 0) == -1) { 207 perror("setitimer"); 208 exit(errno); 209 } 210 #endif 211 212 for (i = 0; !ticked; i++) 213 if (*p == child) { 214 e = 0; 215 break; 216 } 217 218 if (e) 219 fprintf(stderr,"Child never ran when it should have.\n"); 220 } 221 222 exit(e); 223 } 224 225 #ifdef STANDALONE_TESTS 226 int main(int argc, char *argv[]) { return fifo(argc, argv); } 227 #endif 228