1 /******************************************************************************
2 *
3 * Copyright © International Business Machines Corp., 2007, 2008
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * NAME
20 * sched_football.c
21 *
22 * DESCRIPTION
23 * This is a scheduler test that uses a football analogy.
24 * The premise is that we want to make sure that lower priority threads
25 * (defensive team). The offense is trying to increment the balls position,
26 * while the defense is trying to block that from happening.
27 * And the ref (highest priority thread) will blow the wistle if the
28 * ball moves. Finally, we have crazy fans (higer prority) that try to
29 * distract the defense by occasionally running onto the field.
30 *
31 * Steps:
32 * - Create a fixed number of offense threads (lower priority)
33 * - Create a referee thread (highest priority)
34 * - Once everyone is on the field, the offense thread increments the
35 * value of 'the_ball' and yields. The defense thread tries to block
36 * the ball by never letting the offense players get the CPU (it just
37 * does a sched_yield).
38 * - The refree threads wakes up regularly to check if the game is over :)
39 * - In the end, if the value of 'the_ball' is >0, the test is considered
40 * to have failed.
41 *
42 * USAGE:
43 * Use run_auto.sh script in current directory to build and run test.
44 *
45 * AUTHOR
46 * John Stultz <johnstul@xxxxxxxxx >
47 *
48 * HISTORY
49 * 2006-03-16 Reduced verbosity, non binary failure reporting, removal of
50 * crazy_fans thread, added game_length argument by Darren Hart.
51 * 2007-08-01 Remove all thread cleanup in favor of simply exiting.Various
52 * bugfixes and cleanups. -- Josh Triplett
53 * 2009-06-23 Simplified atomic startup mechanism, avoiding thundering herd
54 * scheduling at the beginning of the game. -- Darren Hart
55 *
56 *****************************************************************************/
57
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <signal.h>
61 #include <time.h>
62 #include <string.h>
63 #include <pthread.h>
64 #include <sched.h>
65 #include <errno.h>
66 #include <sys/syscall.h>
67 #include <unistd.h>
68 #include <sys/time.h>
69 #include <librttest.h>
70
71 #define DEF_GAME_LENGTH 5
72
73 /* Here's the position of the ball */
74 volatile int the_ball;
75
76 static int players_per_team = 0;
77 static int game_length = DEF_GAME_LENGTH;
78 static atomic_t players_ready;
79
usage(void)80 void usage(void)
81 {
82 rt_help();
83 printf("sched_football specific options:\n");
84 printf(" -nPLAYERS players per team (defaults to num_cpus)\n");
85 printf(" -lGAME_LENGTH game length in seconds (defaults to %d s)\n",
86 DEF_GAME_LENGTH);
87 }
88
parse_args(int c,char * v)89 int parse_args(int c, char *v)
90 {
91
92 int handled = 1;
93 switch (c) {
94 case 'h':
95 usage();
96 exit(0);
97 case 'n':
98 players_per_team = atoi(v);
99 break;
100 case 'l':
101 game_length = atoi(v);
102 break;
103 default:
104 handled = 0;
105 break;
106 }
107 return handled;
108 }
109
110 /* This is the defensive team. They're trying to block the offense */
thread_defense(void * arg)111 void *thread_defense(void *arg)
112 {
113 atomic_inc(&players_ready);
114 /*keep the ball from being moved */
115 while (1) {
116 sched_yield(); /* let other defenders run */
117 }
118 return NULL;
119 }
120
121 /* This is the offensive team. They're trying to move the ball */
thread_offense(void * arg)122 void *thread_offense(void *arg)
123 {
124 atomic_inc(&players_ready);
125 while (1) {
126 the_ball++; /* move the ball ahead one yard */
127 sched_yield(); /* let other offensive players run */
128 }
129 return NULL;
130 }
131
referee(int game_length)132 int referee(int game_length)
133 {
134 struct timeval start, now;
135 int final_ball;
136
137 printf("Game On (%d seconds)!\n", game_length);
138
139 gettimeofday(&start, NULL);
140 now = start;
141
142 /* Start the game! */
143 the_ball = 0;
144
145 /* Watch the game */
146 while ((now.tv_sec - start.tv_sec) < game_length) {
147 sleep(1);
148 gettimeofday(&now, NULL);
149 }
150 /* Blow the whistle */
151 printf("Game Over!\n");
152 final_ball = the_ball;
153 printf("Final ball position: %d\n", final_ball);
154 return final_ball != 0;
155 }
156
main(int argc,char * argv[])157 int main(int argc, char *argv[])
158 {
159 struct sched_param param;
160 int priority;
161 int i;
162 int result;
163 setup();
164
165 rt_init("n:l:h", parse_args, argc, argv);
166
167 if (players_per_team == 0)
168 players_per_team = sysconf(_SC_NPROCESSORS_ONLN);
169
170 atomic_set(0, &players_ready);
171
172 printf("Running with: players_per_team=%d game_length=%d\n",
173 players_per_team, game_length);
174
175 /* We're the ref, so set our priority right */
176 param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 80;
177 sched_setscheduler(0, SCHED_FIFO, ¶m);
178
179 /*
180 * Start the offense
181 * They are lower priority than defense, so they must be started first.
182 */
183 priority = 15;
184 printf("Starting %d offense threads at priority %d\n",
185 players_per_team, priority);
186 for (i = 0; i < players_per_team; i++)
187 create_fifo_thread(thread_offense, NULL, priority);
188
189 /* Wait for the offense threads to start */
190 while (atomic_get(&players_ready) < players_per_team)
191 usleep(100);
192
193 /* Start the defense */
194 priority = 30;
195 printf("Starting %d defense threads at priority %d\n",
196 players_per_team, priority);
197 for (i = 0; i < players_per_team; i++)
198 create_fifo_thread(thread_defense, NULL, priority);
199
200 /* Wait for the defense threads to start */
201 while (atomic_get(&players_ready) < players_per_team * 2)
202 usleep(100);
203
204 /* Ok, everyone is on the field, bring out the ref */
205 printf("Starting referee thread\n");
206 result = referee(game_length);
207 printf("Result: %s\n", result ? "FAIL" : "PASS");
208 return result;
209
210 }
211