1 /* 2 Redistribution and use in source and binary forms, with or without 3 modification, are permitted provided that the following conditions are met: 4 5 * Redistributions of source code must retain the above copyright 6 notice, this list of conditions and the following disclaimer. 7 8 * Redistributions in binary form must reproduce the above copyright 9 notice, this list of conditions and the following disclaimer in the 10 documentation and/or other materials provided with the distribution. 11 12 * Neither the name of "The Computer Language Benchmarks Game" nor the 13 name of "The Computer Language Shootout Benchmarks" nor the names of 14 its contributors may be used to endorse or promote products derived 15 from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* The Computer Language Benchmarks Game 31 http://shootout.alioth.debian.org/ 32 33 contributed by Michael Barker 34 based on a Java contribution by Luzius Meisser 35 36 convert to C by dualamd 37 */ 38 39 #include <stdlib.h> 40 #include <stdio.h> 41 #include <pthread.h> 42 43 44 enum Colour 45 { 46 blue = 0, 47 red = 1, 48 yellow = 2, 49 Invalid = 3 50 }; 51 52 const char* ColourName[] = {"blue", "red", "yellow"}; 53 const int STACK_SIZE = 32*1024; 54 55 typedef unsigned int BOOL; 56 const BOOL TRUE = 1; 57 const BOOL FALSE = 0; 58 59 int CreatureID = 0; 60 61 62 enum Colour doCompliment(enum Colour c1, enum Colour c2) 63 { 64 switch (c1) 65 { 66 case blue: 67 switch (c2) 68 { 69 case blue: 70 return blue; 71 case red: 72 return yellow; 73 case yellow: 74 return red; 75 default: 76 goto errlb; 77 } 78 case red: 79 switch (c2) 80 { 81 case blue: 82 return yellow; 83 case red: 84 return red; 85 case yellow: 86 return blue; 87 default: 88 goto errlb; 89 } 90 case yellow: 91 switch (c2) 92 { 93 case blue: 94 return red; 95 case red: 96 return blue; 97 case yellow: 98 return yellow; 99 default: 100 goto errlb; 101 } 102 default: 103 break; 104 } 105 106 errlb: 107 printf("Invalid colour\n"); 108 exit( 1 ); 109 } 110 111 /* convert integer to number string: 1234 -> "one two three four" */ 112 char* formatNumber(int n, char* outbuf) 113 { 114 int ochar = 0, ichar = 0; 115 int i; 116 char tmp[64]; 117 118 const char* NUMBERS[] = 119 { 120 "zero", "one", "two", "three", "four", "five", 121 "six", "seven", "eight", "nine" 122 }; 123 124 ichar = sprintf(tmp, "%d", n); 125 126 for (i = 0; i < ichar; i++) 127 ochar += sprintf( outbuf + ochar, " %s", NUMBERS[ tmp[i] - '0' ] ); 128 129 return outbuf; 130 } 131 132 133 struct MeetingPlace 134 { 135 pthread_mutex_t mutex; 136 int meetingsLeft; 137 struct Creature* firstCreature; 138 }; 139 140 struct Creature 141 { 142 pthread_t ht; 143 pthread_attr_t stack_att; 144 145 struct MeetingPlace* place; 146 int count; 147 int sameCount; 148 149 enum Colour colour; 150 int id; 151 152 BOOL two_met; 153 BOOL sameid; 154 }; 155 156 157 void MeetingPlace_Init(struct MeetingPlace* m, int meetings ) 158 { 159 pthread_mutex_init( &m->mutex, 0 ); 160 m->meetingsLeft = meetings; 161 m->firstCreature = 0; 162 } 163 164 165 BOOL Meet( struct Creature* cr) 166 { 167 BOOL retval = TRUE; 168 169 struct MeetingPlace* mp = cr->place; 170 pthread_mutex_lock( &(mp->mutex) ); 171 172 if ( mp->meetingsLeft > 0 ) 173 { 174 if ( mp->firstCreature == 0 ) 175 { 176 cr->two_met = FALSE; 177 mp->firstCreature = cr; 178 } 179 else 180 { 181 struct Creature* first; 182 enum Colour newColour; 183 184 first = mp->firstCreature; 185 newColour = doCompliment( cr->colour, first->colour ); 186 187 cr->sameid = cr->id == first->id; 188 cr->colour = newColour; 189 cr->two_met = TRUE; 190 191 first->sameid = cr->sameid; 192 first->colour = newColour; 193 first->two_met = TRUE; 194 195 mp->firstCreature = 0; 196 mp->meetingsLeft--; 197 } 198 } 199 else 200 retval = FALSE; 201 202 pthread_mutex_unlock( &(mp->mutex) ); 203 return retval; 204 } 205 206 207 void* CreatureThreadRun(void* param) 208 { 209 struct Creature* cr = (struct Creature*)param; 210 211 while (TRUE) 212 { 213 if ( Meet(cr) ) 214 { 215 while (cr->two_met == FALSE) 216 sched_yield(); 217 218 if (cr->sameid) 219 cr->sameCount++; 220 cr->count++; 221 } 222 else 223 break; 224 } 225 226 return 0; 227 } 228 229 void Creature_Init( struct Creature *cr, struct MeetingPlace* place, enum Colour colour ) 230 { 231 cr->place = place; 232 cr->count = cr->sameCount = 0; 233 234 cr->id = ++CreatureID; 235 cr->colour = colour; 236 cr->two_met = FALSE; 237 238 pthread_attr_init( &cr->stack_att ); 239 pthread_attr_setstacksize( &cr->stack_att, STACK_SIZE ); 240 pthread_create( &cr->ht, &cr->stack_att, &CreatureThreadRun, (void*)(cr) ); 241 } 242 243 /* format meeting times of each creature to string */ 244 char* Creature_getResult(struct Creature* cr, char* str) 245 { 246 char numstr[256]; 247 formatNumber(cr->sameCount, numstr); 248 249 sprintf( str, "%u%s", cr->count, numstr ); 250 return str; 251 } 252 253 254 void runGame( int n_meeting, int ncolor, const enum Colour* colours ) 255 { 256 int i; 257 int total = 0; 258 char str[256]; 259 260 struct MeetingPlace place; 261 struct Creature *creatures = (struct Creature*) calloc( ncolor, sizeof(struct Creature) ); 262 263 MeetingPlace_Init( &place, n_meeting ); 264 265 /* print initial color of each creature */ 266 for (i = 0; i < ncolor; i++) 267 { 268 printf( "%s ", ColourName[ colours[i] ] ); 269 Creature_Init( &(creatures[i]), &place, colours[i] ); 270 } 271 printf("\n"); 272 273 /* wait for them to meet */ 274 for (i = 0; i < ncolor; i++) 275 pthread_join( creatures[i].ht, 0 ); 276 277 /* print meeting times of each creature */ 278 for (i = 0; i < ncolor; i++) 279 { 280 printf( "%s\n", Creature_getResult(&(creatures[i]), str) ); 281 total += creatures[i].count; 282 } 283 284 /* print total meeting times, should equal n_meeting */ 285 printf( "%s\n\n", formatNumber(total, str) ); 286 287 /* cleaup & quit */ 288 pthread_mutex_destroy( &place.mutex ); 289 free( creatures ); 290 } 291 292 293 void printColours( enum Colour c1, enum Colour c2 ) 294 { 295 printf( "%s + %s -> %s\n", 296 ColourName[c1], 297 ColourName[c2], 298 ColourName[doCompliment(c1, c2)] ); 299 } 300 301 void printColoursTable(void) 302 { 303 printColours(blue, blue); 304 printColours(blue, red); 305 printColours(blue, yellow); 306 printColours(red, blue); 307 printColours(red, red); 308 printColours(red, yellow); 309 printColours(yellow, blue); 310 printColours(yellow, red); 311 printColours(yellow, yellow); 312 } 313 314 int main(int argc, char** argv) 315 { 316 int n = (argc == 2) ? atoi(argv[1]) : 600; 317 318 printColoursTable(); 319 printf("\n"); 320 321 const enum Colour r1[] = { blue, red, yellow }; 322 const enum Colour r2[] = { blue, red, yellow, 323 red, yellow, blue, 324 red, yellow, red, blue }; 325 326 runGame( n, sizeof(r1) / sizeof(r1[0]), r1 ); 327 runGame( n, sizeof(r2) / sizeof(r2[0]), r2 ); 328 329 return 0; 330 } 331