diff --git a/kern/conf/conf.kern b/kern/conf/conf.kern index 1fc3aa1..61f1b1d 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 a561058..2b725e8 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 "SECRET" #endif /* _SECRET_H_ */ 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/include/test.h b/kern/include/test.h index 998d25e..4f81a45 100644 --- a/kern/include/test.h +++ b/kern/include/test.h @@ -59,8 +59,12 @@ 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 cvtest3(int, char **); +int cvtest4(int, char **); int rwtest(int, char **); /* semaphore unit tests */ @@ -172,7 +176,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/main/menu.c b/kern/main/menu.c index 6f69a14..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) @@ -475,14 +487,18 @@ 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) ", + "[cvt3] CV test 3 (panics) (1) ", + "[cvt4] CV test 4 (panics) (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 ", @@ -537,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 ", @@ -589,6 +606,7 @@ static struct { /* stats */ { "kh", cmd_kheapstats }, + { "khu", cmd_kheapused }, { "khgen", cmd_kheapgeneration }, { "khdump", cmd_kheapdump }, @@ -607,13 +625,17 @@ 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 }, + { "cvt3", cvtest3 }, + { "cvt4", cvtest4 }, + { "rwt1", rwtest }, #if OPT_SYNCHPROBS { "sp1", whalemating }, { "sp2", stoplight }, 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 /* diff --git a/kern/test/rwtest.c b/kern/test/rwtest.c new file mode 100644 index 0000000..9fa3a33 --- /dev/null +++ b/kern/test/rwtest.c @@ -0,0 +1,23 @@ +/* + * All the contents of this file are overwritten during automated + * testing. Please consider this before changing anything in this file. + */ + +#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/synchprobs.c b/kern/test/synchprobs.c index d77aaed..9a13b31 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,81 +9,134 @@ #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 semaphore *startsem; static struct semaphore *endsem; +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 -inititems(uint32_t count) -{ - startcount = count; +initialize_thread(volatile void* threads[], uint32_t index) { + failif((threads[index] != NULL), "failed: incorrect thread type"); + threads[index] = curthread->t_stack; +} - if (startlock==NULL) { - startlock = lock_create("startlock"); - if (startlock == 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"); - } - } +/* + * Helper function to check whether current thread is valid. + */ +static +void +check_thread(volatile void* threads[], uint32_t index) { + failif((threads[index] != curthread->t_stack), "failed: incorrect thread type"); } /* * 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) { + failif((whale_roles[index] != role), "failed: incorrect role"); +} + static void male_wrapper(void * unused1, unsigned long index) { (void)unused1; random_yielder(4); - lock_acquire(startlock); - startcount--; - if (startcount == 0) { - cv_broadcast(startcv, startlock); - } else { - cv_wait(startcv, startlock); - } - lock_release(startlock); + lock_acquire(testlock); + initialize_thread(whale_threads, (uint32_t)index); + whale_roles[index] = MALE; + lock_release(testlock); male((uint32_t)index); - V(endsem); return; } void male_start(uint32_t index) { (void)index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, MALE); + male_start_count++; + 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) { (void)index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, MALE); + 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 @@ -94,69 +145,99 @@ female_wrapper(void * unused1, unsigned long index) { (void)unused1; random_yielder(4); - lock_acquire(startlock); - startcount--; - if (startcount == 0) { - cv_broadcast(startcv, startlock); - } else { - cv_wait(startcv, startlock); - } - lock_release(startlock); + lock_acquire(testlock); + initialize_thread(whale_threads, (uint32_t)index); + whale_roles[index] = FEMALE; + lock_release(testlock); female((uint32_t)index); - V(endsem); return; } void female_start(uint32_t index) { (void) index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, FEMALE); + female_start_count++; + 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) { (void) index; + lock_acquire(testlock); + check_thread(whale_threads, index); + check_role(index, FEMALE); + 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 void matchmaker_wrapper(void * unused1, unsigned long index) { (void)unused1; - + random_yielder(4); - lock_acquire(startlock); - startcount--; - if (startcount == 0) { - cv_broadcast(startcv, startlock); - } else { - cv_wait(startcv, startlock); - } - lock_release(startlock); + lock_acquire(testlock); + initialize_thread(whale_threads, (uint32_t)index); + whale_roles[index] = MATCHMAKER; + 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++; + 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 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++; + 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); } -#define NMATING 10 +static +void +check_zero(int count) { + failif((count != 0), "failed: not all threads completed"); +} int whalemating(int nargs, char **args) { @@ -165,13 +246,45 @@ 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 ; + female_start_count = 0 ; + female_end_count = 0 ; + matchmaker_start_count = 0; + matchmaker_end_count = 0; + match_count = 0; - inititems(3 * NMATING); + testlock = lock_create("testlock"); + if (testlock == NULL) { + panic("sp1: lock_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) { + 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 = SUCCESS; + test_message = ""; + whalemating_init(); - for (i = 0; i < 3; i++) { + /* 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,25 +294,134 @@ 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; } + total_count += 1; if (err) { panic("whalemating: thread_fork failed: (%s)\n", strerror(err)); } } } + /* 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++) { + 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 (failif((loop_status == FAIL), "failed: uncoordinated matchmaking is occurring")) { + 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)); + } + 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("."); + V(matcher_sem); + } + for (i = 0; i < 3 * pivot; i++) { + kprintf_t("."); + P(endsem); + total_count--; + } + + /* Make sure nothing else is happening... */ + 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) || + (matchmaker_start_count != pivot) || (male_end_count != pivot) || + (female_end_count != pivot) || (matchmaker_end_count != pivot)) { + loop_status = FAIL; + } + lock_release(testlock); + } + if (failif((loop_status == FAIL), "failed: uncoordinated matchmaking is occurring")) { + goto done; + } + + /* + * Release the rest of the matchmakers and wait for everyone to finish. + */ + + 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--; } } whalemating_cleanup(); + 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++) { + kprintf_t("."); + j = i * 3; + int male = match_status[j]; + int female = match_status[j + 1]; + failif((male == 0 || female == 0), "failed: not all males were matched"); + } + } else { + failif(true, "failed: not all males were matched"); + } + +done: + for (i = 0; i < total_count; i++) { + P(endsem); + } + + lock_destroy(testlock); + 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; } @@ -207,19 +429,76 @@ 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++) { + failif((quadrant_array[i] > 1), "failed: collision"); + 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 +509,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 +528,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,36 +545,110 @@ 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: + failif((pre_quadrant != UNKNOWN_CAR), "failed: invalid turn"); + break; + case 1: + 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; + failif((pre_quadrant != target_quadrant), "failed: invalid turn"); + target_quadrant = (target_quadrant + NUM_QUADRANTS - 1) % NUM_QUADRANTS; + break; + default: + failif(true, "failed: invalid turn"); + break; + } + failif((quadrant != target_quadrant), "failed: invalid turn"); + car_turn_times[index]++; + + failif((quadrant_array[quadrant] > 0), "failed: collision"); + + 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: + failif((car_turn_times[index] != 2), "failed: incorrect turn"); + break; + case TURN_LEFT: + failif((car_turn_times[index] != 3), "failed: incorrect turn"); + break; + case TURN_RIGHT: + failif((car_turn_times[index] != 1), "failed: incorrect turn"); + break; + default: + failif(true, "failed: incorrect turn"); + break; + } + + car_locations[index] = PASSED_CAR; + lock_release(testlock); kprintf_n("%s left the intersection\n", curthread->t_name); } -#define NCARS 64 - -struct semaphore * stoplightMenuSemaphore; - int stoplight(int nargs, char **args) { (void) nargs; (void) args; int i, direction, turn, err = 0; char name[32]; + int required_quadrant = 0; + int passed = 0; + + max_car_count = 0; + all_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; + } + + 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; - inititems(NCARS); stoplight_init(); for (i = 0; i < NCARS; i++) { + kprintf_t("."); direction = random() % 4; turn = random() % 3; @@ -301,26 +656,48 @@ 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++) { + kprintf_t("."); P(endsem); } stoplight_cleanup(); + for (i = 0; i < NCARS; i++) { + passed += car_locations[i] == PASSED_CAR ? 1 : 0; + } + 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); + sem_destroy(endsem); + + 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 6290921..a90173d 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 @@ -40,152 +43,134 @@ #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"); - } +bool +failif(bool condition) { + if (condition) { + spinlock_acquire(&status_lock); + test_status = FAIL; + spinlock_release(&status_lock); } - 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); + return condition; } - 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); - for (i=0; i #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; @@ -780,18 +782,21 @@ subpage_stats(struct pageref *pr) } } - 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)); } /* @@ -808,12 +813,34 @@ kheap_printstats(void) 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 number of used heap bytes. + */ +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"); +} + //////////////////////////////////////// /*