diff --git a/kern/conf/conf.kern b/kern/conf/conf.kern index 48ed457..093b676 100644 --- a/kern/conf/conf.kern +++ b/kern/conf/conf.kern @@ -438,3 +438,8 @@ file test/semunit.c file test/kmalloctest.c file test/fstest.c optfile net test/nettest.c + +defoption synchprobs +optfile synchprobs synchprobs/whalemating.c +optfile synchprobs synchprobs/stoplight.c +optfile synchprobs test/synchprobs.c diff --git a/kern/include/synchprobs.h b/kern/include/synchprobs.h new file mode 100644 index 0000000..10c9a92 --- /dev/null +++ b/kern/include/synchprobs.h @@ -0,0 +1,28 @@ +#ifndef _SYNCHPROBS_H_ +#define _SYNCHPROBS_H_ + +/* + * Synchronization problem primitives. + */ + +/* + * whalemating.c. + */ + +void whalemating_init(void); +void whalemating_cleanup(void); +void male(void *, unsigned long); +void female(void *, unsigned long); +void matchmaker(void *, unsigned long); + +/* + * stoplight.c. + */ + +void gostraight(void *, unsigned long); +void turnleft(void *, unsigned long); +void turnright(void *, unsigned long); +void stoplight_init(void); +void stoplight_cleanup(void); + +#endif /* _SYNCHPROBS_H_ */ diff --git a/kern/include/test.h b/kern/include/test.h index 2437e78..049ace6 100644 --- a/kern/include/test.h +++ b/kern/include/test.h @@ -30,6 +30,8 @@ #ifndef _TEST_H_ #define _TEST_H_ +#include "opt-synchprobs.h" + /* * Declarations for test code and other miscellaneous high-level * functions. @@ -105,5 +107,24 @@ void menu(char *argstr); /* The main function, called from start.S. */ void kmain(char *bootstring); +#if OPT_SYNCHPROBS + +/* + * Synchronization driver primitives. + */ + +void male_start(void); +void male_end(void); +void female_start(void); +void female_end(void); +void matchmaker_start(void); +void matchmaker_end(void); +int whalemating(int, char **); + +void inQuadrant(int); +void leaveIntersection(void); +int stoplight(int, char **); + +#endif #endif /* _TEST_H_ */ diff --git a/kern/main/menu.c b/kern/main/menu.c index 91cd393..c74e6e0 100644 --- a/kern/main/menu.c +++ b/kern/main/menu.c @@ -44,6 +44,7 @@ #include #include "opt-sfs.h" #include "opt-net.h" +#include "opt-synchprobs.h" /* * In-kernel menu and command dispatcher. @@ -478,6 +479,10 @@ static const char *testmenu[] = { "[sy3] CV test (1) ", "[sy4] CV test #2 (1) ", "[sy5] RW lock test (1) ", +#if OPT_SYNCHPROBS + "[sp1] Whalemating test (1) ", + "[sp2] Stoplight test (1) ", +#endif "[semu1-22] Semaphore unit tests ", "[fs1] Filesystem test ", "[fs2] FS read stress ", @@ -581,6 +586,10 @@ static struct { { "sy3", cvtest }, { "sy4", cvtest2 }, { "sy5", rwtest }, +#if OPT_SYNCHPROBS + { "sp1", whalemating }, + { "sp2", stoplight }, +#endif /* semaphore unit tests */ { "semu1", semu1 }, diff --git a/kern/synchprobs/stoplight.c b/kern/synchprobs/stoplight.c new file mode 100644 index 0000000..15ad3c9 --- /dev/null +++ b/kern/synchprobs/stoplight.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2001, 2002, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver code is in kern/tests/synchprobs.c We will + * replace that file. This file is yours to modify as you see fit. + * + * You should implement your solution to the stoplight problem below. The + * quadrant and direction mappings for reference: (although the problem is, + * of course, stable under rotation) + * + * | 0 | + * -- -- + * 0 1 + * 3 1 + * 3 2 + * -- -- + * | 2 | + * + * As way to think about it, assuming cars drive on the right: a car entering + * the intersection from direction X will enter intersection quadrant X + * first. + * + * You will probably want to write some helper functions to assist + * with the mappings. Modular arithmetic can help, e.g. a car passing + * straight through the intersection entering from direction X will leave to + * direction (X + 2) % 4 and pass through quadrants X and (X + 3) % 4. + * Boo-yah. + * + * Your solutions below should call the inQuadrant() and leaveIntersection() + * functions in synchprobs.c to record their progress. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Called by the driver during initialization. + */ + +void +stoplight_init() { + return; +} + +/* + * Called by the driver during teardown. + */ + +void stoplight_cleanup() { + return; +} + +void +gostraight(void *p, unsigned long direction) +{ + struct semaphore * stoplightMenuSemaphore = (struct semaphore *)p; + (void)direction; + + /* + * Implement this function. + */ + + /* + * This code allows the test to return to the menu cleanly. + */ + V(stoplightMenuSemaphore); + return; +} + +void +turnleft(void *p, unsigned long direction) +{ + struct semaphore * stoplightMenuSemaphore = (struct semaphore *)p; + (void)direction; + + /* + * Implement this function. + */ + + /* + * This code allows the test to return to the menu cleanly. + */ + V(stoplightMenuSemaphore); + return; +} + +void +turnright(void *p, unsigned long direction) +{ + struct semaphore * stoplightMenuSemaphore = (struct semaphore *)p; + (void)direction; + + /* + * Implement this function. + */ + + /* + * This code allows the test to return to the menu cleanly. + */ + V(stoplightMenuSemaphore); + return; +} diff --git a/kern/synchprobs/whalemating.c b/kern/synchprobs/whalemating.c new file mode 100644 index 0000000..5fb15a5 --- /dev/null +++ b/kern/synchprobs/whalemating.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2001, 2002, 2009 + * The President and Fellows of Harvard College. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Driver code is in kern/tests/synchprobs.c We will + * replace that file. This file is yours to modify as you see fit. + * + * You should implement your solution to the whalemating problem below. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Called by the driver during initialization. + */ + +void whalemating_init() { + return; +} + +/* + * Called by the driver during teardown. + */ + +void +whalemating_cleanup() { + return; +} + +void +male(void *p, unsigned long which) +{ + struct semaphore * whalematingMenuSemaphore = (struct semaphore *)p; + (void)which; + + male_start(); + /* + * Implement this function. + */ + male_end(); + + /* + * This code allows the test to return to the menu cleanly. + */ + V(whalematingMenuSemaphore); + return; +} + +void +female(void *p, unsigned long which) +{ + struct semaphore * whalematingMenuSemaphore = (struct semaphore *)p; + (void)which; + + female_start(); + /* + * Implement this function. + */ + female_end(); + + /* + * This code allows the test to return to the menu cleanly. + */ + V(whalematingMenuSemaphore); + return; +} + +void +matchmaker(void *p, unsigned long which) +{ + struct semaphore * whalematingMenuSemaphore = (struct semaphore *)p; + (void)which; + + matchmaker_start(); + /* + * Implement this function. + */ + matchmaker_end(); + + /* + * This code allows the test to return to the menu cleanly. + */ + V(whalematingMenuSemaphore); + return; +} diff --git a/kern/test/synchprobs.c b/kern/test/synchprobs.c new file mode 100644 index 0000000..5942e88 --- /dev/null +++ b/kern/test/synchprobs.c @@ -0,0 +1,202 @@ +/* + * 08 Feb 2012 : GWA : Please make any changes necessary to test your code to + * the drivers in this file. However, the automated testing suite *will + * replace this file in its entirety* with driver code intented to stress + * test your synchronization problem solutions. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define PROBLEMS_MAX_YIELDER 16 +#define PROBLEMS_MAX_SPINNER 8192 + +/* + * 08 Feb 2012 : GWA : Driver code for the whalemating problem. + */ + +/* + * 08 Feb 2012 : GWA : The following functions are for you to use when each + * whale starts and completes either mating (if it is a male or female) or + * matchmaking. We will use the output from these functions to verify the to + * verify the correctness of your solution. These functions may spin for + * arbitrary periods of time or yield. + */ + +inline void male_start(void) { + random_yielder(PROBLEMS_MAX_YIELDER); + kprintf("%s starting\n", curthread->t_name); +} + +inline void male_end(void) { + kprintf("%s ending\n", curthread->t_name); +} + +inline void female_start(void) { + random_spinner(PROBLEMS_MAX_SPINNER); + kprintf("%s starting\n", curthread->t_name); +} + +inline void female_end(void) { + kprintf("%s ending\n", curthread->t_name); +} + +inline void matchmaker_start(void) { + random_yielder(PROBLEMS_MAX_YIELDER); + kprintf("%s starting\n", curthread->t_name); +} + +inline void matchmaker_end(void) { + kprintf("%s ending\n", curthread->t_name); +} + +/* + * 08 Feb 2012 : GWA : The following function drives the entire whalemating + * process. Feel free to modify at will, but make no assumptions about the + * order or timing of threads launched by our testing suite. + */ + +#define NMATING 10 + +struct semaphore * whalematingMenuSemaphore; + +int whalemating(int nargs, char **args) { + (void) nargs; + (void) args; + + int i, j, err = 0; + char name[32]; + + whalematingMenuSemaphore = sem_create("Whalemating Driver Semaphore", + 0); + if (whalematingMenuSemaphore == NULL ) { + panic("whalemating: sem_create failed.\n"); + } + + whalemating_init(); + + for (i = 0; i < 3; i++) { + for (j = 0; j < NMATING; j++) { + + random_yielder(PROBLEMS_MAX_YIELDER); + + switch (i) { + case 0: + snprintf(name, sizeof(name), "Male Whale Thread %d", (i * 3) + j); + err = thread_fork(name, NULL, male, whalematingMenuSemaphore, j); + break; + case 1: + snprintf(name, sizeof(name), "Female Whale Thread %d", (i * 3) + j); + err = thread_fork(name, NULL, female, whalematingMenuSemaphore, j); + break; + case 2: + snprintf(name, sizeof(name), "Matchmaker Whale Thread %d", (i * 3) + j); + err = thread_fork(name, NULL, matchmaker, whalematingMenuSemaphore, j); + break; + } + if (err) { + panic("whalemating: thread_fork failed: (%s)\n", strerror(err)); + } + } + } + + for (i = 0; i < 3; i++) { + for (j = 0; j < NMATING; j++) { + P(whalematingMenuSemaphore); + } + } + + sem_destroy(whalematingMenuSemaphore); + whalemating_cleanup(); + + return 0; +} + +/* + * 08 Feb 2012 : GWA : Driver code for the stoplight problem. + */ + +/* + * 08 Feb 2012 : GWA : The following functions should be called by your + * stoplight solution when a car is in an intersection quadrant. The + * semantics of the problem are that once a car enters any quadrant it has to + * be somewhere in the intersection until it call leaveIntersection(), which + * it should call while in the final quadrant. + * + * As an example, let's say a car approaches the intersection and needs to + * pass through quadrants 0, 3 and 2. Once you call inQuadrant(0), the car is + * considered in quadrant 0 until you call inQuadrant(3). After you call + * inQuadrant(2), the car is considered in quadrant 2 until you call + * leaveIntersection(). + * + * As in the whalemating example, we will use the output from these functions + * to verify the correctness of your solution. These functions may spin for + * arbitrary periods of time or yield. + */ + +inline void inQuadrant(int quadrant) { + random_spinner(PROBLEMS_MAX_SPINNER); + kprintf("%s in quadrant %d\n", curthread->t_name, quadrant); +} + +inline void leaveIntersection() { + kprintf("%s left the intersection\n", curthread->t_name); +} + +#define NCARS 99 + +struct semaphore * stoplightMenuSemaphore; + +int stoplight(int nargs, char **args) { + (void) nargs; + (void) args; + int i, direction, turn, err = 0; + char name[32]; + + stoplightMenuSemaphore = sem_create("Stoplight Driver Semaphore", 0); + if (stoplightMenuSemaphore == NULL ) { + panic("stoplight: sem_create failed.\n"); + } + + stoplight_init(); + + for (i = 0; i < NCARS; i++) { + + direction = random() % 4; + turn = random() % 3; + + snprintf(name, sizeof(name), "Car Thread %d", i); + + switch (turn) { + + random_yielder(PROBLEMS_MAX_YIELDER); + + case 0: + err = thread_fork(name, NULL, gostraight, stoplightMenuSemaphore, direction); + break; + case 1: + err = thread_fork(name, NULL, turnleft, stoplightMenuSemaphore, direction); + break; + case 2: + err = thread_fork(name, NULL, turnright, stoplightMenuSemaphore, direction); + break; + } + if (err) { + panic("stoplight: thread_fork failed: (%s)\n", strerror(err)); + } + } + + for (i = 0; i < NCARS; i++) { + P(stoplightMenuSemaphore); + } + + sem_destroy(stoplightMenuSemaphore); + stoplight_cleanup(); + + return 0; +}