1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1996-1999 5 * HD Associates, Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by HD Associates, Inc 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * $FreeBSD$ 34 * 35 */ 36 #include <sys/types.h> 37 #include <unistd.h> 38 #include <stdlib.h> 39 #include <stdio.h> 40 #include <errno.h> 41 #include <err.h> 42 #include <fcntl.h> 43 #include <sys/types.h> 44 #include <sys/mman.h> 45 #include <sched.h> 46 #include <stdlib.h> 47 #include <sys/wait.h> 48 49 #include "prutil.h" 50 51 /* buzz: busy wait a random amount of time. 52 */ 53 static void buzz(int n) 54 { 55 volatile int i; 56 int m = random() & 0x0ffff; 57 for (i = 0; i < m; i++) 58 ; 59 } 60 61 /* Yield: Verify that "sched_yield" works for the FIFO case. 62 * This runs several processes and verifies that the yield seems 63 * to permit the next one on the ready queue to run. 64 */ 65 int yield(int argc, char *argv[]) 66 { 67 volatile int *p; 68 int i; 69 int nslaves, n; 70 int master, slave; 71 pid_t youngest = !0; /* Our youngest child */ 72 struct sched_param set, got; 73 int nloops = 1000; 74 75 errno = 0; 76 77 set.sched_priority = sched_get_priority_max(SCHED_FIFO); 78 if (set.sched_priority == -1 && errno) { 79 perror("sched_get_priority_max"); 80 exit(errno); 81 } 82 83 if (argc == 1) 84 n = nslaves = 10; 85 86 else if (argc != 2) { 87 fprintf(stderr, "usage: prog [n_instances]\n"); 88 exit(-1); 89 } 90 else 91 n = nslaves = atoi(argv[1]); 92 93 p = (int *)mmap(0, sizeof(int), 94 PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); 95 96 if (p == (int *)-1) 97 err(errno, "mmap"); 98 99 *p = 0; 100 101 if (sched_setscheduler(0, SCHED_FIFO, &set) == -1) 102 err(errno, "sched_setscheduler"); 103 104 /* I better still be SCHED_FIFO and RT_PRIO_MAX: 105 */ 106 (void)sched_is(__LINE__, &got, SCHED_FIFO); 107 if (got.sched_priority != set.sched_priority) { 108 fprintf(stderr, "line %d: scheduler screwup\n", 109 __LINE__); 110 exit(-1); 111 } 112 113 slave = 0; 114 master = 1; 115 116 /* Fork off the slaves. 117 */ 118 for (i = 0; i < nslaves; i++) { 119 if ((youngest = fork()) == 0) { 120 /* I better still be SCHED_FIFO and RT_PRIO_MAX: 121 */ 122 (void)sched_is(__LINE__, &got, SCHED_FIFO); 123 124 if (got.sched_priority != set.sched_priority) { 125 fprintf(stderr, "line %d: scheduler screwup\n", 126 __LINE__); 127 exit(-1); 128 } 129 130 master = 0; /* I'm a slave */ 131 slave = i + 1; /* With this flag */ 132 *p = slave; /* And I live */ 133 break; 134 } 135 } 136 137 if (master) { 138 /* If we conform the slave processes haven't run yet. 139 * The master must yield to let the first slave run. 140 */ 141 if (*p != 0) { 142 fprintf(stderr, 143 "Error at line %d: Writer %d has run\n", __LINE__, *p); 144 exit(-1); 145 } 146 } 147 148 /* Now the master yields, the first slave runs, and yields, 149 * next runs, yields, ... 150 * 151 * So the master should get through this first. 152 */ 153 154 if (sched_yield() == -1) 155 err(errno, "sched_yield"); 156 157 if (master) { 158 int status; 159 160 /* The final slave process should be the last one started. 161 */ 162 if (*p != nslaves) { 163 fprintf(stderr, 164 "Error at line %d: Final slave is %d not %d.\n", 165 __LINE__, *p, nslaves); 166 exit(-1); 167 } 168 169 /* Wait for our youngest to exit: 170 */ 171 waitpid(youngest, &status, 0); 172 173 exit(WEXITSTATUS(status)); /* Let the slaves continue */ 174 } 175 176 /* Now the first one has started up. 177 */ 178 for (i = 0; i < nloops; i++) { 179 if (((*p) % nslaves) != 180 ((slave + nslaves - 1) % nslaves)) { 181 fprintf(stderr, "%d ran before %d on iteration %d.\n", 182 *p, slave, i); 183 exit(-1); 184 } 185 *p = slave; 186 187 /* Delay some random amount of time. 188 */ 189 buzz(slave); 190 191 if (sched_yield() == -1) 192 err(errno, "sched_yield"); 193 } 194 195 exit(0); 196 } 197 #ifdef STANDALONE_TESTS 198 int main(int argc, char *argv[]) { return yield(argc, argv); } 199 #endif 200