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 */ 74volatile int the_ball; 75 76static int players_per_team = 0; 77static int game_length = DEF_GAME_LENGTH; 78static atomic_t players_ready; 79 80void 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 89int 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 */ 111void *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 */ 122void *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 132int 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 157int 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