catmouse.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. /*
  2. * catmouse.c
  3. *
  4. * 30-1-2003 : GWA : Stub functions created for CS161 Asst1.
  5. * 26-11-2007: KMS : Modified to use cat_eat and mouse_eat
  6. * 21-04-2009: KMS : modified to use cat_sleep and mouse_sleep
  7. * 21-04-2009: KMS : added sem_destroy of CatMouseWait
  8. * 05-01-2012: TBB : added comments to try to clarify use/non use of volatile
  9. * 22-08-2013: TBB: made cat and mouse eating and sleeping time optional parameters
  10. * 27-04-2014: KMS: change this to simulation driver that invokes student-implemented synch functions
  11. * 26-01-2015: TBB: adding info about which cat and mouse are eating to be used for debugging
  12. *
  13. */
  14. /*
  15. * CS350 Students Note!
  16. *
  17. * You may not modify the code in this file in any way!
  18. *
  19. */
  20. /*
  21. *
  22. * Includes
  23. *
  24. */
  25. #include <types.h>
  26. #include <lib.h>
  27. #include <test.h>
  28. #include <clock.h>
  29. #include <thread.h>
  30. #include <synch.h>
  31. #include <synchprobs.h>
  32. /* An animal number that won't ever be used */
  33. #define INVALID_ANIMAL_NUM (999999)
  34. /* Useful for debugging */
  35. static int do_print_state = 0;
  36. /* functions defined and used internally */
  37. static void initialize_bowls(void);
  38. static void cleanup_bowls(void);
  39. static void cat_eat(unsigned int bowlnumber, int eat_time, unsigned int cat_num);
  40. static void cat_sleep(int sleep_time);
  41. static void mouse_eat(unsigned int bowlnumber, int eat_time, unsigned int mouse_num);
  42. static void mouse_sleep(int sleep_time);
  43. static void cat_simulation(void *ptr, unsigned long catnumber);
  44. static void mouse_simulation(void *ptr, unsigned long mousenumber);
  45. static void print_state(void);
  46. /*
  47. *
  48. * Problem parameters
  49. *
  50. * Values for these parameters are set by the main driver
  51. * function, catmouse(), based on the problem parameters
  52. * that are passed in from the kernel menu command or
  53. * kernel command line.
  54. * changing them.
  55. *
  56. * These are only ever modified by one thread, at creation time,
  57. * so they do not need to be volatile.
  58. */
  59. static int NumBowls; // number of food bowls
  60. static int NumCats; // number of cats
  61. static int NumMice; // number of mice
  62. static int NumLoops; // number of times each cat and mouse should eat
  63. static int CatEatTime = 1; // length of time a cat spends eating
  64. static int CatSleepTime = 2; // length of time a cat spends sleeping
  65. static int MouseEatTime = 1; // length of time a mouse spends eating
  66. static int MouseSleepTime = 2; // length of time a mouse spends sleeping
  67. /*
  68. * Once the main driver function (catmouse()) has created the cat and mouse
  69. * simulation threads, it uses this semaphore to block until all of the
  70. * cat and mouse simulations are finished.
  71. */
  72. static struct semaphore *CatMouseWait;
  73. /*
  74. *
  75. * shared simulation state
  76. *
  77. * note: this is state should be used only by the
  78. * functions in this file, hence the static declarations
  79. *
  80. */
  81. /* An array with of structs with one entry for each bowl
  82. * bowl[i-1].animal = 'c' if a cat is eating at the ith bowl
  83. * bowl[i-1].animal = 'm' if a mouse is eating at the ith bowl
  84. * bowl[i-1].animal = '-' otherwise
  85. *
  86. * If
  87. * bowl[i-1].animal = 'c'
  88. * bowl[i-1].which = 1 means that cat 1 is eating at bowl[i-1]
  89. * If
  90. * bowl[i-1].animal = '-'
  91. * bowl[i-1].which = INVALID_ANIMAL_NUM
  92. */
  93. /* The elements within the structure can be changed by multiple
  94. * threads so the contents are volatile.
  95. */
  96. struct bowl {
  97. volatile char animal; /* 'c' for cat, 'm' for mouse */
  98. volatile unsigned int which; /* Which cat or mouse */
  99. };
  100. struct bowl *bowls;
  101. /* how many cats are currently eating?
  102. * modified by multiple threads, so volatile
  103. */
  104. static volatile int eating_cats_count;
  105. /* how many mice are currently eating?
  106. * modified by different threads, so volatile
  107. */
  108. static volatile int eating_mice_count;
  109. /* semaphore used to provide mutual exclusion
  110. * for reading and writing the shared simulation state
  111. * The actual mutex is created/initizliaed by one thread and not
  112. * modified by others: not volatile
  113. */
  114. static struct semaphore *mutex;
  115. /* performance statistics */
  116. static volatile time_t cat_total_wait_secs;
  117. static volatile uint32_t cat_total_wait_nsecs;
  118. static volatile int cat_wait_count;
  119. static volatile time_t mouse_total_wait_secs;
  120. static volatile uint32_t mouse_total_wait_nsecs;
  121. static volatile int mouse_wait_count;
  122. /* mutex to provide mutual exclusion to performance stats */
  123. static struct semaphore *perf_mutex;
  124. /*
  125. * initialize_bowls()
  126. *
  127. * Purpose:
  128. * initializes simulation of cats and mice and bowls
  129. *
  130. * Arguments:
  131. * unsigned int bowlcount: the number of food bowls to simulate
  132. *
  133. * Returns:
  134. * 0 on success, 1 otherwise
  135. */
  136. static void
  137. initialize_bowls()
  138. {
  139. int i;
  140. KASSERT(NumBowls > 0);
  141. bowls = kmalloc(NumBowls*sizeof(struct bowl));
  142. if (bowls == NULL) {
  143. panic("initialize_bowls: unable to allocate space for %d bowls\n",NumBowls);
  144. }
  145. /* initialize bowls */
  146. for(i=0;i<NumBowls;i++) {
  147. bowls[i].animal = '-';
  148. bowls[i].which = INVALID_ANIMAL_NUM;
  149. }
  150. eating_cats_count = eating_mice_count = 0;
  151. /* intialize mutex semaphore */
  152. mutex = sem_create("bowl mutex",1);
  153. if (mutex == NULL) {
  154. panic("initialize_bowls: could not create mutex\n");
  155. }
  156. /* intialize perf_mutex semaphore */
  157. perf_mutex = sem_create("stats mutex",1);
  158. if (perf_mutex == NULL) {
  159. panic("initialize_bowls: could not create perf_mutex\n");
  160. }
  161. cat_total_wait_secs = 0;
  162. cat_total_wait_nsecs = 0;
  163. cat_wait_count = 0;
  164. mouse_total_wait_secs = 0;
  165. mouse_total_wait_nsecs = 0;
  166. mouse_wait_count = 0;
  167. return;
  168. }
  169. /*
  170. * cleanup_bowls()
  171. *
  172. * Purpose:
  173. * Releases resources created by initialize_bowls.
  174. *
  175. * Arguments:
  176. * None
  177. *
  178. * Returns:
  179. * Nothing
  180. */
  181. static void
  182. cleanup_bowls()
  183. {
  184. if (mutex != NULL) {
  185. sem_destroy( mutex );
  186. mutex = NULL;
  187. }
  188. if (perf_mutex != NULL) {
  189. sem_destroy( perf_mutex );
  190. perf_mutex = NULL;
  191. }
  192. if (bowls != NULL) {
  193. kfree( (void *) bowls );
  194. bowls = NULL;
  195. }
  196. }
  197. /*
  198. * print_state_on/off()
  199. *
  200. * Purpose:
  201. * Turn the printing of the simulation state on/off.
  202. *
  203. * Arguments:
  204. * none
  205. *
  206. * Returns:
  207. * nothing
  208. */
  209. void
  210. print_state_on()
  211. {
  212. do_print_state = 1;
  213. }
  214. void
  215. print_state_off()
  216. {
  217. do_print_state = 0;
  218. }
  219. /*
  220. * print_state()
  221. *
  222. * Purpose:
  223. * displays the simulation state
  224. *
  225. * Arguments:
  226. * none
  227. *
  228. * Returns:
  229. * nothing
  230. *
  231. * Notes:
  232. * this assumes that it is being called from within
  233. * a critical section - it does not provide its own
  234. * mutual exclusion
  235. */
  236. static void
  237. print_state()
  238. {
  239. int i;
  240. if (NumCats > 100 || NumMice > 100) {
  241. panic("Formatting is set up to only handle two digit numbers for cat and mice numbers\n");
  242. }
  243. if (!do_print_state) {
  244. return;
  245. }
  246. kprintf(" Eating Cats: %3d Eating Mice: %3d ",eating_cats_count,
  247. eating_mice_count);
  248. for(i=0;i<NumBowls;i++) {
  249. kprintf("%c",bowls[i].animal);
  250. if (bowls[i].which == INVALID_ANIMAL_NUM) {
  251. kprintf("%2s", "--");
  252. } else {
  253. kprintf("%02d",bowls[i].which);
  254. }
  255. kprintf(" ");
  256. }
  257. kprintf("\n");
  258. return;
  259. }
  260. /*
  261. * cat_eat()
  262. *
  263. * Purpose:
  264. * simulates a cat eating from a bowl, and checks to
  265. * make sure that none of the simulation requirements
  266. * have been violated.
  267. *
  268. * Arguments:
  269. * unsigned int bowlnumber: which bowl the cat should eat from
  270. * int eat_time: how long to eat
  271. * unsigned int cat_num: which cat is eating (used for debugging)
  272. *
  273. * Returns:
  274. * nothing
  275. *
  276. */
  277. void
  278. cat_eat(unsigned int bowlnumber, int eat_time, unsigned int cat_num)
  279. {
  280. /* check the bowl number */
  281. KASSERT(bowlnumber > 0);
  282. KASSERT((int)bowlnumber <= NumBowls);
  283. /* check and update the simulation state to indicate that
  284. * the cat is now eating at the specified bowl */
  285. P(mutex);
  286. /* first check whether allowing this cat to eat will
  287. * violate any simulation requirements */
  288. if (bowls[bowlnumber-1].animal == 'c') {
  289. /* there is already a cat eating at the specified bowl */
  290. panic("cat_eat: attempt to make cat %d eat from bowl %d while cat %d is already eating there!\n",
  291. cat_num, bowlnumber, bowls[bowlnumber-1].which);
  292. }
  293. if (eating_mice_count > 0) {
  294. /* there is already a mouse eating at some bowl */
  295. panic("cat_eat: attempt to make cat %d eat while mice are eating!\n", cat_num);
  296. }
  297. KASSERT(bowls[bowlnumber-1].animal == '-');
  298. KASSERT(bowls[bowlnumber-1].which == INVALID_ANIMAL_NUM);
  299. KASSERT(eating_mice_count == 0);
  300. /* now update the state to indicate that the cat is eating */
  301. eating_cats_count += 1;
  302. bowls[bowlnumber-1].animal = 'c';
  303. bowls[bowlnumber-1].which = cat_num;
  304. print_state();
  305. DEBUG(DB_SYNCPROB,"cat %d starts to eat at bowl %d [%d:%d]\n",
  306. cat_num, bowlnumber, eating_cats_count, eating_mice_count);
  307. V(mutex); // end critical section
  308. /* simulate eating by introducing a delay
  309. * note that eating is not part of the critical section */
  310. clocksleep(eat_time);
  311. /* update the simulation state to indicate that
  312. * the cat is finished eating */
  313. P(mutex); // start critical section
  314. KASSERT(eating_cats_count > 0);
  315. KASSERT(bowls[bowlnumber-1].animal=='c');
  316. eating_cats_count -= 1;
  317. bowls[bowlnumber-1].animal='-';
  318. bowls[bowlnumber-1].which=INVALID_ANIMAL_NUM;
  319. print_state();
  320. DEBUG(DB_SYNCPROB,"cat %d finished eating at bowl %d [%d:%d]\n",
  321. cat_num,bowlnumber,eating_cats_count,eating_mice_count);
  322. V(mutex); // end critical section
  323. return;
  324. }
  325. /*
  326. * cat_sleep()
  327. *
  328. * Purpose:
  329. * simulates a cat sleeping
  330. *
  331. * Arguments: none
  332. *
  333. * Returns: nothing
  334. *
  335. */
  336. void
  337. cat_sleep(int sleep_time)
  338. {
  339. /* simulate sleeping by introducing a delay */
  340. clocksleep(sleep_time);
  341. return;
  342. }
  343. /*
  344. * mouse_eat()
  345. *
  346. * Purpose:
  347. * simulates a mouse eating from a bowl, and checks to
  348. * make sure that none of the simulation requirements
  349. * have been violated.
  350. *
  351. * Arguments:
  352. * unsigned int bowlnumber: which bowl the mouse should eat from
  353. * int eat_time: how long to eat for
  354. * unsigned int mouse_num: which mouse is eating (for debugging)
  355. *
  356. * Returns:
  357. * nothing
  358. *
  359. */
  360. void
  361. mouse_eat(unsigned int bowlnumber, int eat_time, unsigned int mouse_num)
  362. {
  363. /* check the bowl number */
  364. KASSERT(bowlnumber > 0);
  365. KASSERT((int)bowlnumber <= NumBowls);
  366. /* check and updated the simulation state to indicate that
  367. * the mouse is now eating at the specified bowl. */
  368. P(mutex); // start critical section
  369. /* first check whether allowing this mouse to eat will
  370. * violate any simulation requirements */
  371. if (bowls[bowlnumber-1].animal == 'm') {
  372. /* there is already a mouse eating at the specified bowl */
  373. panic("mouse_eat: attempt to make mouse %d eat from bowl %d while mouse %d is there!\n",
  374. mouse_num, bowlnumber, bowls[bowlnumber-1].which);
  375. }
  376. if (eating_cats_count > 0) {
  377. /* there is already a cat eating at some bowl */
  378. panic("mouse_eat: attempt to make mouse %d eat while cats are eating!\n", mouse_num);
  379. }
  380. KASSERT(bowls[bowlnumber-1].animal=='-');
  381. KASSERT(bowls[bowlnumber-1].which==INVALID_ANIMAL_NUM);
  382. KASSERT(eating_cats_count == 0);
  383. /* now update the state to indicate that the mouse is eating */
  384. eating_mice_count += 1;
  385. bowls[bowlnumber-1].animal = 'm';
  386. bowls[bowlnumber-1].which = mouse_num;
  387. print_state();
  388. DEBUG(DB_SYNCPROB,"mouse %d starts to eat at bowl %d [%d:%d]\n",
  389. mouse_num,bowlnumber,eating_cats_count,eating_mice_count);
  390. V(mutex); // end critical section
  391. /* simulate eating by introducing a delay
  392. * note that eating is not part of the critical section */
  393. clocksleep(eat_time);
  394. /* update the simulation state to indicate that
  395. * the mouse is finished eating */
  396. P(mutex); // start critical section
  397. KASSERT(eating_mice_count > 0);
  398. eating_mice_count -= 1;
  399. KASSERT(bowls[bowlnumber-1].animal=='m');
  400. KASSERT(bowls[bowlnumber-1].which==mouse_num);
  401. bowls[bowlnumber-1].animal='-';
  402. bowls[bowlnumber-1].which=INVALID_ANIMAL_NUM;
  403. print_state();
  404. DEBUG(DB_SYNCPROB,"mouse %d finishes eating at bowl %d [%d:%d]\n",
  405. mouse_num,bowlnumber,eating_cats_count,eating_mice_count);
  406. V(mutex); // end critical section
  407. return;
  408. }
  409. /*
  410. * mouse_sleep()
  411. *
  412. * Purpose:
  413. * simulates a mouse sleeping
  414. *
  415. * Arguments: none
  416. *
  417. * Returns: nothing
  418. *
  419. */
  420. void
  421. mouse_sleep(int sleep_time)
  422. {
  423. /* simulate sleeping by introducing a delay */
  424. clocksleep(sleep_time);
  425. return;
  426. }
  427. /*
  428. * cat_simulation()
  429. *
  430. * Arguments:
  431. * void * unusedpointer: currently unused.
  432. * unsigned long catnumber: holds cat identifier from 0 to NumCats-1.
  433. *
  434. * Returns:
  435. * nothing.
  436. *
  437. * Notes:
  438. * Each cat simulation thread runs this function.
  439. *
  440. */
  441. static
  442. void
  443. cat_simulation(void * unusedpointer,
  444. unsigned long catnumber)
  445. {
  446. int i;
  447. unsigned int bowl;
  448. time_t before_sec, after_sec, wait_sec;
  449. uint32_t before_nsec, after_nsec, wait_nsec;
  450. /* avoid unused variable warnings. */
  451. (void) unusedpointer;
  452. (void) catnumber;
  453. for(i=0;i<NumLoops;i++) {
  454. /* make the cat sleep */
  455. cat_sleep(CatSleepTime);
  456. /* choose bowl. legal bowl numbers range from 1 to NumBowls */
  457. bowl = ((unsigned int)random() % NumBowls) + 1;
  458. gettime(&before_sec,&before_nsec);
  459. cat_before_eating(bowl); /* student-implemented function */
  460. gettime(&after_sec,&after_nsec);
  461. /* make the cat eat */
  462. cat_eat(bowl, CatEatTime, catnumber);
  463. cat_after_eating(bowl); /* student-implemented function */
  464. /* update wait time statistics */
  465. getinterval(before_sec,before_nsec,after_sec,after_nsec,&wait_sec,&wait_nsec);
  466. P(perf_mutex);
  467. cat_total_wait_secs += wait_sec;
  468. cat_total_wait_nsecs += wait_nsec;
  469. if (cat_total_wait_nsecs > 1000000000) {
  470. cat_total_wait_nsecs -= 1000000000;
  471. cat_total_wait_secs ++;
  472. }
  473. cat_wait_count++;
  474. V(perf_mutex);
  475. }
  476. /* indicate that this cat simulation is finished */
  477. V(CatMouseWait);
  478. }
  479. /*
  480. * mouse_simulation()
  481. *
  482. * Arguments:
  483. * void * unusedpointer: currently unused.
  484. * unsigned long mousenumber: holds mouse identifier from 0 to NumMice-1.
  485. *
  486. * Returns:
  487. * nothing.
  488. *
  489. * Notes:
  490. * each mouse simulation thread runs this function
  491. *
  492. */
  493. static
  494. void
  495. mouse_simulation(void * unusedpointer,
  496. unsigned long mousenumber)
  497. {
  498. int i;
  499. unsigned int bowl;
  500. time_t before_sec, after_sec, wait_sec;
  501. uint32_t before_nsec, after_nsec, wait_nsec;
  502. /* Avoid unused variable warnings. */
  503. (void) unusedpointer;
  504. (void) mousenumber;
  505. for(i=0;i<NumLoops;i++) {
  506. /* make the mouse sleep */
  507. mouse_sleep(MouseSleepTime);
  508. /* choose bowl. legal bowl numbers range from 1 to NumBowls */
  509. bowl = ((unsigned int)random() % NumBowls) + 1;
  510. gettime(&before_sec,&before_nsec);
  511. mouse_before_eating(bowl); /* student-implemented function */
  512. gettime(&after_sec,&after_nsec);
  513. /* make the mouse eat */
  514. mouse_eat(bowl, MouseEatTime, mousenumber);
  515. mouse_after_eating(bowl); /* student-implemented function */
  516. /* update wait time statistics */
  517. getinterval(before_sec,before_nsec,after_sec,after_nsec,&wait_sec,&wait_nsec);
  518. P(perf_mutex);
  519. mouse_total_wait_secs += wait_sec;
  520. mouse_total_wait_nsecs += wait_nsec;
  521. if (mouse_total_wait_nsecs > 1000000000) {
  522. mouse_total_wait_nsecs -= 1000000000;
  523. mouse_total_wait_secs ++;
  524. }
  525. mouse_wait_count++;
  526. V(perf_mutex);
  527. }
  528. /* indicate that this mouse is finished */
  529. V(CatMouseWait);
  530. }
  531. /*
  532. * catmouse()
  533. *
  534. * Arguments:
  535. * int nargs: should be 5 or 9
  536. * char ** args: args[1] = number of food bowls
  537. * args[2] = number of cats
  538. * args[3] = number of mice
  539. * args[4] = number of loops
  540. * Optional parameters
  541. * args[5] = cat eating time
  542. * args[6] = cat sleeping time
  543. * args[7] = mouse eating time
  544. * args[8] = mouse sleeping time
  545. *
  546. * Returns:
  547. * 0 on success.
  548. *
  549. * Notes:
  550. * Driver code to start up cat_simulation() and
  551. * mouse_simulation() threads.
  552. */
  553. int
  554. catmouse(int nargs,
  555. char ** args)
  556. {
  557. int catindex, mouseindex, error;
  558. int i;
  559. int mean_cat_wait_usecs, mean_mouse_wait_usecs;
  560. time_t before_sec, after_sec, wait_sec;
  561. uint32_t before_nsec, after_nsec, wait_nsec;
  562. int total_bowl_milliseconds, total_eating_milliseconds, utilization_percent;
  563. /* check and process command line arguments */
  564. if ((nargs != 9) && (nargs != 5)) {
  565. kprintf("Usage: <command> NUM_BOWLS NUM_CATS NUM_MICE NUM_LOOPS\n");
  566. kprintf("or\n");
  567. kprintf("Usage: <command> NUM_BOWLS NUM_CATS NUM_MICE NUM_LOOPS ");
  568. kprintf("CAT_EATING_TIME CAT_SLEEPING_TIME MOUSE_EATING_TIME MOUSE_SLEEPING_TIME\n");
  569. return 1; // return failure indication
  570. }
  571. /* check the problem parameters, and set the global variables */
  572. NumBowls = atoi(args[1]);
  573. if (NumBowls <= 0) {
  574. kprintf("catmouse: invalid number of bowls: %d\n",NumBowls);
  575. return 1;
  576. }
  577. NumCats = atoi(args[2]);
  578. if (NumCats < 0) {
  579. kprintf("catmouse: invalid number of cats: %d\n",NumCats);
  580. return 1;
  581. }
  582. NumMice = atoi(args[3]);
  583. if (NumMice < 0) {
  584. kprintf("catmouse: invalid number of mice: %d\n",NumMice);
  585. return 1;
  586. }
  587. NumLoops = atoi(args[4]);
  588. if (NumLoops <= 0) {
  589. kprintf("catmouse: invalid number of loops: %d\n",NumLoops);
  590. return 1;
  591. }
  592. if (nargs == 9) {
  593. CatEatTime = atoi(args[5]);
  594. if (CatEatTime < 0) {
  595. kprintf("catmouse: invalid cat eating time: %d\n",CatEatTime);
  596. return 1;
  597. }
  598. CatSleepTime = atoi(args[6]);
  599. if (CatSleepTime < 0) {
  600. kprintf("catmouse: invalid cat sleeping time: %d\n",CatSleepTime);
  601. return 1;
  602. }
  603. MouseEatTime = atoi(args[7]);
  604. if (MouseEatTime < 0) {
  605. kprintf("catmouse: invalid mouse eating time: %d\n",MouseEatTime);
  606. return 1;
  607. }
  608. MouseSleepTime = atoi(args[8]);
  609. if (MouseSleepTime < 0) {
  610. kprintf("catmouse: invalid mouse sleeping time: %d\n",MouseSleepTime);
  611. return 1;
  612. }
  613. }
  614. if ((NumMice >= INVALID_ANIMAL_NUM) || (NumCats >= INVALID_ANIMAL_NUM)) {
  615. panic("Trying to use too many cats or mice: limit = %d\n", INVALID_ANIMAL_NUM);
  616. }
  617. kprintf("Using %d bowls, %d cats, and %d mice. Looping %d times.\n",
  618. NumBowls,NumCats,NumMice,NumLoops);
  619. kprintf("Using cat eating time %d, cat sleeping time %d\n", CatEatTime, CatSleepTime);
  620. kprintf("Using mouse eating time %d, mouse sleeping time %d\n", MouseEatTime, MouseSleepTime);
  621. /* create the semaphore that is used to make the main thread
  622. wait for all of the cats and mice to finish */
  623. CatMouseWait = sem_create("CatMouseWait",0);
  624. if (CatMouseWait == NULL) {
  625. panic("catmouse: could not create semaphore\n");
  626. }
  627. /* initialize our simulation state */
  628. initialize_bowls();
  629. /* initialize the synchronization functions */
  630. catmouse_sync_init(NumBowls);
  631. /* get current time, for measuring total simulation time */
  632. gettime(&before_sec,&before_nsec);
  633. /*
  634. * Start NumCats cat_simulation() threads and NumMice mouse_simulation() threads.
  635. * Alternate cat and mouse creation.
  636. */
  637. for (catindex = 0; catindex < NumCats; catindex++) {
  638. error = thread_fork("cat_simulation thread", NULL, cat_simulation, NULL, catindex);
  639. if (error) {
  640. panic("cat_simulation: thread_fork failed: %s\n", strerror(error));
  641. }
  642. if (catindex < NumMice) {
  643. error = thread_fork("mouse_simulation thread", NULL, mouse_simulation, NULL, catindex);
  644. if (error) {
  645. panic("mouse_simulation: thread_fork failed: %s\n",strerror(error));
  646. }
  647. }
  648. }
  649. /* launch any remaining mice */
  650. for(mouseindex = catindex; mouseindex < NumMice; mouseindex++) {
  651. error = thread_fork("mouse_simulation thread", NULL, mouse_simulation, NULL, mouseindex);
  652. if (error) {
  653. panic("mouse_simulation: thread_fork failed: %s\n",strerror(error));
  654. }
  655. }
  656. /* wait for all of the cats and mice to finish before
  657. terminating */
  658. for(i=0;i<(NumCats+NumMice);i++) {
  659. P(CatMouseWait);
  660. }
  661. /* get current time, for measuring total simulation time */
  662. gettime(&after_sec,&after_nsec);
  663. /* compute total simulation time */
  664. getinterval(before_sec,before_nsec,after_sec,after_nsec,&wait_sec,&wait_nsec);
  665. /* compute and report bowl utilization */
  666. total_bowl_milliseconds = (wait_sec*1000 + wait_nsec/1000000)*NumBowls;
  667. total_eating_milliseconds = (NumCats*CatEatTime + NumMice*MouseEatTime)*NumLoops*1000;
  668. if (total_bowl_milliseconds > 0) {
  669. utilization_percent = total_eating_milliseconds*100/total_bowl_milliseconds;
  670. kprintf("STATS: Bowl utilization: %d%%\n",utilization_percent);
  671. }
  672. /* clean up the semaphore that we created */
  673. sem_destroy(CatMouseWait);
  674. /* clean up the synchronization state */
  675. catmouse_sync_cleanup(NumBowls);
  676. /* clean up resources used for tracking bowl use */
  677. cleanup_bowls();
  678. if (cat_wait_count > 0) {
  679. /* some rounding error here - not significant if cat_wait_count << 1000000 */
  680. mean_cat_wait_usecs = (cat_total_wait_secs*1000000+cat_total_wait_nsecs/1000)/cat_wait_count;
  681. kprintf("STATS: Mean cat waiting time: %d.%d seconds\n",
  682. mean_cat_wait_usecs/1000000,mean_cat_wait_usecs%1000000);
  683. }
  684. if (mouse_wait_count > 0) {
  685. /* some rounding error here - not significant if mouse_wait_count << 1000000 */
  686. mean_mouse_wait_usecs = (mouse_total_wait_secs*1000000+mouse_total_wait_nsecs/1000)/mouse_wait_count;
  687. kprintf("STATS: Mean mouse waiting time: %d.%d seconds\n",
  688. mean_mouse_wait_usecs/1000000,mean_mouse_wait_usecs%1000000);
  689. }
  690. return 0;
  691. }
  692. /*
  693. * End of catmouse.c
  694. */