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