00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <types.h>
00030 #include <lib.h>
00031 #include <test.h>
00032 #include <clock.h>
00033 #include <thread.h>
00034 #include <synch.h>
00035 #include <synchprobs.h>
00036
00037
00038 static void initialize_bowls(void);
00039 static void cleanup_bowls(void);
00040 static void cat_eat(unsigned int bowlnumber, int eat_time);
00041 static void cat_sleep(int sleep_time);
00042 static void mouse_eat(unsigned int bowlnumber, int eat_time);
00043 static void mouse_sleep(int sleep_time);
00044 static void cat_simulation(void *ptr, unsigned long catnumber);
00045 static void mouse_simulation(void *ptr, unsigned long mousenumber);
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 static int NumBowls;
00062 static int NumCats;
00063 static int NumMice;
00064 static int NumLoops;
00065
00066 static int CatEatTime = 1;
00067 static int CatSleepTime = 2;
00068 static int MouseEatTime = 1;
00069 static int MouseSleepTime = 2;
00070
00071
00072
00073
00074
00075
00076 static struct semaphore *CatMouseWait;
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 static volatile char *bowls;
00096
00097
00098
00099
00100 static volatile int eating_cats_count;
00101
00102
00103
00104
00105 static volatile int eating_mice_count;
00106
00107
00108
00109
00110
00111
00112 static struct semaphore *mutex;
00113
00114
00115 static volatile time_t cat_total_wait_secs;
00116 static volatile uint32_t cat_total_wait_nsecs;
00117 static volatile int cat_wait_count;
00118 static volatile time_t mouse_total_wait_secs;
00119 static volatile uint32_t mouse_total_wait_nsecs;
00120 static volatile int mouse_wait_count;
00121
00122
00123 static struct semaphore *perf_mutex;
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 static void
00140 initialize_bowls()
00141 {
00142 int i;
00143
00144 KASSERT(NumBowls > 0);
00145
00146 bowls = kmalloc(NumBowls*sizeof(char));
00147 if (bowls == NULL) {
00148 panic("initialize_bowls: unable to allocate space for %d bowls\n",NumBowls);
00149 }
00150
00151 for(i=0;i<NumBowls;i++) {
00152 bowls[i] = '-';
00153 }
00154 eating_cats_count = eating_mice_count = 0;
00155
00156
00157 mutex = sem_create("bowl mutex",1);
00158 if (mutex == NULL) {
00159 panic("initialize_bowls: could not create mutex\n");
00160 }
00161
00162 perf_mutex = sem_create("stats mutex",1);
00163 if (perf_mutex == NULL) {
00164 panic("initialize_bowls: could not create perf_mutex\n");
00165 }
00166
00167 cat_total_wait_secs = 0;
00168 cat_total_wait_nsecs = 0;
00169 cat_wait_count = 0;
00170 mouse_total_wait_secs = 0;
00171 mouse_total_wait_nsecs = 0;
00172 mouse_wait_count = 0;
00173
00174 return;
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 static void
00192 cleanup_bowls()
00193 {
00194 if (mutex != NULL) {
00195 sem_destroy( mutex );
00196 mutex = NULL;
00197 }
00198 if (perf_mutex != NULL) {
00199 sem_destroy( perf_mutex );
00200 perf_mutex = NULL;
00201 }
00202 if (bowls != NULL) {
00203 kfree( (void *) bowls );
00204 bowls = NULL;
00205 }
00206 }
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 void
00260 cat_eat(unsigned int bowlnumber, int eat_time)
00261 {
00262
00263
00264 KASSERT(bowlnumber > 0);
00265 KASSERT((int)bowlnumber <= NumBowls);
00266
00267
00268
00269 P(mutex);
00270
00271
00272
00273 if (bowls[bowlnumber-1] == 'c') {
00274
00275 panic("cat_eat: attempt to make two cats eat from bowl %d!\n",bowlnumber);
00276 }
00277 if (eating_mice_count > 0) {
00278
00279 panic("cat_eat: attempt to make a cat eat while mice are eating!\n");
00280 }
00281 KASSERT(bowls[bowlnumber-1]=='-');
00282 KASSERT(eating_mice_count == 0);
00283
00284
00285 eating_cats_count += 1;
00286 bowls[bowlnumber-1] = 'c';
00287
00288 DEBUG(DB_SYNCPROB,"cat starts to eat at bowl %d [%d:%d]\n",
00289 bowlnumber,eating_cats_count,eating_mice_count);
00290 V(mutex);
00291
00292
00293
00294 clocksleep(eat_time);
00295
00296
00297
00298 P(mutex);
00299 KASSERT(eating_cats_count > 0);
00300 KASSERT(bowls[bowlnumber-1]=='c');
00301 eating_cats_count -= 1;
00302 bowls[bowlnumber-1]='-';
00303
00304 DEBUG(DB_SYNCPROB,"cat finished eating at bowl %d [%d:%d]\n",
00305 bowlnumber,eating_cats_count,eating_mice_count);
00306 V(mutex);
00307
00308 return;
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 void
00323 cat_sleep(int sleep_time)
00324 {
00325
00326 clocksleep(sleep_time);
00327 return;
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 void
00348 mouse_eat(unsigned int bowlnumber, int eat_time)
00349 {
00350
00351 KASSERT(bowlnumber > 0);
00352 KASSERT((int)bowlnumber <= NumBowls);
00353
00354
00355
00356 P(mutex);
00357
00358
00359
00360 if (bowls[bowlnumber-1] == 'm') {
00361
00362 panic("mouse_eat: attempt to make two mice eat from bowl %d!\n",bowlnumber);
00363 }
00364 if (eating_cats_count > 0) {
00365
00366 panic("mouse_eat: attempt to make a mouse eat while cats are eating!\n");
00367 }
00368 KASSERT(bowls[bowlnumber-1]=='-');
00369 KASSERT(eating_cats_count == 0);
00370
00371
00372 eating_mice_count += 1;
00373 bowls[bowlnumber-1] = 'm';
00374
00375 DEBUG(DB_SYNCPROB,"mouse starts to eat at bowl %d [%d:%d]\n",
00376 bowlnumber,eating_cats_count,eating_mice_count);
00377 V(mutex);
00378
00379
00380
00381 clocksleep(eat_time);
00382
00383
00384
00385 P(mutex);
00386
00387 KASSERT(eating_mice_count > 0);
00388 eating_mice_count -= 1;
00389 KASSERT(bowls[bowlnumber-1]=='m');
00390 bowls[bowlnumber-1]='-';
00391
00392 DEBUG(DB_SYNCPROB,"mouse finishes eating at bowl %d [%d:%d]\n",
00393 bowlnumber,eating_cats_count,eating_mice_count);
00394 V(mutex);
00395 return;
00396 }
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409 void
00410 mouse_sleep(int sleep_time)
00411 {
00412
00413 clocksleep(sleep_time);
00414 return;
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 static
00433 void
00434 cat_simulation(void * unusedpointer,
00435 unsigned long catnumber)
00436 {
00437 int i;
00438 unsigned int bowl;
00439 time_t before_sec, after_sec, wait_sec;
00440 uint32_t before_nsec, after_nsec, wait_nsec;
00441
00442
00443 (void) unusedpointer;
00444 (void) catnumber;
00445
00446
00447 for(i=0;i<NumLoops;i++) {
00448
00449
00450 cat_sleep(CatSleepTime);
00451
00452
00453 bowl = ((unsigned int)random() % NumBowls) + 1;
00454
00455 gettime(&before_sec,&before_nsec);
00456 cat_before_eating(bowl);
00457 gettime(&after_sec,&after_nsec);
00458
00459
00460 cat_eat(bowl, CatEatTime);
00461
00462 cat_after_eating(bowl);
00463
00464
00465 getinterval(before_sec,before_nsec,after_sec,after_nsec,&wait_sec,&wait_nsec);
00466 P(perf_mutex);
00467 cat_total_wait_secs += wait_sec;
00468 cat_total_wait_nsecs += wait_nsec;
00469 if (cat_total_wait_nsecs > 1000000000) {
00470 cat_total_wait_nsecs -= 1000000000;
00471 cat_total_wait_secs ++;
00472 }
00473 cat_wait_count++;
00474 V(perf_mutex);
00475 }
00476
00477
00478 V(CatMouseWait);
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 static
00497 void
00498 mouse_simulation(void * unusedpointer,
00499 unsigned long mousenumber)
00500 {
00501 int i;
00502 unsigned int bowl;
00503 time_t before_sec, after_sec, wait_sec;
00504 uint32_t before_nsec, after_nsec, wait_nsec;
00505
00506
00507 (void) unusedpointer;
00508 (void) mousenumber;
00509
00510 for(i=0;i<NumLoops;i++) {
00511
00512
00513 mouse_sleep(MouseSleepTime);
00514
00515
00516 bowl = ((unsigned int)random() % NumBowls) + 1;
00517
00518 gettime(&before_sec,&before_nsec);
00519 mouse_before_eating(bowl);
00520 gettime(&after_sec,&after_nsec);
00521
00522
00523 mouse_eat(bowl, MouseEatTime);
00524
00525 mouse_after_eating(bowl);
00526
00527
00528 getinterval(before_sec,before_nsec,after_sec,after_nsec,&wait_sec,&wait_nsec);
00529 P(perf_mutex);
00530 mouse_total_wait_secs += wait_sec;
00531 mouse_total_wait_nsecs += wait_nsec;
00532 if (mouse_total_wait_nsecs > 1000000000) {
00533 mouse_total_wait_nsecs -= 1000000000;
00534 mouse_total_wait_secs ++;
00535 }
00536 mouse_wait_count++;
00537 V(perf_mutex);
00538 }
00539
00540
00541 V(CatMouseWait);
00542 }
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567 int
00568 catmouse(int nargs,
00569 char ** args)
00570 {
00571 int catindex, mouseindex, error;
00572 int i;
00573 int mean_cat_wait_usecs, mean_mouse_wait_usecs;
00574 time_t before_sec, after_sec, wait_sec;
00575 uint32_t before_nsec, after_nsec, wait_nsec;
00576 int total_bowl_milliseconds, total_eating_milliseconds, utilization_percent;
00577
00578
00579 if ((nargs != 9) && (nargs != 5)) {
00580 kprintf("Usage: <command> NUM_BOWLS NUM_CATS NUM_MICE NUM_LOOPS\n");
00581 kprintf("or\n");
00582 kprintf("Usage: <command> NUM_BOWLS NUM_CATS NUM_MICE NUM_LOOPS ");
00583 kprintf("CAT_EATING_TIME CAT_SLEEPING_TIME MOUSE_EATING_TIME MOUSE_SLEEPING_TIME\n");
00584 return 1;
00585 }
00586
00587
00588 NumBowls = atoi(args[1]);
00589 if (NumBowls <= 0) {
00590 kprintf("catmouse: invalid number of bowls: %d\n",NumBowls);
00591 return 1;
00592 }
00593 NumCats = atoi(args[2]);
00594 if (NumCats < 0) {
00595 kprintf("catmouse: invalid number of cats: %d\n",NumCats);
00596 return 1;
00597 }
00598 NumMice = atoi(args[3]);
00599 if (NumMice < 0) {
00600 kprintf("catmouse: invalid number of mice: %d\n",NumMice);
00601 return 1;
00602 }
00603 NumLoops = atoi(args[4]);
00604 if (NumLoops <= 0) {
00605 kprintf("catmouse: invalid number of loops: %d\n",NumLoops);
00606 return 1;
00607 }
00608
00609 if (nargs == 9) {
00610 CatEatTime = atoi(args[5]);
00611 if (CatEatTime < 0) {
00612 kprintf("catmouse: invalid cat eating time: %d\n",CatEatTime);
00613 return 1;
00614 }
00615
00616 CatSleepTime = atoi(args[6]);
00617 if (CatSleepTime < 0) {
00618 kprintf("catmouse: invalid cat sleeping time: %d\n",CatSleepTime);
00619 return 1;
00620 }
00621
00622 MouseEatTime = atoi(args[7]);
00623 if (MouseEatTime < 0) {
00624 kprintf("catmouse: invalid mouse eating time: %d\n",MouseEatTime);
00625 return 1;
00626 }
00627
00628 MouseSleepTime = atoi(args[8]);
00629 if (MouseSleepTime < 0) {
00630 kprintf("catmouse: invalid mouse sleeping time: %d\n",MouseSleepTime);
00631 return 1;
00632 }
00633 }
00634
00635 kprintf("Using %d bowls, %d cats, and %d mice. Looping %d times.\n",
00636 NumBowls,NumCats,NumMice,NumLoops);
00637 kprintf("Using cat eating time %d, cat sleeping time %d\n", CatEatTime, CatSleepTime);
00638 kprintf("Using mouse eating time %d, mouse sleeping time %d\n", MouseEatTime, MouseSleepTime);
00639
00640
00641
00642 CatMouseWait = sem_create("CatMouseWait",0);
00643 if (CatMouseWait == NULL) {
00644 panic("catmouse: could not create semaphore\n");
00645 }
00646
00647
00648 initialize_bowls();
00649
00650
00651 catmouse_sync_init(NumBowls);
00652
00653
00654 gettime(&before_sec,&before_nsec);
00655
00656
00657
00658
00659
00660 for (catindex = 0; catindex < NumCats; catindex++) {
00661 error = thread_fork("cat_simulation thread", NULL, cat_simulation, NULL, catindex);
00662 if (error) {
00663 panic("cat_simulation: thread_fork failed: %s\n", strerror(error));
00664 }
00665 if (catindex < NumMice) {
00666 error = thread_fork("mouse_simulation thread", NULL, mouse_simulation, NULL, catindex);
00667 if (error) {
00668 panic("mouse_simulation: thread_fork failed: %s\n",strerror(error));
00669 }
00670 }
00671 }
00672
00673 for(mouseindex = catindex; mouseindex < NumMice; mouseindex++) {
00674 error = thread_fork("mouse_simulation thread", NULL, mouse_simulation, NULL, mouseindex);
00675 if (error) {
00676 panic("mouse_simulation: thread_fork failed: %s\n",strerror(error));
00677 }
00678 }
00679
00680
00681
00682 for(i=0;i<(NumCats+NumMice);i++) {
00683 P(CatMouseWait);
00684 }
00685
00686
00687 gettime(&after_sec,&after_nsec);
00688
00689 getinterval(before_sec,before_nsec,after_sec,after_nsec,&wait_sec,&wait_nsec);
00690
00691 total_bowl_milliseconds = (wait_sec*1000 + wait_nsec/1000000)*NumBowls;
00692 total_eating_milliseconds = (NumCats*CatEatTime + NumMice*MouseEatTime)*NumLoops*1000;
00693 if (total_bowl_milliseconds > 0) {
00694 utilization_percent = total_eating_milliseconds*100/total_bowl_milliseconds;
00695 kprintf("Bowl utilization: %d%%\n",utilization_percent);
00696 }
00697
00698
00699 sem_destroy(CatMouseWait);
00700
00701
00702 catmouse_sync_cleanup(NumBowls);
00703
00704
00705 cleanup_bowls();
00706
00707 if (cat_wait_count > 0) {
00708
00709 mean_cat_wait_usecs = (cat_total_wait_secs*1000000+cat_total_wait_nsecs/1000)/cat_wait_count;
00710 kprintf("Mean cat waiting time: %d.%d seconds\n",mean_cat_wait_usecs/1000000,mean_cat_wait_usecs%1000000);
00711 }
00712 if (mouse_wait_count > 0) {
00713
00714 mean_mouse_wait_usecs = (mouse_total_wait_secs*1000000+mouse_total_wait_nsecs/1000)/mouse_wait_count;
00715 kprintf("Mean mouse waiting time: %d.%d seconds\n",mean_mouse_wait_usecs/1000000,mean_mouse_wait_usecs%1000000);
00716 }
00717
00718 return 0;
00719 }
00720
00721
00722
00723