From 5521823176b358204bd031cfd7873421ce8c6b0a Mon Sep 17 00:00:00 2001 From: Geoffrey Challen Date: Wed, 10 Feb 2016 17:03:53 -0500 Subject: [PATCH 1/9] Menu changes and test fixes for ASST1. --- kern/include/test.h | 2 + kern/main/menu.c | 28 ++-- kern/test/synchtest.c | 346 ++++++++++++++++++++++++++---------------- 3 files changed, 237 insertions(+), 139 deletions(-) diff --git a/kern/include/test.h b/kern/include/test.h index 998d25e..1e7f9ef 100644 --- a/kern/include/test.h +++ b/kern/include/test.h @@ -59,6 +59,8 @@ int threadtest2(int, char **); int threadtest3(int, char **); int semtest(int, char **); int locktest(int, char **); +int locktest2(int, char **); +int locktest3(int, char **); int cvtest(int, char **); int cvtest2(int, char **); int rwtest(int, char **); diff --git a/kern/main/menu.c b/kern/main/menu.c index 6f69a14..83f96db 100644 --- a/kern/main/menu.c +++ b/kern/main/menu.c @@ -475,14 +475,16 @@ static const char *testmenu[] = { #if OPT_NET "[net] Network test ", #endif - "[sy1] Semaphore test ", - "[sy2] Lock test (1) ", - "[sy3] CV test (1) ", - "[sy4] CV test #2 (1) ", - "[sy5] RW lock test (1) ", + "[sem1] Semaphore test ", + "[lt1] Lock test 1 (1) ", + "[lt2] Lock test 2 (panics) (1) ", + "[lt3] Lock test 3 (panics) (1) ", + "[cvt1] CV test 1 (1) ", + "[cvt2] CV test 2 (1) ", + "[rwt1] RW lock test (1) ", #if OPT_SYNCHPROBS - "[sp1] Whalemating test (1) ", - "[sp2] Stoplight test (1) ", + "[sp1] Whalemating test (1) ", + "[sp2] Stoplight test (1) ", #endif "[semu1-22] Semaphore unit tests ", "[fs1] Filesystem test ", @@ -607,13 +609,15 @@ static struct { { "tt1", threadtest }, { "tt2", threadtest2 }, { "tt3", threadtest3 }, - { "sy1", semtest }, /* synchronization assignment tests */ - { "sy2", locktest }, - { "sy3", cvtest }, - { "sy4", cvtest2 }, - { "sy5", rwtest }, + { "sem1", semtest }, + { "lt1", locktest }, + { "lt2", locktest2 }, + { "lt3", locktest3 }, + { "cvt1", cvtest }, + { "cvt2", cvtest2 }, + { "rwt1", rwtest }, #if OPT_SYNCHPROBS { "sp1", whalemating }, { "sp2", stoplight }, diff --git a/kern/test/synchtest.c b/kern/test/synchtest.c index 6290921..627f30b 100644 --- a/kern/test/synchtest.c +++ b/kern/test/synchtest.c @@ -40,75 +40,47 @@ #include #include +#define CREATELOOPS 8 #define NSEMLOOPS 63 #define NLOCKLOOPS 120 #define NCVLOOPS 5 #define NTHREADS 32 +#define SYNCHTEST_YIELDER_MAX 16 static volatile unsigned long testval1; static volatile unsigned long testval2; static volatile unsigned long testval3; static volatile int32_t testval4; -static struct semaphore *testsem; -static struct lock *testlock; -static struct cv *testcv; -static struct semaphore *donesem; +static struct semaphore *testsem = NULL; +static struct lock *testlock = NULL; +static struct cv *testcv = NULL; +static struct semaphore *donesem = NULL; struct spinlock status_lock; -static bool test_status; +static bool test_status = FAIL; static unsigned long semtest_current; -static -void -inititems(void) -{ - if (testsem==NULL) { - testsem = sem_create("testsem", 2); - if (testsem == NULL) { - panic("synchtest: sem_create failed\n"); - } - } - if (testlock==NULL) { - testlock = lock_create("testlock"); - if (testlock == NULL) { - panic("synchtest: lock_create failed\n"); - } - } - if (testcv==NULL) { - testcv = cv_create("testlock"); - if (testcv == NULL) { - panic("synchtest: cv_create failed\n"); - } - } - if (donesem==NULL) { - donesem = sem_create("donesem", 0); - if (donesem == NULL) { - panic("synchtest: sem_create failed\n"); - } - } - spinlock_init(&status_lock); -} - - static void semtestthread(void *junk, unsigned long num) { - int i; (void)junk; + int i; + + random_yielder(4); + /* * Only one of these should print at a time. */ - random_yielder(4); P(testsem); semtest_current = num; - kprintf_n("Thread %2lu: ", num); + kprintf_n("Thread %2lu: ", num); for (i=0; i Date: Thu, 11 Feb 2016 01:30:33 -0500 Subject: [PATCH 2/9] Added ksecprintf for securely printing messages from the kernel. If SECRET_TESTING is defined, the function will compute and print a salt value and the hmac/sha256 hash of the message, which can be verified from the test161 server. --- kern/include/kern/secret.h | 2 +- kern/include/test.h | 4 +- kern/test/lib.c | 79 +++++++++++++++++++------------------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/kern/include/kern/secret.h b/kern/include/kern/secret.h index a561058..02d0335 100644 --- a/kern/include/kern/secret.h +++ b/kern/include/kern/secret.h @@ -45,6 +45,6 @@ */ #undef SECRET_TESTING -#define SECRET 0 +#define SECRET "" #endif /* _SECRET_H_ */ diff --git a/kern/include/test.h b/kern/include/test.h index 1e7f9ef..aebefbd 100644 --- a/kern/include/test.h +++ b/kern/include/test.h @@ -174,7 +174,9 @@ int ll16test(int, char **); #define SUCCESS 0 #define FAIL 1 -void success(bool, uint32_t, const char *); +int success(bool, const char *, const char *); + +int ksecprintf(const char *secret, const char *msg, const char *name); void random_yielder(uint32_t); void random_spinner(uint32_t); diff --git a/kern/test/lib.c b/kern/test/lib.c index 5f6a5a5..2fe3711 100644 --- a/kern/test/lib.c +++ b/kern/test/lib.c @@ -3,55 +3,54 @@ #include #include #include +#include /* - * Main success function for kernel tests. Prints a multiple of the secret if - * the secret is non-zero and the test succeeded. Otherwise prints a random - * number. - * - * Ideally we would multiply the secret (a large prime) by another large prime - * to ensure that factoring was hard, but that would require either primality - * testing (slow) or augmenting sys161 with a prime number generator. This is - * sufficient for now to prevent replay attacks. + * Common success function for kernel tests. If SECRET_TESTING is defined, + * ksecprintf will compute the hmac/sha256 hash of any message using the + * shared secret and a random salt value. The (secure) server also knows + * the secret and can verify the message was generated by a trusted source. + * The salt value prevents against replay attacks. */ - -#define MIN_MULTIPLIER 0x80000000 +int +success(bool status, const char * secret, const char * name) { + if (status == SUCCESS) { + return ksecprintf(secret, "SUCCESS", name); + } else { + return ksecprintf(secret, "FAIL", name); + } +} #ifndef SECRET_TESTING -void -success(bool status, uint32_t secret, const char * name) { + +int +ksecprintf(const char * secret, const char * msg, const char * name) +{ (void)secret; - if (status == SUCCESS) { - kprintf("%s: SUCCESS\n", name); - } else { - kprintf("%s: FAIL\n", name); - } - return; + return kprintf("%s: %s\n", name, msg); } + #else -void -success(bool status, uint32_t secret, const char * name) { - uint32_t multiplier; - // Make sure we can get large random numbers - KASSERT(randmax() == 0xffffffff); - while (1) { - multiplier = random(); - // We can at least remove the obvious non-primes... - if (multiplier % 2 == 0) { - continue; - } - if (multiplier > MIN_MULTIPLIER) { - break; - } - } - uint64_t big_secret = (uint64_t) secret * (uint64_t) multiplier; - if (status == SUCCESS) { - kprintf("%s: SUCCESS (%llu)\n", name, big_secret); - } else { - kprintf("%s: FAIL (%llu)\n", name, big_secret); - } - return; + +int +ksecprintf(const char * secret, const char * msg, const char * name) +{ + char *hash; + char *salt; + int res; + + res = hmac_salted(msg, strlen(msg), secret, strlen(secret), &hash, &salt); + if (res) + return -res; + + res = kprintf("(%s, %s, %s, %s: %s)\n", name, hash, salt, name, msg); + + kfree(hash); + kfree(salt); + + return res; } + #endif /* From 875b75bf24cabddf8b9244f49357010551b8318a Mon Sep 17 00:00:00 2001 From: Geoffrey Challen Date: Thu, 11 Feb 2016 13:55:09 -0500 Subject: [PATCH 3/9] Improvements to synchronization tests. --- kern/conf/conf.kern | 1 + kern/include/kern/secret.h | 2 +- kern/include/test.h | 2 + kern/main/menu.c | 4 ++ kern/test/rwtest.c | 18 +++++++ kern/test/synchtest.c | 103 +++++++++++++++++++++++++++++++++---- 6 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 kern/test/rwtest.c diff --git a/kern/conf/conf.kern b/kern/conf/conf.kern index 1fc3aa1..4b4fdaf 100644 --- a/kern/conf/conf.kern +++ b/kern/conf/conf.kern @@ -442,6 +442,7 @@ file test/threadlisttest.c file test/threadtest.c file test/tt3.c file test/synchtest.c +file test/rwtest.c file test/semunit.c file test/hmacunit.c file test/kmalloctest.c diff --git a/kern/include/kern/secret.h b/kern/include/kern/secret.h index 02d0335..16c3903 100644 --- a/kern/include/kern/secret.h +++ b/kern/include/kern/secret.h @@ -45,6 +45,6 @@ */ #undef SECRET_TESTING -#define SECRET "" +#define SECRET "TEST" #endif /* _SECRET_H_ */ diff --git a/kern/include/test.h b/kern/include/test.h index aebefbd..4f81a45 100644 --- a/kern/include/test.h +++ b/kern/include/test.h @@ -63,6 +63,8 @@ int locktest2(int, char **); int locktest3(int, char **); int cvtest(int, char **); int cvtest2(int, char **); +int cvtest3(int, char **); +int cvtest4(int, char **); int rwtest(int, char **); /* semaphore unit tests */ diff --git a/kern/main/menu.c b/kern/main/menu.c index 83f96db..4aeb5db 100644 --- a/kern/main/menu.c +++ b/kern/main/menu.c @@ -481,6 +481,8 @@ static const char *testmenu[] = { "[lt3] Lock test 3 (panics) (1) ", "[cvt1] CV test 1 (1) ", "[cvt2] CV test 2 (1) ", + "[cvt3] CV test 3 (panics) (1) ", + "[cvt4] CV test 4 (panics) (1) ", "[rwt1] RW lock test (1) ", #if OPT_SYNCHPROBS "[sp1] Whalemating test (1) ", @@ -617,6 +619,8 @@ static struct { { "lt3", locktest3 }, { "cvt1", cvtest }, { "cvt2", cvtest2 }, + { "cvt3", cvtest3 }, + { "cvt4", cvtest4 }, { "rwt1", rwtest }, #if OPT_SYNCHPROBS { "sp1", whalemating }, diff --git a/kern/test/rwtest.c b/kern/test/rwtest.c new file mode 100644 index 0000000..e3896d4 --- /dev/null +++ b/kern/test/rwtest.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int rwtest(int nargs, char **args) { + (void)nargs; + (void)args; + + kprintf_n("rwt1 unimplemented\n"); + success(FAIL, SECRET, "rwt1"); + + return 0; +} diff --git a/kern/test/synchtest.c b/kern/test/synchtest.c index 627f30b..31a14b9 100644 --- a/kern/test/synchtest.c +++ b/kern/test/synchtest.c @@ -80,6 +80,7 @@ semtestthread(void *junk, unsigned long num) kprintf_n("Thread %2lu: ", num); for (i=0; i Date: Thu, 11 Feb 2016 14:46:27 -0500 Subject: [PATCH 4/9] Working on synchronization problem code. --- kern/test/rwtest.c | 5 + kern/test/synchprobs.c | 545 ++++++++++++++++++++++++++++++++++++----- kern/test/synchtest.c | 7 + 3 files changed, 497 insertions(+), 60 deletions(-) diff --git a/kern/test/rwtest.c b/kern/test/rwtest.c index e3896d4..9fa3a33 100644 --- a/kern/test/rwtest.c +++ b/kern/test/rwtest.c @@ -1,3 +1,8 @@ +/* + * All the contents of this file are overwritten during automated + * testing. Please consider this before changing anything in this file. + */ + #include #include #include diff --git a/kern/test/synchprobs.c b/kern/test/synchprobs.c index d77aaed..07fec9a 100644 --- a/kern/test/synchprobs.c +++ b/kern/test/synchprobs.c @@ -1,6 +1,4 @@ /* - * NO NOT MODIFY THIS FILE - * * All the contents of this file are overwritten during automated * testing. Please consider this before changing anything in this file. */ @@ -11,28 +9,37 @@ #include #include #include +#include +#include #define PROBLEMS_MAX_YIELDER 16 #define PROBLEMS_MAX_SPINNER 8192 +#define SUCCESS 0 +#define FAIL 1 + /* * Shared initialization routines */ static uint32_t startcount; -static struct lock *startlock; +static struct lock *testlock; static struct cv *startcv; +static struct cv *endcv; static struct semaphore *endsem; +struct spinlock status_lock; +static bool test_status = FAIL; + static void inititems(uint32_t count) { startcount = count; - if (startlock==NULL) { - startlock = lock_create("startlock"); - if (startlock == NULL) { + if (testlock==NULL) { + testlock = lock_create("testlock"); + if (testlock == NULL) { panic("synchprobs: lock_create failed\n"); } } @@ -48,26 +55,78 @@ inititems(uint32_t count) panic("synchprobs: sem_create failed\n"); } } + spinlock_init(&status_lock); +} + +/* + * Helper function to initialize the thread pool. + */ +static +void +initialize_thread(volatile void* threads[], uint32_t index) { + if (threads[index] != NULL) { + test_status = FAIL; + } + threads[index] = curthread->t_stack; +} + +/* + * Helper function to check whether current thread is valid. + */ +static +void +check_thread(volatile void* threads[], uint32_t index) { + if (threads[index] != curthread->t_stack) { + test_status = FAIL; + } } /* * Driver code for the whalemating problem. */ +#define NMATING 10 +#define MALE 0 +#define FEMALE 1 +#define MATCHMAKER 2 +#define CHECK_TIMES 32 + +static volatile int male_start_count; +static volatile int male_end_count; +static volatile int female_start_count; +static volatile int female_end_count; +static volatile int matchmaker_start_count; +static volatile int matchmaker_end_count; +static volatile int match_count; + +static volatile int match_status[3 * NMATING]; +static volatile void* whale_threads[3 * NMATING]; +static volatile int whale_roles[3 * NMATING]; +static struct semaphore *matcher_sem; + +/* + * Enforce male_start() and male_end() called from male thread. + * Similar for female and matchmaker threads + */ +static +void +check_role(uint32_t index, int role) { + if (whale_roles[index] != role) { + test_status = FAIL; + } +} + static void male_wrapper(void * unused1, unsigned long index) { (void)unused1; random_yielder(4); - lock_acquire(startlock); + lock_acquire(testlock); + initialize_thread(whale_threads, (uint32_t)index); + whale_roles[index] = MALE; startcount--; - if (startcount == 0) { - cv_broadcast(startcv, startlock); - } else { - cv_wait(startcv, startlock); - } - lock_release(startlock); + lock_release(testlock); male((uint32_t)index); V(endsem); @@ -76,16 +135,30 @@ male_wrapper(void * unused1, unsigned long index) { void male_start(uint32_t index) { (void)index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, MALE); + male_start_count++; + cv_signal(startcv, testlock); + lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s starting\n", curthread->t_name); + kprintf_t("."); } void male_end(uint32_t index) { (void)index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, MALE); + cv_signal(endcv, testlock); + male_end_count++; + lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s ending\n", curthread->t_name); + kprintf_t("."); } static @@ -94,14 +167,11 @@ female_wrapper(void * unused1, unsigned long index) { (void)unused1; random_yielder(4); - lock_acquire(startlock); + lock_acquire(testlock); + initialize_thread(whale_threads, (uint32_t)index); + whale_roles[index] = FEMALE; startcount--; - if (startcount == 0) { - cv_broadcast(startcv, startlock); - } else { - cv_wait(startcv, startlock); - } - lock_release(startlock); + lock_release(testlock); female((uint32_t)index); V(endsem); @@ -110,53 +180,93 @@ female_wrapper(void * unused1, unsigned long index) { void female_start(uint32_t index) { (void) index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, FEMALE); + female_start_count++; + cv_signal(startcv, testlock); + lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s starting\n", curthread->t_name); + kprintf_t("."); } void female_end(uint32_t index) { (void) index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, FEMALE); + cv_signal(endcv, testlock); + female_end_count++; + lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s ending\n", curthread->t_name); + kprintf_t("."); } static void matchmaker_wrapper(void * unused1, unsigned long index) { (void)unused1; - + random_yielder(4); - lock_acquire(startlock); + lock_acquire(testlock); + initialize_thread(whale_threads, (uint32_t)index); + whale_roles[index] = MATCHMAKER; startcount--; - if (startcount == 0) { - cv_broadcast(startcv, startlock); - } else { - cv_wait(startcv, startlock); - } - lock_release(startlock); + lock_release(testlock); matchmaker((uint32_t)index); V(endsem); - + return; } void matchmaker_start(uint32_t index) { (void)index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, MATCHMAKER); + matchmaker_start_count++; + cv_signal(startcv, testlock); + lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s starting\n", curthread->t_name); + kprintf_t("."); + P(matcher_sem); } void matchmaker_end(uint32_t index) { (void)index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, MATCHMAKER); + + int i = match_count * 3; + match_status[i] = male_start_count - male_end_count; + match_status[i+1] = female_start_count - female_end_count; + match_status[i+2] = matchmaker_start_count - matchmaker_end_count; + + match_count++; + matchmaker_end_count++; + cv_signal(endcv, testlock); + lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s ending\n", curthread->t_name); + kprintf_t("."); } -#define NMATING 10 +static +void +check_zero(int count, const char *name) { + (void)name; + if (count != 0) { + test_status = FAIL; + } +} int whalemating(int nargs, char **args) { @@ -165,13 +275,47 @@ whalemating(int nargs, char **args) { int i, j, err = 0; char name[32]; - - inititems(3 * NMATING); - whalemating_init(); - for (i = 0; i < 3; i++) { + male_start_count = 0 ; + male_end_count = 0 ; + female_start_count = 0 ; + female_end_count = 0 ; + matchmaker_start_count = 0; + matchmaker_end_count = 0; + match_count = 0; + + startcount = 3 * NMATING; + testlock = lock_create("testlock"); + if (testlock == NULL) { + panic("sp1: lock_create failed\n"); + } + startcv = cv_create("startcv"); + if (startcv == NULL) { + panic("sp1: cv_create failed\n"); + } + endcv = cv_create("endcv"); + if (endcv == NULL) { + panic("sp1: cv_create failed\n"); + } + endsem = sem_create("endsem", 0); + if (endsem == NULL) { + panic("sp1: sem_create failed\n"); + } + matcher_sem = sem_create("matcher_sem", 0); + if (matcher_sem == NULL) { + panic("sp1: sem_create failed\n"); + } + spinlock_init(&status_lock); + test_status = FAIL; + + whalemating_init(); + + /* Start males and females only. */ + for (i = 0; i < 2; i++) { for (j = 0; j < NMATING; j++) { + kprintf_t("."); int index = (i * NMATING) + j; + whale_threads[index] = NULL; switch (i) { case 0: snprintf(name, sizeof(name), "Male Whale Thread %d", index); @@ -181,10 +325,6 @@ whalemating(int nargs, char **args) { snprintf(name, sizeof(name), "Female Whale Thread %d", index); err = thread_fork(name, NULL, female_wrapper, NULL, index); break; - case 2: - snprintf(name, sizeof(name), "Matchmaker Whale Thread %d", index); - err = thread_fork(name, NULL, matchmaker_wrapper, NULL, index); - break; } if (err) { panic("whalemating: thread_fork failed: (%s)\n", strerror(err)); @@ -192,14 +332,127 @@ whalemating(int nargs, char **args) { } } + /* Wait for males and females to start. */ + for (i = 0; i < NMATING * 2; i++) { + kprintf_t("."); + lock_acquire(testlock); + cv_wait(startcv, testlock); + lock_release(testlock); + } + + /* Make sure nothing is happening... */ + bool loop_status = SUCCESS; + for (i = 0; i < CHECK_TIMES && loop_status == SUCCESS; ) { + kprintf_t("."); + random_spinner(PROBLEMS_MAX_SPINNER); + lock_acquire(testlock); + if ((male_start_count != NMATING) || (female_start_count != NMATING) || + (matchmaker_start_count + male_end_count + female_end_count + matchmaker_end_count != 0)) { + loop_status = FAIL; + } + lock_release(testlock); + } + if (loop_status == FAIL) { + test_status = FAIL; + goto done; + } + + /* Create the matchmakers */ + for (j = 0; j < NMATING; j++) { + kprintf_t("."); + int index = (2 * NMATING) + j; + whale_threads[index] = NULL; + snprintf(name, sizeof(name), "Matchmaker Whale Thread %d", index); + err = thread_fork(name, NULL, matchmaker_wrapper, NULL, index); + if (err) { + panic("whalemating: thread_fork failed: (%s)\n", strerror(err)); + } + } + + /* + * Release a random number of matchmakers and wait for them and their + * matches to finish. + */ + int pivot = (random() % (NMATING - 2)) + 1; + for (i = 0; i < pivot; i++) { + kprintf_t("."); + V(matcher_sem); + } + for (i = 0; i < 3 * pivot; i++) { + kprintf_t("."); + lock_acquire(testlock); + cv_wait(endcv, testlock); + lock_release(testlock); + } + + /* Make sure nothing else is happening... */ + bool loop_status = SUCCESS; + for (i = 0; i < CHECK_TIMES && loop_status == SUCCESS; ) { + kprintf_t("."); + random_spinner(PROBLEMS_MAX_SPINNER); + lock_acquire(testlock); + if ((male_start_count != NMATING) || (female_start_count != NMATING) || + (male_end_count != pivot) || (female_end_count != pivot) || + (matchmaker_start_count != pivot) || (matchmaker_end_count != pivot)) { + loop_status = FAIL; + } + lock_release(testlock); + } + if (loop_status == FAIL) { + test_status = FAIL; + goto done; + } + + /* + * Release the rest of the matchmakers and wait for everyone to finish. + */ + + for (i = pivot; i < NMATING; i++) { + V(matcher_sem); + } for (i = 0; i < 3; i++) { for (j = 0; j < NMATING; j++) { + kprintf_t("."); P(endsem); } } whalemating_cleanup(); + check_zero(male_start_count - NMATING, "male"); + check_zero(female_start_count - NMATING, "female"); + check_zero(matchmaker_start_count - NMATING, "matchmaker"); + check_zero(male_start_count - male_end_count, "male"); + check_zero(female_start_count - female_end_count, "female"); + check_zero(matchmaker_start_count - matchmaker_end_count, "matchmaker"); + + if (match_count == NMATING) { + for (i = 0; i < NMATING; i++) { + kprintf_t("."); + j = i * 3; + int male = match_status[j]; + int female = match_status[j + 1]; + if (male == 0 || female == 0) { + spinlock_acquire(&status_lock); + test_status = FAIL; + spinlock_release(&status_lock); + } + } + } else { + spinlock_acquire(&status_lock); + test_status = FAIL; + spinlock_release(&status_lock); + } + +done: + lock_destroy(testlock); + cv_destroy(startcv); + cv_destroy(endcv); + sem_destroy(endsem); + sem_destroy(matcher_sem); + + success(test_status, SECRET, "sp1"); + return 0; } @@ -207,19 +460,79 @@ whalemating(int nargs, char **args) { * Driver code for the stoplight problem. */ +#define NCARS 64 +#define NUM_QUADRANTS 4 +#define UNKNOWN_CAR -1 +#define PASSED_CAR -2 + +#define GO_STRAIGHT 0 +#define TURN_LEFT 1 +#define TURN_RIGHT 2 + +static volatile int quadrant_array[NUM_QUADRANTS]; +static volatile int max_car_count; +static volatile int all_quadrant; +static volatile int car_locations[NCARS]; +static volatile int car_directions[NCARS]; +static volatile int car_turns[NCARS]; +static volatile int car_turn_times[NCARS]; +static volatile void* car_threads[NCARS]; + +static +void +initialize_car_thread(uint32_t index, uint32_t direction, uint32_t turn) { + initialize_thread(car_threads, index); + car_directions[index] = direction; + car_turns[index] = turn; + car_turn_times[index] = 0; +} + +static +void +check_intersection() { + int n = 0; + for (int i = 0; i < NUM_QUADRANTS; i++) { + if (quadrant_array[i] > 1) { + // panic("stoplight: more than 1 car in same quadrant %d\n", i); + test_status = FAIL; + } + n += quadrant_array[i]; + } + max_car_count = n > max_car_count ? n : max_car_count; +} + +/* + * When car move, must call this function and hold a lock. + * It first checks current intersection status make sure no more than one car in one quadrant. + * Then it removes current car from previous location. + * In the end, it returns current car's index for inQuadrant, to let inQuadrant update car_locations array. + */ +static +int +move(uint32_t index) { + check_thread(car_threads, index); + check_intersection(); + int pre_location = car_locations[index]; + if (pre_location != UNKNOWN_CAR && pre_location != PASSED_CAR) { + quadrant_array[pre_location]--; + } + return pre_location; +} + static void turnright_wrapper(void *index, unsigned long direction) { random_yielder(4); - lock_acquire(startlock); + lock_acquire(testlock); + initialize_car_thread((uint32_t)index, (uint32_t)direction, TURN_RIGHT); startcount--; if (startcount == 0) { - cv_broadcast(startcv, startlock); + cv_broadcast(startcv, testlock); } else { - cv_wait(startcv, startlock); + cv_wait(startcv, testlock); } - lock_release(startlock); + lock_release(testlock); turnright((uint32_t)direction, (uint32_t)index); V(endsem); @@ -230,14 +543,15 @@ void gostraight_wrapper(void *index, unsigned long direction) { random_yielder(4); - lock_acquire(startlock); + lock_acquire(testlock); + initialize_car_thread((uint32_t)index, (uint32_t)direction, GO_STRAIGHT); startcount--; if (startcount == 0) { - cv_broadcast(startcv, startlock); + cv_broadcast(startcv, testlock); } else { - cv_wait(startcv, startlock); + cv_wait(startcv, testlock); } - lock_release(startlock); + lock_release(testlock); gostraight((uint32_t)direction, (uint32_t)index); V(endsem); @@ -248,14 +562,15 @@ void turnleft_wrapper(void *index, unsigned long direction) { random_yielder(4); - lock_acquire(startlock); + lock_acquire(testlock); + initialize_car_thread((uint32_t)index, (uint32_t)direction, TURN_LEFT); startcount--; if (startcount == 0) { - cv_broadcast(startcv, startlock); + cv_broadcast(startcv, testlock); } else { - cv_wait(startcv, startlock); + cv_wait(startcv, testlock); } - lock_release(startlock); + lock_release(testlock); turnleft((uint32_t)direction, (uint32_t)index); V(endsem); @@ -264,24 +579,86 @@ turnleft_wrapper(void *index, unsigned long direction) void inQuadrant(int quadrant, uint32_t index) { - (void)index; - random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); + lock_acquire(testlock); + int pre_quadrant = move(index); + + int target_quadrant = car_directions[index]; + switch (car_turn_times[index]) { + case 0: + if (pre_quadrant != UNKNOWN_CAR) { + test_status = FAIL; + } + break; + case 1: + if (pre_quadrant != target_quadrant) { + test_status = FAIL; + } + target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; + break; + case 2: + target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; + if (pre_quadrant != target_quadrant) { + test_status = FAIL; + } + target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; + break; + default: + test_status = FAIL; + break; + } + if (quadrant != target_quadrant) { + test_status = FAIL; + } + car_turn_times[index]++; + + if (quadrant_array[quadrant] > 0) { + // panic("%s inQuadrant %d which already has another car\n", curthread->t_name, quadrant); + test_status = FAIL; + } + quadrant_array[quadrant]++; + car_locations[index] = quadrant; + all_quadrant++; + + lock_release(testlock); kprintf_n("%s in quadrant %d\n", curthread->t_name, quadrant); } void leaveIntersection(uint32_t index) { - (void)index; - random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); + lock_acquire(testlock); + move(index); + + switch (car_turns[index]) { + case GO_STRAIGHT: + if (car_turn_times[index] != 2) { + test_status = FAIL; + } + break; + case TURN_LEFT: + if (car_turn_times[index] != 3) { + test_status = FAIL; + } + break; + case TURN_RIGHT: + if (car_turn_times[index] != 1) { + test_status = FAIL; + } + break; + default: + test_status = FAIL; + break; + } + + car_locations[index] = PASSED_CAR; + lock_release(testlock); kprintf_n("%s left the intersection\n", curthread->t_name); } -#define NCARS 64 - +// TODO: should we delete this? struct semaphore * stoplightMenuSemaphore; int stoplight(int nargs, char **args) { @@ -292,6 +669,21 @@ int stoplight(int nargs, char **args) { inititems(NCARS); stoplight_init(); + test_status = SUCCESS; + + max_car_count = 0; + all_quadrant = 0; + int required_quadrant = 0; + + for (i = 0; i < NUM_QUADRANTS; i++) { + quadrant_array[i] = 0; + } + + for (i = 0; i < NCARS; i++) { + car_locations[i] = UNKNOWN_CAR; + car_threads[i] = NULL; + car_directions[i] = -1; + } for (i = 0; i < NCARS; i++) { @@ -301,26 +693,59 @@ int stoplight(int nargs, char **args) { snprintf(name, sizeof(name), "Car Thread %d", i); switch (turn) { - case 0: + case GO_STRAIGHT: err = thread_fork(name, NULL, gostraight_wrapper, (void *)i, direction); + required_quadrant += 2; break; - case 1: + case TURN_LEFT: err = thread_fork(name, NULL, turnleft_wrapper, (void *)i, direction); + required_quadrant += 3; break; - case 2: + case TURN_RIGHT: err = thread_fork(name, NULL, turnright_wrapper, (void *)i, direction); + required_quadrant += 1; break; } if (err) { panic("stoplight: thread_fork failed: (%s)\n", strerror(err)); } } - + for (i = 0; i < NCARS; i++) { P(endsem); } stoplight_cleanup(); + if (test_status == FAIL) { + success(test_status, SECRET, "sp2"); + return 0; + } + + // Check all cars pass the intersection + int passed = 0; + for (i = 0; i < NCARS; i++) { + passed += car_locations[i] == PASSED_CAR ? 1 : 0; + } + if (passed != NCARS) { + // panic("stoplight: not all cars pass the intersection, total: %d, passed: %d\n", NCARS, passed); + success(FAIL, SECRET, "sp2"); + return 0; + } + + // Check hit quadrant times is same as required, for example, student can force all cars turn right + if (all_quadrant != required_quadrant) { + // panic("stoplight: you may make wrong turn for some cars\n"); + success(FAIL, SECRET, "sp2"); + return 0; + } + + if (max_car_count <= 1) { + test_status = FAIL; + // panic("stoplight: only one car in the intersection at same time, did you use big lock?\n"); + } + + success(test_status, SECRET, "sp2"); + return 0; } diff --git a/kern/test/synchtest.c b/kern/test/synchtest.c index 31a14b9..be94df6 100644 --- a/kern/test/synchtest.c +++ b/kern/test/synchtest.c @@ -29,6 +29,9 @@ /* * Synchronization test code. + * + * All the contents of this file are overwritten during automated + * testing. Please consider this before changing anything in this file. */ #include @@ -117,6 +120,7 @@ semtest(int nargs, char **args) sem_destroy(donesem); } } + spinlock_init(&status_lock); test_status = FAIL; kprintf_n("If this hangs, it's broken: "); @@ -249,6 +253,7 @@ locktest(int nargs, char **args) sem_destroy(donesem); } } + spinlock_init(&status_lock); test_status = SUCCESS; for (i=0; i Date: Thu, 11 Feb 2016 16:35:46 -0500 Subject: [PATCH 5/9] Nearing done with ASST1 changes. --- kern/conf/conf.kern | 2 +- kern/include/kern/secret.h | 2 +- kern/test/synchprobs.c | 190 ++++++++++++++++++------------------- kern/test/synchtest.c | 15 ++- 4 files changed, 109 insertions(+), 100 deletions(-) diff --git a/kern/conf/conf.kern b/kern/conf/conf.kern index 4b4fdaf..61f1b1d 100644 --- a/kern/conf/conf.kern +++ b/kern/conf/conf.kern @@ -442,7 +442,7 @@ file test/threadlisttest.c file test/threadtest.c file test/tt3.c file test/synchtest.c -file test/rwtest.c +file test/rwtest.c file test/semunit.c file test/hmacunit.c file test/kmalloctest.c diff --git a/kern/include/kern/secret.h b/kern/include/kern/secret.h index 16c3903..2b725e8 100644 --- a/kern/include/kern/secret.h +++ b/kern/include/kern/secret.h @@ -45,6 +45,6 @@ */ #undef SECRET_TESTING -#define SECRET "TEST" +#define SECRET "SECRET" #endif /* _SECRET_H_ */ diff --git a/kern/test/synchprobs.c b/kern/test/synchprobs.c index 07fec9a..65641f9 100644 --- a/kern/test/synchprobs.c +++ b/kern/test/synchprobs.c @@ -25,38 +25,12 @@ static uint32_t startcount; static struct lock *testlock; static struct cv *startcv; -static struct cv *endcv; +static struct semaphore *startsem; static struct semaphore *endsem; struct spinlock status_lock; static bool test_status = FAIL; - -static -void -inititems(uint32_t count) -{ - startcount = count; - - if (testlock==NULL) { - testlock = lock_create("testlock"); - if (testlock == NULL) { - panic("synchprobs: lock_create failed\n"); - } - } - if (startcv==NULL) { - startcv = cv_create("startcv"); - if (startcv == NULL) { - panic("synchprobs: cv_create failed\n"); - } - } - if (endsem==NULL) { - endsem = sem_create("endsem", 0); - if (endsem == NULL) { - panic("synchprobs: sem_create failed\n"); - } - } - spinlock_init(&status_lock); -} +const char *test_message; /* * Helper function to initialize the thread pool. @@ -66,6 +40,7 @@ void initialize_thread(volatile void* threads[], uint32_t index) { if (threads[index] != NULL) { test_status = FAIL; + test_message = "failed: incorrect thread type"; } threads[index] = curthread->t_stack; } @@ -78,6 +53,7 @@ void check_thread(volatile void* threads[], uint32_t index) { if (threads[index] != curthread->t_stack) { test_status = FAIL; + test_message = "failed: incorrect thread type"; } } @@ -113,6 +89,7 @@ void check_role(uint32_t index, int role) { if (whale_roles[index] != role) { test_status = FAIL; + test_message = "failed: incorrect role"; } } @@ -125,10 +102,8 @@ male_wrapper(void * unused1, unsigned long index) { lock_acquire(testlock); initialize_thread(whale_threads, (uint32_t)index); whale_roles[index] = MALE; - startcount--; lock_release(testlock); male((uint32_t)index); - V(endsem); return; } @@ -139,12 +114,12 @@ male_start(uint32_t index) { check_thread(whale_threads, index); check_role(index, MALE); male_start_count++; - cv_signal(startcv, testlock); lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s starting\n", curthread->t_name); kprintf_t("."); + V(startsem); } void male_end(uint32_t index) { @@ -152,13 +127,13 @@ male_end(uint32_t index) { lock_acquire(testlock); check_thread(whale_threads, index); check_role(index, MALE); - cv_signal(endcv, testlock); male_end_count++; lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s ending\n", curthread->t_name); kprintf_t("."); + V(endsem); } static @@ -170,10 +145,8 @@ female_wrapper(void * unused1, unsigned long index) { lock_acquire(testlock); initialize_thread(whale_threads, (uint32_t)index); whale_roles[index] = FEMALE; - startcount--; lock_release(testlock); female((uint32_t)index); - V(endsem); return; } @@ -184,12 +157,12 @@ female_start(uint32_t index) { check_thread(whale_threads, index); check_role(index, FEMALE); female_start_count++; - cv_signal(startcv, testlock); lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s starting\n", curthread->t_name); kprintf_t("."); + V(startsem); } void female_end(uint32_t index) { @@ -197,13 +170,13 @@ female_end(uint32_t index) { lock_acquire(testlock); check_thread(whale_threads, index); check_role(index, FEMALE); - cv_signal(endcv, testlock); female_end_count++; lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s ending\n", curthread->t_name); kprintf_t("."); + V(endsem); } static @@ -215,27 +188,25 @@ matchmaker_wrapper(void * unused1, unsigned long index) { lock_acquire(testlock); initialize_thread(whale_threads, (uint32_t)index); whale_roles[index] = MATCHMAKER; - startcount--; lock_release(testlock); matchmaker((uint32_t)index); - V(endsem); return; } void matchmaker_start(uint32_t index) { (void)index; + P(matcher_sem); lock_acquire(testlock); check_thread(whale_threads, index); check_role(index, MATCHMAKER); matchmaker_start_count++; - cv_signal(startcv, testlock); lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s starting\n", curthread->t_name); kprintf_t("."); - P(matcher_sem); + V(startsem); } void matchmaker_end(uint32_t index) { @@ -251,12 +222,12 @@ matchmaker_end(uint32_t index) { match_count++; matchmaker_end_count++; - cv_signal(endcv, testlock); lock_release(testlock); random_yielder(PROBLEMS_MAX_YIELDER); random_spinner(PROBLEMS_MAX_SPINNER); kprintf_n("%s ending\n", curthread->t_name); kprintf_t("."); + V(endsem); } static @@ -265,6 +236,7 @@ check_zero(int count, const char *name) { (void)name; if (count != 0) { test_status = FAIL; + test_message = "failed: not all threads completed"; } } @@ -275,6 +247,8 @@ whalemating(int nargs, char **args) { int i, j, err = 0; char name[32]; + bool loop_status; + int total_count = 0; male_start_count = 0 ; male_end_count = 0 ; @@ -284,18 +258,13 @@ whalemating(int nargs, char **args) { matchmaker_end_count = 0; match_count = 0; - startcount = 3 * NMATING; testlock = lock_create("testlock"); if (testlock == NULL) { panic("sp1: lock_create failed\n"); } - startcv = cv_create("startcv"); - if (startcv == NULL) { - panic("sp1: cv_create failed\n"); - } - endcv = cv_create("endcv"); - if (endcv == NULL) { - panic("sp1: cv_create failed\n"); + startsem = sem_create("startsem", 0); + if (startsem == NULL) { + panic("sp1: sem_create failed\n"); } endsem = sem_create("endsem", 0); if (endsem == NULL) { @@ -306,7 +275,8 @@ whalemating(int nargs, char **args) { panic("sp1: sem_create failed\n"); } spinlock_init(&status_lock); - test_status = FAIL; + test_status = SUCCESS; + test_message = ""; whalemating_init(); @@ -326,6 +296,7 @@ whalemating(int nargs, char **args) { err = thread_fork(name, NULL, female_wrapper, NULL, index); break; } + total_count += 1; if (err) { panic("whalemating: thread_fork failed: (%s)\n", strerror(err)); } @@ -335,14 +306,12 @@ whalemating(int nargs, char **args) { /* Wait for males and females to start. */ for (i = 0; i < NMATING * 2; i++) { kprintf_t("."); - lock_acquire(testlock); - cv_wait(startcv, testlock); - lock_release(testlock); + P(startsem); } /* Make sure nothing is happening... */ - bool loop_status = SUCCESS; - for (i = 0; i < CHECK_TIMES && loop_status == SUCCESS; ) { + loop_status = SUCCESS; + for (i = 0; i < CHECK_TIMES && loop_status == SUCCESS; i++) { kprintf_t("."); random_spinner(PROBLEMS_MAX_SPINNER); lock_acquire(testlock); @@ -354,6 +323,7 @@ whalemating(int nargs, char **args) { } if (loop_status == FAIL) { test_status = FAIL; + test_message = "failed: uncoordinated matchmaking is occurring"; goto done; } @@ -367,6 +337,7 @@ whalemating(int nargs, char **args) { if (err) { panic("whalemating: thread_fork failed: (%s)\n", strerror(err)); } + total_count++; } /* @@ -380,26 +351,26 @@ whalemating(int nargs, char **args) { } for (i = 0; i < 3 * pivot; i++) { kprintf_t("."); - lock_acquire(testlock); - cv_wait(endcv, testlock); - lock_release(testlock); + P(endsem); + total_count--; } /* Make sure nothing else is happening... */ - bool loop_status = SUCCESS; - for (i = 0; i < CHECK_TIMES && loop_status == SUCCESS; ) { + loop_status = SUCCESS; + for (i = 0; i < CHECK_TIMES && loop_status == SUCCESS; i++) { kprintf_t("."); random_spinner(PROBLEMS_MAX_SPINNER); lock_acquire(testlock); if ((male_start_count != NMATING) || (female_start_count != NMATING) || - (male_end_count != pivot) || (female_end_count != pivot) || - (matchmaker_start_count != pivot) || (matchmaker_end_count != pivot)) { + (matchmaker_start_count != pivot) || (male_end_count != pivot) || + (female_end_count != pivot) || (matchmaker_end_count != pivot)) { loop_status = FAIL; } lock_release(testlock); } if (loop_status == FAIL) { test_status = FAIL; + test_message = "failed: uncoordinating matchmaking is occurring"; goto done; } @@ -408,12 +379,14 @@ whalemating(int nargs, char **args) { */ for (i = pivot; i < NMATING; i++) { + kprintf_t("."); V(matcher_sem); } for (i = 0; i < 3; i++) { - for (j = 0; j < NMATING; j++) { + for (j = pivot; j < NMATING; j++) { kprintf_t("."); P(endsem); + total_count--; } } @@ -435,22 +408,31 @@ whalemating(int nargs, char **args) { if (male == 0 || female == 0) { spinlock_acquire(&status_lock); test_status = FAIL; + test_message = "failed: not all males were matched"; spinlock_release(&status_lock); } } } else { spinlock_acquire(&status_lock); test_status = FAIL; + test_message = "failed: not all males were matched"; spinlock_release(&status_lock); } done: + for (i = 0; i < total_count; i++) { + P(endsem); + } + lock_destroy(testlock); - cv_destroy(startcv); - cv_destroy(endcv); + sem_destroy(startsem); sem_destroy(endsem); sem_destroy(matcher_sem); + kprintf_t("\n"); + if (test_status != SUCCESS) { + ksecprintf(SECRET, test_message, "sp1"); + } success(test_status, SECRET, "sp1"); return 0; @@ -493,7 +475,7 @@ check_intersection() { int n = 0; for (int i = 0; i < NUM_QUADRANTS; i++) { if (quadrant_array[i] > 1) { - // panic("stoplight: more than 1 car in same quadrant %d\n", i); + test_message = "failed: collision"; test_status = FAIL; } n += quadrant_array[i]; @@ -588,11 +570,13 @@ inQuadrant(int quadrant, uint32_t index) { switch (car_turn_times[index]) { case 0: if (pre_quadrant != UNKNOWN_CAR) { + test_message = "failed: invalid turn"; test_status = FAIL; } break; case 1: if (pre_quadrant != target_quadrant) { + test_message = "failed: invalid turn"; test_status = FAIL; } target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; @@ -600,6 +584,7 @@ inQuadrant(int quadrant, uint32_t index) { case 2: target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; if (pre_quadrant != target_quadrant) { + test_message = "failed: invalid turn"; test_status = FAIL; } target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; @@ -614,7 +599,7 @@ inQuadrant(int quadrant, uint32_t index) { car_turn_times[index]++; if (quadrant_array[quadrant] > 0) { - // panic("%s inQuadrant %d which already has another car\n", curthread->t_name, quadrant); + test_message = "failed: collision"; test_status = FAIL; } quadrant_array[quadrant]++; @@ -635,16 +620,19 @@ leaveIntersection(uint32_t index) { switch (car_turns[index]) { case GO_STRAIGHT: if (car_turn_times[index] != 2) { + test_message = "failed: incorrect turn"; test_status = FAIL; } break; case TURN_LEFT: if (car_turn_times[index] != 3) { + test_message = "failed: incorrect turn"; test_status = FAIL; } break; case TURN_RIGHT: if (car_turn_times[index] != 1) { + test_message = "failed: incorrect turn"; test_status = FAIL; } break; @@ -658,22 +646,16 @@ leaveIntersection(uint32_t index) { kprintf_n("%s left the intersection\n", curthread->t_name); } -// TODO: should we delete this? -struct semaphore * stoplightMenuSemaphore; - int stoplight(int nargs, char **args) { (void) nargs; (void) args; int i, direction, turn, err = 0; char name[32]; - - inititems(NCARS); - stoplight_init(); - test_status = SUCCESS; + int required_quadrant = 0; + int passed = 0; max_car_count = 0; all_quadrant = 0; - int required_quadrant = 0; for (i = 0; i < NUM_QUADRANTS; i++) { quadrant_array[i] = 0; @@ -685,7 +667,26 @@ int stoplight(int nargs, char **args) { car_directions[i] = -1; } + startcount = NCARS; + testlock = lock_create("testlock"); + if (testlock == NULL) { + panic("sp2: lock_create failed\n"); + } + startcv = cv_create("startcv"); + if (startcv == NULL) { + panic("sp2: cv_create failed\n"); + } + endsem = sem_create("endsem", 0); + if (endsem == NULL) { + panic("sp2: sem_create failed\n"); + } + spinlock_init(&status_lock); + test_status = SUCCESS; + + stoplight_init(); + for (i = 0; i < NCARS; i++) { + kprintf_t("."); direction = random() % 4; turn = random() % 3; @@ -712,39 +713,36 @@ int stoplight(int nargs, char **args) { } for (i = 0; i < NCARS; i++) { + kprintf_t("."); P(endsem); } stoplight_cleanup(); - if (test_status == FAIL) { - success(test_status, SECRET, "sp2"); - return 0; - } - - // Check all cars pass the intersection - int passed = 0; for (i = 0; i < NCARS; i++) { passed += car_locations[i] == PASSED_CAR ? 1 : 0; } - if (passed != NCARS) { - // panic("stoplight: not all cars pass the intersection, total: %d, passed: %d\n", NCARS, passed); - success(FAIL, SECRET, "sp2"); - return 0; + if (test_status == SUCCESS) { + if (passed != NCARS) { + test_message = "failed: not enough cars"; + test_status = FAIL; + } else if (all_quadrant != required_quadrant) { + test_message = "failed: didn't do the right turns"; + test_status = FAIL; + } else if (max_car_count <= 1) { + test_message = "failed: no concurrency achieved"; + test_status = FAIL; + } } - // Check hit quadrant times is same as required, for example, student can force all cars turn right - if (all_quadrant != required_quadrant) { - // panic("stoplight: you may make wrong turn for some cars\n"); - success(FAIL, SECRET, "sp2"); - return 0; - } + lock_destroy(testlock); + cv_destroy(startcv); + sem_destroy(endsem); - if (max_car_count <= 1) { - test_status = FAIL; - // panic("stoplight: only one car in the intersection at same time, did you use big lock?\n"); + kprintf_t("\n"); + if (test_status != SUCCESS) { + ksecprintf(SECRET, test_message, "sp2"); } - success(test_status, SECRET, "sp2"); return 0; diff --git a/kern/test/synchtest.c b/kern/test/synchtest.c index be94df6..1e41526 100644 --- a/kern/test/synchtest.c +++ b/kern/test/synchtest.c @@ -107,6 +107,7 @@ semtest(int nargs, char **args) kprintf_n("Starting sem1...\n"); for (i=0; i Date: Thu, 11 Feb 2016 16:56:51 -0500 Subject: [PATCH 6/9] Command to print total kernel heap usage for debugging. --- kern/include/lib.h | 1 + kern/main/menu.c | 14 ++++++++++++ kern/vm/kmalloc.c | 57 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/kern/include/lib.h b/kern/include/lib.h index 7478ce6..498ec28 100644 --- a/kern/include/lib.h +++ b/kern/include/lib.h @@ -129,6 +129,7 @@ uint32_t random(void); void *kmalloc(size_t size); void kfree(void *ptr); void kheap_printstats(void); +void kheap_printused(void); void kheap_nextgeneration(void); void kheap_dump(void); void kheap_dumpall(void); diff --git a/kern/main/menu.c b/kern/main/menu.c index 4aeb5db..945a91d 100644 --- a/kern/main/menu.c +++ b/kern/main/menu.c @@ -376,6 +376,18 @@ cmd_kheapstats(int nargs, char **args) return 0; } +static +int +cmd_kheapused(int nargs, char **args) +{ + (void)nargs; + (void)args; + + kheap_printused(); + + return 0; +} + static int cmd_kheapgeneration(int nargs, char **args) @@ -541,6 +553,7 @@ static const char *mainmenu[] = { "[?o] Operations menu ", "[?t] Tests menu ", "[kh] Kernel heap stats ", + "[khu] Kernel heap usage ", "[khgen] Next kernel heap generation ", "[khdump] Dump kernel heap ", "[q] Quit and shut down ", @@ -593,6 +606,7 @@ static struct { /* stats */ { "kh", cmd_kheapstats }, + { "khu", cmd_kheapused }, { "khgen", cmd_kheapgeneration }, { "khdump", cmd_kheapdump }, diff --git a/kern/vm/kmalloc.c b/kern/vm/kmalloc.c index 453b3cc..4921a85 100644 --- a/kern/vm/kmalloc.c +++ b/kern/vm/kmalloc.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include /* * Kernel malloc. @@ -743,8 +745,8 @@ kheap_dumpall(void) * Print the allocated/freed map of a single kernel heap page. */ static -void -subpage_stats(struct pageref *pr) +unsigned long +subpage_stats(struct pageref *pr, bool quiet) { vaddr_t prpage, fla; struct freelist *fl; @@ -779,19 +781,22 @@ subpage_stats(struct pageref *pr) freemap[index/32] |= (1<<(index%32)); } } - - kprintf("at 0x%08lx: size %-4lu %u/%u free\n", - (unsigned long)prpage, (unsigned long) sizes[blktype], - (unsigned) pr->nfree, n); - kprintf(" "); - for (i=0; infree, n); + kprintf(" "); + for (i=0; infree)); } /* @@ -806,14 +811,36 @@ kheap_printstats(void) spinlock_acquire(&kmalloc_spinlock); kprintf("Subpage allocator status:\n"); - + for (pr = allbase; pr != NULL; pr = pr->next_all) { - subpage_stats(pr); + subpage_stats(pr, false); } spinlock_release(&kmalloc_spinlock); } +/* + * Print the whole heap. + */ +void +kheap_printused(void) +{ + struct pageref *pr; + unsigned long total = 0; + /* print the whole thing with interrupts off */ + spinlock_acquire(&kmalloc_spinlock); + + for (pr = allbase; pr != NULL; pr = pr->next_all) { + total += subpage_stats(pr, true); + } + + spinlock_release(&kmalloc_spinlock); + + char total_string[32]; + snprintf(total_string, sizeof(total_string), "%lu", total); + ksecprintf(SECRET, total_string, "khu"); +} + //////////////////////////////////////// /* From 4b630a915d6f912a7451ace6b3d09b393d384af1 Mon Sep 17 00:00:00 2001 From: Geoffrey Challen Date: Thu, 11 Feb 2016 19:53:53 -0500 Subject: [PATCH 7/9] Cleanup. --- kern/conf/DUMBVM | 2 +- kern/test/synchprobs.c | 154 +++++++++++++++-------------------------- kern/test/synchtest.c | 40 +++++------ 3 files changed, 72 insertions(+), 124 deletions(-) diff --git a/kern/conf/DUMBVM b/kern/conf/DUMBVM index 3216e1f..cc07484 100644 --- a/kern/conf/DUMBVM +++ b/kern/conf/DUMBVM @@ -30,4 +30,4 @@ options sfs # Always use the file system #options netfs # You might write this as a project. options dumbvm # Chewing gum and baling wire. -#options synchprobs # Uncomment to enable ASST1 synchronization problems +options synchprobs # Uncomment to enable ASST1 synchronization problems diff --git a/kern/test/synchprobs.c b/kern/test/synchprobs.c index 65641f9..5b6361e 100644 --- a/kern/test/synchprobs.c +++ b/kern/test/synchprobs.c @@ -32,16 +32,25 @@ struct spinlock status_lock; static bool test_status = FAIL; const char *test_message; +static +bool +failif(bool condition, const char *message) { + if (condition) { + spinlock_acquire(&status_lock); + test_status = FAIL; + test_message = message; + spinlock_release(&status_lock); + } + return condition; +} + /* * Helper function to initialize the thread pool. */ static void initialize_thread(volatile void* threads[], uint32_t index) { - if (threads[index] != NULL) { - test_status = FAIL; - test_message = "failed: incorrect thread type"; - } + failif((threads[index] != NULL), "failed: incorrect thread type"); threads[index] = curthread->t_stack; } @@ -51,10 +60,7 @@ initialize_thread(volatile void* threads[], uint32_t index) { static void check_thread(volatile void* threads[], uint32_t index) { - if (threads[index] != curthread->t_stack) { - test_status = FAIL; - test_message = "failed: incorrect thread type"; - } + failif((threads[index] != curthread->t_stack), "failed: incorrect thread type"); } /* @@ -87,10 +93,7 @@ static struct semaphore *matcher_sem; static void check_role(uint32_t index, int role) { - if (whale_roles[index] != role) { - test_status = FAIL; - test_message = "failed: incorrect role"; - } + failif((whale_roles[index] != role), "failed: incorrect role"); } static @@ -232,12 +235,8 @@ matchmaker_end(uint32_t index) { static void -check_zero(int count, const char *name) { - (void)name; - if (count != 0) { - test_status = FAIL; - test_message = "failed: not all threads completed"; - } +check_zero(int count) { + failif((count != 0), "failed: not all threads completed"); } int @@ -321,9 +320,7 @@ whalemating(int nargs, char **args) { } lock_release(testlock); } - if (loop_status == FAIL) { - test_status = FAIL; - test_message = "failed: uncoordinated matchmaking is occurring"; + if (failif((loop_status == FAIL), "failed: uncoordinated matchmaking is occurring")) { goto done; } @@ -368,9 +365,7 @@ whalemating(int nargs, char **args) { } lock_release(testlock); } - if (loop_status == FAIL) { - test_status = FAIL; - test_message = "failed: uncoordinating matchmaking is occurring"; + if (failif((loop_status == FAIL), "failed: uncoordinated matchmaking is occurring")) { goto done; } @@ -392,12 +387,12 @@ whalemating(int nargs, char **args) { whalemating_cleanup(); - check_zero(male_start_count - NMATING, "male"); - check_zero(female_start_count - NMATING, "female"); - check_zero(matchmaker_start_count - NMATING, "matchmaker"); - check_zero(male_start_count - male_end_count, "male"); - check_zero(female_start_count - female_end_count, "female"); - check_zero(matchmaker_start_count - matchmaker_end_count, "matchmaker"); + check_zero(male_start_count - NMATING); + check_zero(female_start_count - NMATING); + check_zero(matchmaker_start_count - NMATING); + check_zero(male_start_count - male_end_count); + check_zero(female_start_count - female_end_count); + check_zero(matchmaker_start_count - matchmaker_end_count); if (match_count == NMATING) { for (i = 0; i < NMATING; i++) { @@ -405,18 +400,10 @@ whalemating(int nargs, char **args) { j = i * 3; int male = match_status[j]; int female = match_status[j + 1]; - if (male == 0 || female == 0) { - spinlock_acquire(&status_lock); - test_status = FAIL; - test_message = "failed: not all males were matched"; - spinlock_release(&status_lock); - } + failif((male == 0 || female == 0), "failed: not all males were matched"); } } else { - spinlock_acquire(&status_lock); - test_status = FAIL; - test_message = "failed: not all males were matched"; - spinlock_release(&status_lock); + failif(true, "failed: not all males were matched"); } done: @@ -474,10 +461,7 @@ void check_intersection() { int n = 0; for (int i = 0; i < NUM_QUADRANTS; i++) { - if (quadrant_array[i] > 1) { - test_message = "failed: collision"; - test_status = FAIL; - } + failif((quadrant_array[i] > 1), "failed: collision"); n += quadrant_array[i]; } max_car_count = n > max_car_count ? n : max_car_count; @@ -569,39 +553,26 @@ inQuadrant(int quadrant, uint32_t index) { int target_quadrant = car_directions[index]; switch (car_turn_times[index]) { case 0: - if (pre_quadrant != UNKNOWN_CAR) { - test_message = "failed: invalid turn"; - test_status = FAIL; - } - break; + failif((pre_quadrant != UNKNOWN_CAR), "failed: invalid turn"); + break; case 1: - if (pre_quadrant != target_quadrant) { - test_message = "failed: invalid turn"; - test_status = FAIL; - } - target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; - break; + failif((pre_quadrant != target_quadrant), "failed: invalid turn"); + target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; + break; case 2: - target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; - if (pre_quadrant != target_quadrant) { - test_message = "failed: invalid turn"; - test_status = FAIL; - } - target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; - break; + target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; + failif((pre_quadrant != target_quadrant), "failed: invalid turn"); + target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; + break; default: - test_status = FAIL; - break; - } - if (quadrant != target_quadrant) { - test_status = FAIL; + failif(true, "failed: invalid turn"); + break; } + failif((quadrant != target_quadrant), "failed: invalid turn"); car_turn_times[index]++; + + failif((quadrant_array[quadrant] > 0), "failed: collision"); - if (quadrant_array[quadrant] > 0) { - test_message = "failed: collision"; - test_status = FAIL; - } quadrant_array[quadrant]++; car_locations[index] = quadrant; all_quadrant++; @@ -619,26 +590,17 @@ leaveIntersection(uint32_t index) { switch (car_turns[index]) { case GO_STRAIGHT: - if (car_turn_times[index] != 2) { - test_message = "failed: incorrect turn"; - test_status = FAIL; - } - break; + failif((car_turn_times[index] != 2), "failed: incorrect turn"); + break; case TURN_LEFT: - if (car_turn_times[index] != 3) { - test_message = "failed: incorrect turn"; - test_status = FAIL; - } - break; + failif((car_turn_times[index] != 3), "failed: incorrect turn"); + break; case TURN_RIGHT: - if (car_turn_times[index] != 1) { - test_message = "failed: incorrect turn"; - test_status = FAIL; - } - break; + failif((car_turn_times[index] != 1), "failed: incorrect turn"); + break; default: - test_status = FAIL; - break; + failif(true, "failed: incorrect turn"); + break; } car_locations[index] = PASSED_CAR; @@ -722,18 +684,10 @@ int stoplight(int nargs, char **args) { for (i = 0; i < NCARS; i++) { passed += car_locations[i] == PASSED_CAR ? 1 : 0; } - if (test_status == SUCCESS) { - if (passed != NCARS) { - test_message = "failed: not enough cars"; - test_status = FAIL; - } else if (all_quadrant != required_quadrant) { - test_message = "failed: didn't do the right turns"; - test_status = FAIL; - } else if (max_car_count <= 1) { - test_message = "failed: no concurrency achieved"; - test_status = FAIL; - } - } + if ((test_status == SUCCESS) && + (!failif((passed != NCARS), "failed: not enough cars")) && + (!(failif((all_quadrant != required_quadrant), "failed: didn't do the right turns"))) && + (!(failif((max_car_count <= 1), "failed: no concurrency achieved")))) {}; lock_destroy(testlock); cv_destroy(startcv); diff --git a/kern/test/synchtest.c b/kern/test/synchtest.c index 1e41526..56ff74a 100644 --- a/kern/test/synchtest.c +++ b/kern/test/synchtest.c @@ -65,6 +65,17 @@ static bool test_status = FAIL; static unsigned long semtest_current; +static +bool +failif(bool condition) { + if (condition) { + spinlock_acquire(&status_lock); + test_status = FAIL; + spinlock_release(&status_lock); + } + return condition; +} + static void semtestthread(void *junk, unsigned long num) @@ -86,11 +97,7 @@ semtestthread(void *junk, unsigned long num) kprintf_t("."); kprintf_n("%2lu", num); random_yielder(4); - if (semtest_current != num) { - spinlock_acquire(&status_lock); - test_status = FAIL; - spinlock_release(&status_lock); - } + failif((semtest_current != num)); } kprintf_n("\n"); @@ -224,9 +231,7 @@ locktestthread(void *junk, unsigned long num) fail: lock_release(testlock); fail2: - spinlock_acquire(&status_lock); - test_status = FAIL; - spinlock_release(&status_lock); + failif(true); V(donesem); return; } @@ -373,10 +378,8 @@ cvtestthread(void *junk, unsigned long num) /* Require at least 2000 cpu cycles (we're 25mhz) */ if (ts2.tv_sec == 0 && ts2.tv_nsec < 40*2000) { kprintf_n("cv_wait took only %u ns\n", ts2.tv_nsec); - kprintf_n("That's too fast... you must be " "busy-looping\n"); - spinlock_acquire(&status_lock); - test_status = FAIL; - spinlock_release(&status_lock); + kprintf_n("That's too fast... you must be busy-looping\n"); + failif(true); V(donesem); thread_exit(); } @@ -394,12 +397,7 @@ cvtestthread(void *junk, unsigned long num) random_yielder(4); cv_broadcast(testcv, testlock); random_yielder(4); - - spinlock_acquire(&status_lock); - if (testval1 != testval2) { - test_status = FAIL; - } - spinlock_release(&status_lock); + failif((testval1 != testval2)); kprintf_n("Thread %lu\n", testval2); testval1 = (testval1 + NTHREADS - 1) % NTHREADS; @@ -532,12 +530,8 @@ wakethread(void *junk1, unsigned long junk2) random_yielder(4); lock_acquire(testlocks[i]); random_yielder(4); - spinlock_acquire(&status_lock); testval4--; - if (testval4 != 0) { - test_status = FAIL; - } - spinlock_release(&status_lock); + failif((testval4 != 0)); cv_signal(testcvs[i], testlocks[i]); random_yielder(4); lock_release(testlocks[i]); From ec9ae33666c7925d59fbe372335416069ee07a52 Mon Sep 17 00:00:00 2001 From: Geoffrey Challen Date: Thu, 11 Feb 2016 19:56:59 -0500 Subject: [PATCH 8/9] Redisable synchprobs by default. --- kern/conf/DUMBVM | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kern/conf/DUMBVM b/kern/conf/DUMBVM index cc07484..3216e1f 100644 --- a/kern/conf/DUMBVM +++ b/kern/conf/DUMBVM @@ -30,4 +30,4 @@ options sfs # Always use the file system #options netfs # You might write this as a project. options dumbvm # Chewing gum and baling wire. -options synchprobs # Uncomment to enable ASST1 synchronization problems +#options synchprobs # Uncomment to enable ASST1 synchronization problems From 32253d53bc7bf6246d7298e27ae48abe81dd0695 Mon Sep 17 00:00:00 2001 From: Geoffrey Challen Date: Thu, 11 Feb 2016 20:10:39 -0500 Subject: [PATCH 9/9] Fix whitespace errors. --- kern/test/synchprobs.c | 22 +++++++++++----------- kern/test/synchtest.c | 42 +++++++++++++++++++++--------------------- kern/vm/kmalloc.c | 12 ++++++------ 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/kern/test/synchprobs.c b/kern/test/synchprobs.c index 5b6361e..9a13b31 100644 --- a/kern/test/synchprobs.c +++ b/kern/test/synchprobs.c @@ -278,7 +278,7 @@ whalemating(int nargs, char **args) { test_message = ""; whalemating_init(); - + /* Start males and females only. */ for (i = 0; i < 2; i++) { for (j = 0; j < NMATING; j++) { @@ -302,12 +302,12 @@ whalemating(int nargs, char **args) { } } - /* Wait for males and females to start. */ + /* Wait for males and females to start. */ for (i = 0; i < NMATING * 2; i++) { kprintf_t("."); P(startsem); } - + /* Make sure nothing is happening... */ loop_status = SUCCESS; for (i = 0; i < CHECK_TIMES && loop_status == SUCCESS; i++) { @@ -323,7 +323,7 @@ whalemating(int nargs, char **args) { if (failif((loop_status == FAIL), "failed: uncoordinated matchmaking is occurring")) { goto done; } - + /* Create the matchmakers */ for (j = 0; j < NMATING; j++) { kprintf_t("."); @@ -336,11 +336,11 @@ whalemating(int nargs, char **args) { } total_count++; } - + /* * Release a random number of matchmakers and wait for them and their * matches to finish. - */ + */ int pivot = (random() % (NMATING - 2)) + 1; for (i = 0; i < pivot; i++) { kprintf_t("."); @@ -351,8 +351,8 @@ whalemating(int nargs, char **args) { P(endsem); total_count--; } - - /* Make sure nothing else is happening... */ + + /* Make sure nothing else is happening... */ loop_status = SUCCESS; for (i = 0; i < CHECK_TIMES && loop_status == SUCCESS; i++) { kprintf_t("."); @@ -368,7 +368,7 @@ whalemating(int nargs, char **args) { if (failif((loop_status == FAIL), "failed: uncoordinated matchmaking is occurring")) { goto done; } - + /* * Release the rest of the matchmakers and wait for everyone to finish. */ @@ -415,7 +415,7 @@ done: sem_destroy(startsem); sem_destroy(endsem); sem_destroy(matcher_sem); - + kprintf_t("\n"); if (test_status != SUCCESS) { ksecprintf(SECRET, test_message, "sp1"); @@ -570,7 +570,7 @@ inQuadrant(int quadrant, uint32_t index) { } failif((quadrant != target_quadrant), "failed: invalid turn"); car_turn_times[index]++; - + failif((quadrant_array[quadrant] > 0), "failed: collision"); quadrant_array[quadrant]++; diff --git a/kern/test/synchtest.c b/kern/test/synchtest.c index 56ff74a..a90173d 100644 --- a/kern/test/synchtest.c +++ b/kern/test/synchtest.c @@ -83,7 +83,7 @@ semtestthread(void *junk, unsigned long num) (void)junk; int i; - + random_yielder(4); /* @@ -111,7 +111,7 @@ semtest(int nargs, char **args) (void)args; int i, result; - + kprintf_n("Starting sem1...\n"); for (i=0; infree, n); @@ -811,7 +811,7 @@ kheap_printstats(void) spinlock_acquire(&kmalloc_spinlock); kprintf("Subpage allocator status:\n"); - + for (pr = allbase; pr != NULL; pr = pr->next_all) { subpage_stats(pr, false); } @@ -820,7 +820,7 @@ kheap_printstats(void) } /* - * Print the whole heap. + * Print number of used heap bytes. */ void kheap_printused(void) @@ -829,13 +829,13 @@ kheap_printused(void) unsigned long total = 0; /* print the whole thing with interrupts off */ spinlock_acquire(&kmalloc_spinlock); - + for (pr = allbase; pr != NULL; pr = pr->next_all) { total += subpage_stats(pr, true); } spinlock_release(&kmalloc_spinlock); - + char total_string[32]; snprintf(total_string, sizeof(total_string), "%lu", total); ksecprintf(SECRET, total_string, "khu");