1 /* 2 * Copyright (c) 1996-1999 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 * $FreeBSD$ 32 * 33 */ 34 #include <sys/types.h> 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 <sched.h> 44 #include <stdlib.h> 45 #include <sys/wait.h> 46 47 #include "prutil.h" 48 49 /* buzz: busy wait a random amount of time. 50 */ 51 static void buzz(int n) 52 { 53 volatile int i; 54 int m = random() & 0x0ffff; 55 for (i = 0; i < m; i++) 56 ; 57 } 58 59 /* Yield: Verify that "sched_yield" works for the FIFO case. 60 * This runs several processes and verifies that the yield seems 61 * to permit the next one on the ready queue to run. 62 */ 63 int yield(int argc, char *argv[]) 64 { 65 volatile int *p; 66 int i; 67 int nslaves, n; 68 int master, slave; 69 pid_t youngest = !0; /* Our youngest child */ 70 struct sched_param set, got; 71 int nloops = 1000; 72 73 errno = 0; 74 75 set.sched_priority = sched_get_priority_max(SCHED_FIFO); 76 if (set.sched_priority == -1 && errno) { 77 perror("sched_get_priority_max"); 78 exit(errno); 79 } 80 81 if (argc == 1) 82 n = nslaves = 10; 83 84 else if (argc != 2) { 85 fprintf(stderr, "usage: prog [n_instances]\n"); 86 exit(-1); 87 } 88 else 89 n = nslaves = atoi(argv[1]); 90 91 p = (int *)mmap(0, sizeof(int), 92 PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED|MAP_INHERIT, -1, 0); 93 94 if (p == (int *)-1) 95 err(errno, "mmap"); 96 97 *p = 0; 98 99 if (sched_setscheduler(0, SCHED_FIFO, &set) == -1) 100 err(errno, "sched_setscheduler"); 101 102 /* I better still be SCHED_FIFO and RT_PRIO_MAX: 103 */ 104 (void)sched_is(__LINE__, &got, SCHED_FIFO); 105 if (got.sched_priority != set.sched_priority) { 106 fprintf(stderr, "line %d: scheduler screwup\n", 107 __LINE__); 108 exit(-1); 109 } 110 111 slave = 0; 112 master = 1; 113 114 /* Fork off the slaves. 115 */ 116 for (i = 0; i < nslaves; i++) { 117 if ((youngest = fork()) == 0) { 118 /* I better still be SCHED_FIFO and RT_PRIO_MAX: 119 */ 120 (void)sched_is(__LINE__, &got, SCHED_FIFO); 121 122 if (got.sched_priority != set.sched_priority) { 123 fprintf(stderr, "line %d: scheduler screwup\n", 124 __LINE__); 125 exit(-1); 126 } 127 128 master = 0; /* I'm a slave */ 129 slave = i + 1; /* With this flag */ 130 *p = slave; /* And I live */ 131 break; 132 } 133 } 134 135 if (master) { 136 /* If we conform the slave processes haven't run yet. 137 * The master must yield to let the first slave run. 138 */ 139 if (*p != 0) { 140 fprintf(stderr, 141 "Error at line %d: Writer %d has run\n", __LINE__, *p); 142 exit(-1); 143 } 144 } 145 146 /* Now the master yields, the first slave runs, and yields, 147 * next runs, yields, ... 148 * 149 * So the master should get through this first. 150 */ 151 152 if (sched_yield() == -1) 153 err(errno, "sched_yield"); 154 155 if (master) { 156 int status; 157 158 /* The final slave process should be the last one started. 159 */ 160 if (*p != nslaves) { 161 fprintf(stderr, 162 "Error at line %d: Final slave is %d not %d.\n", 163 __LINE__, *p, nslaves); 164 exit(-1); 165 } 166 167 /* Wait for our youngest to exit: 168 */ 169 waitpid(youngest, &status, 0); 170 171 exit(WEXITSTATUS(status)); /* Let the slaves continue */ 172 } 173 174 /* Now the first one has started up. 175 */ 176 for (i = 0; i < nloops; i++) { 177 if (((*p) % nslaves) != 178 ((slave + nslaves - 1) % nslaves)) { 179 fprintf(stderr, "%d ran before %d on iteration %d.\n", 180 *p, slave, i); 181 exit(-1); 182 } 183 *p = slave; 184 185 /* Delay some random amount of time. 186 */ 187 buzz(slave); 188 189 if (sched_yield() == -1) 190 err(errno, "sched_yield"); 191 } 192 193 exit(0); 194 } 195 #ifdef STANDALONE_TESTS 196 int main(int argc, char *argv[]) { return yield(argc, argv); } 197 #endif 198