Changes for ASST1 testing.
This commit is contained in:
		@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,6 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#undef SECRET_TESTING
 | 
			
		||||
#define SECRET 0
 | 
			
		||||
#define SECRET "SECRET"
 | 
			
		||||
 | 
			
		||||
#endif /* _SECRET_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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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 },
 | 
			
		||||
 
 | 
			
		||||
@@ -3,55 +3,54 @@
 | 
			
		||||
#include <thread.h>
 | 
			
		||||
#include <test.h>
 | 
			
		||||
#include <lib.h>
 | 
			
		||||
#include <kern/secure.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										23
									
								
								kern/test/rwtest.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								kern/test/rwtest.c
									
									
									
									
									
										Normal file
									
								
							@@ -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 <types.h>
 | 
			
		||||
#include <lib.h>
 | 
			
		||||
#include <clock.h>
 | 
			
		||||
#include <thread.h>
 | 
			
		||||
#include <synch.h>
 | 
			
		||||
#include <test.h>
 | 
			
		||||
#include <kern/secret.h>
 | 
			
		||||
#include <spinlock.h>
 | 
			
		||||
 | 
			
		||||
int rwtest(int nargs, char **args) {
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("rwt1 unimplemented\n");
 | 
			
		||||
	success(FAIL, SECRET, "rwt1");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -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 <test.h>
 | 
			
		||||
#include <current.h>
 | 
			
		||||
#include <synch.h>
 | 
			
		||||
#include <kern/secret.h>
 | 
			
		||||
#include <spinlock.h>
 | 
			
		||||
 | 
			
		||||
#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;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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 <types.h>
 | 
			
		||||
@@ -40,152 +43,134 @@
 | 
			
		||||
#include <kern/secret.h>
 | 
			
		||||
#include <spinlock.h>
 | 
			
		||||
 | 
			
		||||
#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<NSEMLOOPS; i++) {
 | 
			
		||||
		kprintf_n("%c", (int)num+64);
 | 
			
		||||
		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");
 | 
			
		||||
 | 
			
		||||
	V(donesem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
semtest(int nargs, char **args)
 | 
			
		||||
{
 | 
			
		||||
	int i, result;
 | 
			
		||||
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
 | 
			
		||||
	inititems();
 | 
			
		||||
	test_status = FAIL;
 | 
			
		||||
	kprintf_n("Starting semaphore test...\n");
 | 
			
		||||
	int i, result;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("Starting sem1...\n");
 | 
			
		||||
	for (i=0; i<CREATELOOPS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		testsem = sem_create("testsem", 2);
 | 
			
		||||
		if (testsem == NULL) {
 | 
			
		||||
			panic("sem1: sem_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		donesem = sem_create("donesem", 0);
 | 
			
		||||
		if (donesem == NULL) {
 | 
			
		||||
			panic("sem1: sem_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (i != CREATELOOPS - 1) {
 | 
			
		||||
			sem_destroy(testsem);
 | 
			
		||||
			sem_destroy(donesem);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spinlock_init(&status_lock);
 | 
			
		||||
	test_status = SUCCESS;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("If this hangs, it's broken: ");
 | 
			
		||||
	P(testsem);
 | 
			
		||||
	P(testsem);
 | 
			
		||||
	test_status = SUCCESS;
 | 
			
		||||
	kprintf_n("ok\n");
 | 
			
		||||
	kprintf_n("OK\n");
 | 
			
		||||
	kprintf_t(".");
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<NTHREADS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		result = thread_fork("semtest", NULL, semtestthread, NULL, i);
 | 
			
		||||
		if (result) {
 | 
			
		||||
			panic("semtest: thread_fork failed: %s\n",
 | 
			
		||||
			panic("sem1: thread_fork failed: %s\n",
 | 
			
		||||
			      strerror(result));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<NTHREADS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		V(testsem);
 | 
			
		||||
		P(donesem);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* so we can run it again */
 | 
			
		||||
	V(testsem);
 | 
			
		||||
	V(testsem);
 | 
			
		||||
	
 | 
			
		||||
	kprintf_n("Semaphore test done.\n");
 | 
			
		||||
	success(test_status, SECRET, "sy1");
 | 
			
		||||
	sem_destroy(testsem);
 | 
			
		||||
	sem_destroy(donesem);
 | 
			
		||||
	testsem = donesem = NULL;
 | 
			
		||||
 | 
			
		||||
	kprintf_t("\n");
 | 
			
		||||
	success(test_status, SECRET, "sem1");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
fail(unsigned long num, const char *msg)
 | 
			
		||||
{
 | 
			
		||||
	kprintf_n("thread %lu: Mismatch on %s\n", num, msg);
 | 
			
		||||
	kprintf_n("Test failed\n");
 | 
			
		||||
 | 
			
		||||
	lock_release(testlock);
 | 
			
		||||
 | 
			
		||||
	spinlock_acquire(&status_lock);
 | 
			
		||||
	test_status = FAIL;
 | 
			
		||||
	spinlock_release(&status_lock);
 | 
			
		||||
 | 
			
		||||
	V(donesem);
 | 
			
		||||
	thread_exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static
 | 
			
		||||
void
 | 
			
		||||
locktestthread(void *junk, unsigned long num)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	(void)junk;
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<NLOCKLOOPS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		lock_acquire(testlock);
 | 
			
		||||
		random_yielder(4);
 | 
			
		||||
 | 
			
		||||
@@ -194,65 +179,174 @@ locktestthread(void *junk, unsigned long num)
 | 
			
		||||
		testval3 = num%3;
 | 
			
		||||
 | 
			
		||||
		if (testval2 != testval1*testval1) {
 | 
			
		||||
			fail(num, "testval2/testval1");
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		random_yielder(4);
 | 
			
		||||
 | 
			
		||||
		if (testval2%3 != (testval3*testval3)%3) {
 | 
			
		||||
			fail(num, "testval2/testval3");
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		random_yielder(4);
 | 
			
		||||
 | 
			
		||||
		if (testval3 != testval1%3) {
 | 
			
		||||
			fail(num, "testval3/testval1");
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		random_yielder(4);
 | 
			
		||||
 | 
			
		||||
		if (testval1 != num) {
 | 
			
		||||
			fail(num, "testval1/num");
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		random_yielder(4);
 | 
			
		||||
 | 
			
		||||
		if (testval2 != num*num) {
 | 
			
		||||
			fail(num, "testval2/num");
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		random_yielder(4);
 | 
			
		||||
 | 
			
		||||
		if (testval3 != num%3) {
 | 
			
		||||
			fail(num, "testval3/num");
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		random_yielder(4);
 | 
			
		||||
 | 
			
		||||
		if (!(lock_do_i_hold(testlock))) {
 | 
			
		||||
			goto fail;
 | 
			
		||||
		}
 | 
			
		||||
		random_yielder(4);
 | 
			
		||||
 | 
			
		||||
		lock_release(testlock);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Check for solutions that don't track ownership properly */
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<NLOCKLOOPS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		if (lock_do_i_hold(testlock)) {
 | 
			
		||||
			goto fail2;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	V(donesem);
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
	lock_release(testlock);
 | 
			
		||||
fail2:
 | 
			
		||||
	failif(true);
 | 
			
		||||
	V(donesem);
 | 
			
		||||
	return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
locktest(int nargs, char **args)
 | 
			
		||||
{
 | 
			
		||||
	int i, result;
 | 
			
		||||
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
 | 
			
		||||
	inititems();
 | 
			
		||||
	int i, result;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("Starting lt1...\n");
 | 
			
		||||
	for (i=0; i<CREATELOOPS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		testlock = lock_create("testlock");
 | 
			
		||||
		if (testlock == NULL) {
 | 
			
		||||
			panic("lt1: lock_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		donesem = sem_create("donesem", 0);
 | 
			
		||||
		if (donesem == NULL) {
 | 
			
		||||
			panic("lt1: sem_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (i != CREATELOOPS - 1) {
 | 
			
		||||
			lock_destroy(testlock);
 | 
			
		||||
			sem_destroy(donesem);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spinlock_init(&status_lock);
 | 
			
		||||
	test_status = SUCCESS;
 | 
			
		||||
	kprintf_n("Starting lock test...\n");
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<NTHREADS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		result = thread_fork("synchtest", NULL, locktestthread, NULL, i);
 | 
			
		||||
		if (result) {
 | 
			
		||||
			panic("locktest: thread_fork failed: %s\n", strerror(result));
 | 
			
		||||
			panic("lt1: thread_fork failed: %s\n", strerror(result));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for (i=0; i<NTHREADS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		P(donesem);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	kprintf_n("Lock test done.\n");
 | 
			
		||||
	success(test_status, SECRET, "sy2");
 | 
			
		||||
 | 
			
		||||
	lock_destroy(testlock);
 | 
			
		||||
	sem_destroy(donesem);
 | 
			
		||||
	testlock = NULL;
 | 
			
		||||
	donesem = NULL;
 | 
			
		||||
 | 
			
		||||
	kprintf_t("\n");
 | 
			
		||||
	success(test_status, SECRET, "lt1");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
locktest2(int nargs, char **args) {
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("Starting lt2...\n");
 | 
			
		||||
	kprintf_n("(This test panics on success!)\n");
 | 
			
		||||
	for (i=0; i<CREATELOOPS; i++) {
 | 
			
		||||
		testlock = lock_create("testlock");
 | 
			
		||||
		if (testlock == NULL) {
 | 
			
		||||
			panic("lt2: lock_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (i != CREATELOOPS - 1) {
 | 
			
		||||
			lock_destroy(testlock);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ksecprintf(SECRET, "Should panic...", "lt2");
 | 
			
		||||
	lock_release(testlock);
 | 
			
		||||
 | 
			
		||||
	/* Should not get here on success. */
 | 
			
		||||
 | 
			
		||||
	success(FAIL, SECRET, "lt2");
 | 
			
		||||
 | 
			
		||||
	lock_destroy(testlock);
 | 
			
		||||
	testlock = NULL;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
locktest3(int nargs, char **args) {
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("Starting lt3...\n");
 | 
			
		||||
	kprintf_n("(This test panics on success!)\n");
 | 
			
		||||
	for (i=0; i<CREATELOOPS; i++) {
 | 
			
		||||
		testlock = lock_create("testlock");
 | 
			
		||||
		if (testlock == NULL) {
 | 
			
		||||
			panic("lt3: lock_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (i != CREATELOOPS - 1) {
 | 
			
		||||
			lock_destroy(testlock);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ksecprintf(SECRET, "Should panic...", "lt3");
 | 
			
		||||
	lock_acquire(testlock);
 | 
			
		||||
	lock_destroy(testlock);
 | 
			
		||||
 | 
			
		||||
	/* Should not get here on success. */
 | 
			
		||||
 | 
			
		||||
	success(FAIL, SECRET, "lt3");
 | 
			
		||||
 | 
			
		||||
	testlock = NULL;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -261,13 +355,14 @@ static
 | 
			
		||||
void
 | 
			
		||||
cvtestthread(void *junk, unsigned long num)
 | 
			
		||||
{
 | 
			
		||||
	(void)junk;
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
	volatile int j;
 | 
			
		||||
	struct timespec ts1, ts2;
 | 
			
		||||
 | 
			
		||||
	(void)junk;
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<NCVLOOPS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		lock_acquire(testlock);
 | 
			
		||||
		while (testval1 != num) {
 | 
			
		||||
			testval2 = 0;
 | 
			
		||||
@@ -283,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();
 | 
			
		||||
			}
 | 
			
		||||
@@ -304,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;
 | 
			
		||||
@@ -321,29 +409,57 @@ cvtestthread(void *junk, unsigned long num)
 | 
			
		||||
int
 | 
			
		||||
cvtest(int nargs, char **args)
 | 
			
		||||
{
 | 
			
		||||
	int i, result;
 | 
			
		||||
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
 | 
			
		||||
	inititems();
 | 
			
		||||
	kprintf_n("Starting CV test...\n");
 | 
			
		||||
	kprintf_n("Threads should print out in reverse order.\n");
 | 
			
		||||
	int i, result;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("Starting cvt1...\n");
 | 
			
		||||
	for (i=0; i<CREATELOOPS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		testlock = lock_create("testlock");
 | 
			
		||||
		if (testlock == NULL) {
 | 
			
		||||
			panic("lockt1: lock_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		testcv = cv_create("testcv");
 | 
			
		||||
		if (testcv == NULL) {
 | 
			
		||||
			panic("cvt1: cv_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		donesem = sem_create("donesem", 0);
 | 
			
		||||
		if (donesem == NULL) {
 | 
			
		||||
			panic("cvt1: sem_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (i != CREATELOOPS - 1) {
 | 
			
		||||
			lock_destroy(testlock);
 | 
			
		||||
			cv_destroy(testcv);
 | 
			
		||||
			sem_destroy(donesem);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	spinlock_init(&status_lock);
 | 
			
		||||
	test_status = SUCCESS;
 | 
			
		||||
 | 
			
		||||
	testval1 = NTHREADS-1;
 | 
			
		||||
 | 
			
		||||
	for (i=0; i<NTHREADS; i++) {
 | 
			
		||||
		result = thread_fork("synchtest", NULL, cvtestthread, NULL, (long unsigned) i);
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		result = thread_fork("cvt1", NULL, cvtestthread, NULL, (long unsigned) i);
 | 
			
		||||
		if (result) {
 | 
			
		||||
			panic("cvtest: thread_fork failed: %s\n", strerror(result));
 | 
			
		||||
			panic("cvt1: thread_fork failed: %s\n", strerror(result));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for (i=0; i<NTHREADS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		P(donesem);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	kprintf_n("CV test done\n");
 | 
			
		||||
	success(test_status, SECRET, "sy3");
 | 
			
		||||
 | 
			
		||||
	lock_destroy(testlock);
 | 
			
		||||
	cv_destroy(testcv);
 | 
			
		||||
	sem_destroy(donesem);
 | 
			
		||||
	testlock = NULL;
 | 
			
		||||
	testcv = NULL;
 | 
			
		||||
	donesem = NULL;
 | 
			
		||||
 | 
			
		||||
	kprintf_t("\n");
 | 
			
		||||
	success(test_status, SECRET, "cvt1");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -369,14 +485,15 @@ static
 | 
			
		||||
void
 | 
			
		||||
sleepthread(void *junk1, unsigned long junk2)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i, j;
 | 
			
		||||
 | 
			
		||||
	(void)junk1;
 | 
			
		||||
	(void)junk2;
 | 
			
		||||
 | 
			
		||||
	unsigned i, j;
 | 
			
		||||
	
 | 
			
		||||
	random_yielder(4);
 | 
			
		||||
 | 
			
		||||
	for (j=0; j<NLOOPS; j++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		for (i=0; i<NCVS; i++) {
 | 
			
		||||
			lock_acquire(testlocks[i]);
 | 
			
		||||
			random_yielder(4);
 | 
			
		||||
@@ -398,26 +515,23 @@ static
 | 
			
		||||
void
 | 
			
		||||
wakethread(void *junk1, unsigned long junk2)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i, j;
 | 
			
		||||
 | 
			
		||||
	(void)junk1;
 | 
			
		||||
	(void)junk2;
 | 
			
		||||
 | 
			
		||||
	unsigned i, j;
 | 
			
		||||
 | 
			
		||||
	random_yielder(4);
 | 
			
		||||
 | 
			
		||||
	for (j=0; j<NLOOPS; j++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		for (i=0; i<NCVS; i++) {
 | 
			
		||||
			random_yielder(4);
 | 
			
		||||
			P(gatesem);
 | 
			
		||||
			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]);
 | 
			
		||||
@@ -430,33 +544,44 @@ wakethread(void *junk1, unsigned long junk2)
 | 
			
		||||
int
 | 
			
		||||
cvtest2(int nargs, char **args)
 | 
			
		||||
{
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
	
 | 
			
		||||
	inititems();
 | 
			
		||||
	test_status = SUCCESS;
 | 
			
		||||
	unsigned i;
 | 
			
		||||
	int result;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("Starting cvt2...\n");
 | 
			
		||||
	for (i=0; i<CREATELOOPS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		gatesem = sem_create("gatesem", 0);
 | 
			
		||||
		if (gatesem == NULL) {
 | 
			
		||||
			panic("cvt2: sem_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		exitsem = sem_create("exitsem", 0);
 | 
			
		||||
		if (exitsem == NULL) {
 | 
			
		||||
			panic("cvt2: sem_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (i != CREATELOOPS - 1) {
 | 
			
		||||
			sem_destroy(gatesem);
 | 
			
		||||
			sem_destroy(exitsem);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for (i=0; i<NCVS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		testlocks[i] = lock_create("cvtest2 lock");
 | 
			
		||||
		testcvs[i] = cv_create("cvtest2 cv");
 | 
			
		||||
	}
 | 
			
		||||
	gatesem = sem_create("gatesem", 0);
 | 
			
		||||
	exitsem = sem_create("exitsem", 0);
 | 
			
		||||
	spinlock_init(&status_lock);
 | 
			
		||||
	test_status = SUCCESS;
 | 
			
		||||
 | 
			
		||||
	kprintf_n("cvtest2...\n");
 | 
			
		||||
 | 
			
		||||
	result = thread_fork("cvtest2", NULL, sleepthread, NULL, 0);
 | 
			
		||||
	result = thread_fork("cvt2", NULL, sleepthread, NULL, 0);
 | 
			
		||||
	if (result) {
 | 
			
		||||
		panic("cvtest2: thread_fork failed\n");
 | 
			
		||||
		panic("cvt2: thread_fork failed\n");
 | 
			
		||||
	}
 | 
			
		||||
	result = thread_fork("cvtest2", NULL, wakethread, NULL, 0);
 | 
			
		||||
	result = thread_fork("cvt2", NULL, wakethread, NULL, 0);
 | 
			
		||||
	if (result) {
 | 
			
		||||
		panic("cvtest2: thread_fork failed\n");
 | 
			
		||||
		panic("cvt2: thread_fork failed\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	P(exitsem);
 | 
			
		||||
	P(exitsem);
 | 
			
		||||
 | 
			
		||||
@@ -464,29 +589,93 @@ cvtest2(int nargs, char **args)
 | 
			
		||||
	sem_destroy(gatesem);
 | 
			
		||||
	exitsem = gatesem = NULL;
 | 
			
		||||
	for (i=0; i<NCVS; i++) {
 | 
			
		||||
		kprintf_t(".");
 | 
			
		||||
		lock_destroy(testlocks[i]);
 | 
			
		||||
		cv_destroy(testcvs[i]);
 | 
			
		||||
		testlocks[i] = NULL;
 | 
			
		||||
		testcvs[i] = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kprintf_n("cvtest2 done\n");
 | 
			
		||||
	success(test_status, SECRET, "sy4");
 | 
			
		||||
	kprintf_t("\n");
 | 
			
		||||
	success(test_status, SECRET, "cvt2");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Complete this for ASST1.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
cvtest3(int nargs, char **args) {
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
 | 
			
		||||
int rwtest(int nargs, char **args) {
 | 
			
		||||
	int i;
 | 
			
		||||
	
 | 
			
		||||
	(void) nargs;
 | 
			
		||||
	(void) args;
 | 
			
		||||
	
 | 
			
		||||
	kprintf_n("rwtest unimplemented\n");
 | 
			
		||||
	success(FAIL, SECRET, "sy5");
 | 
			
		||||
	kprintf_n("Starting cvt3...\n");
 | 
			
		||||
	kprintf_n("(This test panics on success!)\n");
 | 
			
		||||
	for (i=0; i<CREATELOOPS; i++) {
 | 
			
		||||
		testlock = lock_create("testlock");
 | 
			
		||||
		if (testlock == NULL) {
 | 
			
		||||
			panic("lockt1: lock_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		testcv = cv_create("testcv");
 | 
			
		||||
		if (testcv == NULL) {
 | 
			
		||||
			panic("cvt1: cv_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (i != CREATELOOPS - 1) {
 | 
			
		||||
			lock_destroy(testlock);
 | 
			
		||||
			cv_destroy(testcv);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ksecprintf(SECRET, "Should panic...", "cvt3");
 | 
			
		||||
	cv_wait(testcv, testlock);
 | 
			
		||||
 | 
			
		||||
	/* Should not get here on success. */
 | 
			
		||||
 | 
			
		||||
	success(FAIL, SECRET, "cvt3");
 | 
			
		||||
 | 
			
		||||
	lock_destroy(testlock);
 | 
			
		||||
	cv_destroy(testcv);
 | 
			
		||||
	testcv = NULL;
 | 
			
		||||
	testlock = NULL;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
cvtest4(int nargs, char **args) {
 | 
			
		||||
	(void)nargs;
 | 
			
		||||
	(void)args;
 | 
			
		||||
 | 
			
		||||
	int i;
 | 
			
		||||
	
 | 
			
		||||
	kprintf_n("Starting cvt4...\n");
 | 
			
		||||
	kprintf_n("(This test panics on success!)\n");
 | 
			
		||||
	for (i=0; i<CREATELOOPS; i++) {
 | 
			
		||||
		testlock = lock_create("testlock");
 | 
			
		||||
		if (testlock == NULL) {
 | 
			
		||||
			panic("lockt1: lock_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		testcv = cv_create("testcv");
 | 
			
		||||
		if (testcv == NULL) {
 | 
			
		||||
			panic("cvt1: cv_create failed\n");
 | 
			
		||||
		}
 | 
			
		||||
		if (i != CREATELOOPS - 1) {
 | 
			
		||||
			lock_destroy(testlock);
 | 
			
		||||
			cv_destroy(testcv);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ksecprintf(SECRET, "Should panic...", "cvt4");
 | 
			
		||||
	cv_broadcast(testcv, testlock);
 | 
			
		||||
 | 
			
		||||
	/* Should not get here on success. */
 | 
			
		||||
 | 
			
		||||
	success(FAIL, SECRET, "cvt4");
 | 
			
		||||
 | 
			
		||||
	lock_destroy(testlock);
 | 
			
		||||
	cv_destroy(testcv);
 | 
			
		||||
	testcv = NULL;
 | 
			
		||||
	testlock = NULL;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,8 @@
 | 
			
		||||
#include <lib.h>
 | 
			
		||||
#include <spinlock.h>
 | 
			
		||||
#include <vm.h>
 | 
			
		||||
#include <kern/secret.h>
 | 
			
		||||
#include <test.h>
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * 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; i<n; i++) {
 | 
			
		||||
		int val = (freemap[i/32] & (1<<(i%32)))!=0;
 | 
			
		||||
		kprintf("%c", val ? '.' : '*');
 | 
			
		||||
		if (i%64==63 && i<n-1) {
 | 
			
		||||
			kprintf("\n   ");
 | 
			
		||||
	if (!quiet) {
 | 
			
		||||
		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; i<n; i++) {
 | 
			
		||||
			int val = (freemap[i/32] & (1<<(i%32)))!=0;
 | 
			
		||||
			kprintf("%c", val ? '.' : '*');
 | 
			
		||||
			if (i%64==63 && i<n-1) {
 | 
			
		||||
				kprintf("\n   ");
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		kprintf("\n");
 | 
			
		||||
	}
 | 
			
		||||
	kprintf("\n");
 | 
			
		||||
	return ((unsigned long)sizes[blktype] * (n - (unsigned) pr->nfree));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -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");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user