Changes for ASST1 testing.
This commit is contained in:
commit
5cbbbd8b29
@ -442,6 +442,7 @@ file test/threadlisttest.c
|
|||||||
file test/threadtest.c
|
file test/threadtest.c
|
||||||
file test/tt3.c
|
file test/tt3.c
|
||||||
file test/synchtest.c
|
file test/synchtest.c
|
||||||
|
file test/rwtest.c
|
||||||
file test/semunit.c
|
file test/semunit.c
|
||||||
file test/hmacunit.c
|
file test/hmacunit.c
|
||||||
file test/kmalloctest.c
|
file test/kmalloctest.c
|
||||||
|
@ -45,6 +45,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#undef SECRET_TESTING
|
#undef SECRET_TESTING
|
||||||
#define SECRET 0
|
#define SECRET "SECRET"
|
||||||
|
|
||||||
#endif /* _SECRET_H_ */
|
#endif /* _SECRET_H_ */
|
||||||
|
@ -129,6 +129,7 @@ uint32_t random(void);
|
|||||||
void *kmalloc(size_t size);
|
void *kmalloc(size_t size);
|
||||||
void kfree(void *ptr);
|
void kfree(void *ptr);
|
||||||
void kheap_printstats(void);
|
void kheap_printstats(void);
|
||||||
|
void kheap_printused(void);
|
||||||
void kheap_nextgeneration(void);
|
void kheap_nextgeneration(void);
|
||||||
void kheap_dump(void);
|
void kheap_dump(void);
|
||||||
void kheap_dumpall(void);
|
void kheap_dumpall(void);
|
||||||
|
@ -59,8 +59,12 @@ int threadtest2(int, char **);
|
|||||||
int threadtest3(int, char **);
|
int threadtest3(int, char **);
|
||||||
int semtest(int, char **);
|
int semtest(int, char **);
|
||||||
int locktest(int, char **);
|
int locktest(int, char **);
|
||||||
|
int locktest2(int, char **);
|
||||||
|
int locktest3(int, char **);
|
||||||
int cvtest(int, char **);
|
int cvtest(int, char **);
|
||||||
int cvtest2(int, char **);
|
int cvtest2(int, char **);
|
||||||
|
int cvtest3(int, char **);
|
||||||
|
int cvtest4(int, char **);
|
||||||
int rwtest(int, char **);
|
int rwtest(int, char **);
|
||||||
|
|
||||||
/* semaphore unit tests */
|
/* semaphore unit tests */
|
||||||
@ -172,7 +176,9 @@ int ll16test(int, char **);
|
|||||||
#define SUCCESS 0
|
#define SUCCESS 0
|
||||||
#define FAIL 1
|
#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_yielder(uint32_t);
|
||||||
void random_spinner(uint32_t);
|
void random_spinner(uint32_t);
|
||||||
|
@ -376,6 +376,18 @@ cmd_kheapstats(int nargs, char **args)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
cmd_kheapused(int nargs, char **args)
|
||||||
|
{
|
||||||
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
|
kheap_printused();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
cmd_kheapgeneration(int nargs, char **args)
|
cmd_kheapgeneration(int nargs, char **args)
|
||||||
@ -475,14 +487,18 @@ static const char *testmenu[] = {
|
|||||||
#if OPT_NET
|
#if OPT_NET
|
||||||
"[net] Network test ",
|
"[net] Network test ",
|
||||||
#endif
|
#endif
|
||||||
"[sy1] Semaphore test ",
|
"[sem1] Semaphore test ",
|
||||||
"[sy2] Lock test (1) ",
|
"[lt1] Lock test 1 (1) ",
|
||||||
"[sy3] CV test (1) ",
|
"[lt2] Lock test 2 (panics) (1) ",
|
||||||
"[sy4] CV test #2 (1) ",
|
"[lt3] Lock test 3 (panics) (1) ",
|
||||||
"[sy5] RW lock test (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
|
#if OPT_SYNCHPROBS
|
||||||
"[sp1] Whalemating test (1) ",
|
"[sp1] Whalemating test (1) ",
|
||||||
"[sp2] Stoplight test (1) ",
|
"[sp2] Stoplight test (1) ",
|
||||||
#endif
|
#endif
|
||||||
"[semu1-22] Semaphore unit tests ",
|
"[semu1-22] Semaphore unit tests ",
|
||||||
"[fs1] Filesystem test ",
|
"[fs1] Filesystem test ",
|
||||||
@ -537,6 +553,7 @@ static const char *mainmenu[] = {
|
|||||||
"[?o] Operations menu ",
|
"[?o] Operations menu ",
|
||||||
"[?t] Tests menu ",
|
"[?t] Tests menu ",
|
||||||
"[kh] Kernel heap stats ",
|
"[kh] Kernel heap stats ",
|
||||||
|
"[khu] Kernel heap usage ",
|
||||||
"[khgen] Next kernel heap generation ",
|
"[khgen] Next kernel heap generation ",
|
||||||
"[khdump] Dump kernel heap ",
|
"[khdump] Dump kernel heap ",
|
||||||
"[q] Quit and shut down ",
|
"[q] Quit and shut down ",
|
||||||
@ -589,6 +606,7 @@ static struct {
|
|||||||
|
|
||||||
/* stats */
|
/* stats */
|
||||||
{ "kh", cmd_kheapstats },
|
{ "kh", cmd_kheapstats },
|
||||||
|
{ "khu", cmd_kheapused },
|
||||||
{ "khgen", cmd_kheapgeneration },
|
{ "khgen", cmd_kheapgeneration },
|
||||||
{ "khdump", cmd_kheapdump },
|
{ "khdump", cmd_kheapdump },
|
||||||
|
|
||||||
@ -607,13 +625,17 @@ static struct {
|
|||||||
{ "tt1", threadtest },
|
{ "tt1", threadtest },
|
||||||
{ "tt2", threadtest2 },
|
{ "tt2", threadtest2 },
|
||||||
{ "tt3", threadtest3 },
|
{ "tt3", threadtest3 },
|
||||||
{ "sy1", semtest },
|
|
||||||
|
|
||||||
/* synchronization assignment tests */
|
/* synchronization assignment tests */
|
||||||
{ "sy2", locktest },
|
{ "sem1", semtest },
|
||||||
{ "sy3", cvtest },
|
{ "lt1", locktest },
|
||||||
{ "sy4", cvtest2 },
|
{ "lt2", locktest2 },
|
||||||
{ "sy5", rwtest },
|
{ "lt3", locktest3 },
|
||||||
|
{ "cvt1", cvtest },
|
||||||
|
{ "cvt2", cvtest2 },
|
||||||
|
{ "cvt3", cvtest3 },
|
||||||
|
{ "cvt4", cvtest4 },
|
||||||
|
{ "rwt1", rwtest },
|
||||||
#if OPT_SYNCHPROBS
|
#if OPT_SYNCHPROBS
|
||||||
{ "sp1", whalemating },
|
{ "sp1", whalemating },
|
||||||
{ "sp2", stoplight },
|
{ "sp2", stoplight },
|
||||||
|
@ -3,55 +3,54 @@
|
|||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include <test.h>
|
#include <test.h>
|
||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
|
#include <kern/secure.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Main success function for kernel tests. Prints a multiple of the secret if
|
* Common success function for kernel tests. If SECRET_TESTING is defined,
|
||||||
* the secret is non-zero and the test succeeded. Otherwise prints a random
|
* ksecprintf will compute the hmac/sha256 hash of any message using the
|
||||||
* number.
|
* 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.
|
||||||
* Ideally we would multiply the secret (a large prime) by another large prime
|
* The salt value prevents against replay attacks.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
|
int
|
||||||
#define MIN_MULTIPLIER 0x80000000
|
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
|
#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;
|
(void)secret;
|
||||||
if (status == SUCCESS) {
|
return kprintf("%s: %s\n", name, msg);
|
||||||
kprintf("%s: SUCCESS\n", name);
|
|
||||||
} else {
|
|
||||||
kprintf("%s: FAIL\n", name);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
void
|
|
||||||
success(bool status, uint32_t secret, const char * name) {
|
int
|
||||||
uint32_t multiplier;
|
ksecprintf(const char * secret, const char * msg, const char * name)
|
||||||
// Make sure we can get large random numbers
|
{
|
||||||
KASSERT(randmax() == 0xffffffff);
|
char *hash;
|
||||||
while (1) {
|
char *salt;
|
||||||
multiplier = random();
|
int res;
|
||||||
// We can at least remove the obvious non-primes...
|
|
||||||
if (multiplier % 2 == 0) {
|
res = hmac_salted(msg, strlen(msg), secret, strlen(secret), &hash, &salt);
|
||||||
continue;
|
if (res)
|
||||||
}
|
return -res;
|
||||||
if (multiplier > MIN_MULTIPLIER) {
|
|
||||||
break;
|
res = kprintf("(%s, %s, %s, %s: %s)\n", name, hash, salt, name, msg);
|
||||||
}
|
|
||||||
}
|
kfree(hash);
|
||||||
uint64_t big_secret = (uint64_t) secret * (uint64_t) multiplier;
|
kfree(salt);
|
||||||
if (status == SUCCESS) {
|
|
||||||
kprintf("%s: SUCCESS (%llu)\n", name, big_secret);
|
return res;
|
||||||
} else {
|
|
||||||
kprintf("%s: FAIL (%llu)\n", name, big_secret);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#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
|
* All the contents of this file are overwritten during automated
|
||||||
* testing. Please consider this before changing anything in this file.
|
* testing. Please consider this before changing anything in this file.
|
||||||
*/
|
*/
|
||||||
@ -11,81 +9,134 @@
|
|||||||
#include <test.h>
|
#include <test.h>
|
||||||
#include <current.h>
|
#include <current.h>
|
||||||
#include <synch.h>
|
#include <synch.h>
|
||||||
|
#include <kern/secret.h>
|
||||||
|
#include <spinlock.h>
|
||||||
|
|
||||||
#define PROBLEMS_MAX_YIELDER 16
|
#define PROBLEMS_MAX_YIELDER 16
|
||||||
#define PROBLEMS_MAX_SPINNER 8192
|
#define PROBLEMS_MAX_SPINNER 8192
|
||||||
|
|
||||||
|
#define SUCCESS 0
|
||||||
|
#define FAIL 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Shared initialization routines
|
* Shared initialization routines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static uint32_t startcount;
|
static uint32_t startcount;
|
||||||
static struct lock *startlock;
|
static struct lock *testlock;
|
||||||
static struct cv *startcv;
|
static struct cv *startcv;
|
||||||
|
static struct semaphore *startsem;
|
||||||
static struct semaphore *endsem;
|
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
|
static
|
||||||
void
|
void
|
||||||
inititems(uint32_t count)
|
initialize_thread(volatile void* threads[], uint32_t index) {
|
||||||
{
|
failif((threads[index] != NULL), "failed: incorrect thread type");
|
||||||
startcount = count;
|
threads[index] = curthread->t_stack;
|
||||||
|
}
|
||||||
|
|
||||||
if (startlock==NULL) {
|
/*
|
||||||
startlock = lock_create("startlock");
|
* Helper function to check whether current thread is valid.
|
||||||
if (startlock == NULL) {
|
*/
|
||||||
panic("synchprobs: lock_create failed\n");
|
static
|
||||||
}
|
void
|
||||||
}
|
check_thread(volatile void* threads[], uint32_t index) {
|
||||||
if (startcv==NULL) {
|
failif((threads[index] != curthread->t_stack), "failed: incorrect thread type");
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Driver code for the whalemating problem.
|
* 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
|
static
|
||||||
void
|
void
|
||||||
male_wrapper(void * unused1, unsigned long index) {
|
male_wrapper(void * unused1, unsigned long index) {
|
||||||
(void)unused1;
|
(void)unused1;
|
||||||
|
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
lock_acquire(startlock);
|
lock_acquire(testlock);
|
||||||
startcount--;
|
initialize_thread(whale_threads, (uint32_t)index);
|
||||||
if (startcount == 0) {
|
whale_roles[index] = MALE;
|
||||||
cv_broadcast(startcv, startlock);
|
lock_release(testlock);
|
||||||
} else {
|
|
||||||
cv_wait(startcv, startlock);
|
|
||||||
}
|
|
||||||
lock_release(startlock);
|
|
||||||
male((uint32_t)index);
|
male((uint32_t)index);
|
||||||
V(endsem);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
male_start(uint32_t index) {
|
male_start(uint32_t index) {
|
||||||
(void)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_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
random_spinner(PROBLEMS_MAX_SPINNER);
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
kprintf_n("%s starting\n", curthread->t_name);
|
kprintf_n("%s starting\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
V(startsem);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
male_end(uint32_t index) {
|
male_end(uint32_t index) {
|
||||||
(void)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_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
random_spinner(PROBLEMS_MAX_SPINNER);
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
kprintf_n("%s ending\n", curthread->t_name);
|
kprintf_n("%s ending\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
V(endsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@ -94,69 +145,99 @@ female_wrapper(void * unused1, unsigned long index) {
|
|||||||
(void)unused1;
|
(void)unused1;
|
||||||
|
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
lock_acquire(startlock);
|
lock_acquire(testlock);
|
||||||
startcount--;
|
initialize_thread(whale_threads, (uint32_t)index);
|
||||||
if (startcount == 0) {
|
whale_roles[index] = FEMALE;
|
||||||
cv_broadcast(startcv, startlock);
|
lock_release(testlock);
|
||||||
} else {
|
|
||||||
cv_wait(startcv, startlock);
|
|
||||||
}
|
|
||||||
lock_release(startlock);
|
|
||||||
female((uint32_t)index);
|
female((uint32_t)index);
|
||||||
V(endsem);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
female_start(uint32_t index) {
|
female_start(uint32_t index) {
|
||||||
(void) 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_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
random_spinner(PROBLEMS_MAX_SPINNER);
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
kprintf_n("%s starting\n", curthread->t_name);
|
kprintf_n("%s starting\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
V(startsem);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
female_end(uint32_t index) {
|
female_end(uint32_t index) {
|
||||||
(void) 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_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
random_spinner(PROBLEMS_MAX_SPINNER);
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
kprintf_n("%s ending\n", curthread->t_name);
|
kprintf_n("%s ending\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
V(endsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
matchmaker_wrapper(void * unused1, unsigned long index) {
|
matchmaker_wrapper(void * unused1, unsigned long index) {
|
||||||
(void)unused1;
|
(void)unused1;
|
||||||
|
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
lock_acquire(startlock);
|
lock_acquire(testlock);
|
||||||
startcount--;
|
initialize_thread(whale_threads, (uint32_t)index);
|
||||||
if (startcount == 0) {
|
whale_roles[index] = MATCHMAKER;
|
||||||
cv_broadcast(startcv, startlock);
|
lock_release(testlock);
|
||||||
} else {
|
|
||||||
cv_wait(startcv, startlock);
|
|
||||||
}
|
|
||||||
lock_release(startlock);
|
|
||||||
matchmaker((uint32_t)index);
|
matchmaker((uint32_t)index);
|
||||||
V(endsem);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
matchmaker_start(uint32_t index) {
|
matchmaker_start(uint32_t index) {
|
||||||
(void)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_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
random_spinner(PROBLEMS_MAX_SPINNER);
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
kprintf_n("%s starting\n", curthread->t_name);
|
kprintf_n("%s starting\n", curthread->t_name);
|
||||||
|
kprintf_t(".");
|
||||||
|
V(startsem);
|
||||||
}
|
}
|
||||||
void
|
void
|
||||||
matchmaker_end(uint32_t index) {
|
matchmaker_end(uint32_t index) {
|
||||||
(void)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_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
random_spinner(PROBLEMS_MAX_SPINNER);
|
random_spinner(PROBLEMS_MAX_SPINNER);
|
||||||
kprintf_n("%s ending\n", curthread->t_name);
|
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
|
int
|
||||||
whalemating(int nargs, char **args) {
|
whalemating(int nargs, char **args) {
|
||||||
@ -165,13 +246,45 @@ whalemating(int nargs, char **args) {
|
|||||||
|
|
||||||
int i, j, err = 0;
|
int i, j, err = 0;
|
||||||
char name[32];
|
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();
|
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++) {
|
for (j = 0; j < NMATING; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
int index = (i * NMATING) + j;
|
int index = (i * NMATING) + j;
|
||||||
|
whale_threads[index] = NULL;
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
snprintf(name, sizeof(name), "Male Whale Thread %d", index);
|
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);
|
snprintf(name, sizeof(name), "Female Whale Thread %d", index);
|
||||||
err = thread_fork(name, NULL, female_wrapper, NULL, index);
|
err = thread_fork(name, NULL, female_wrapper, NULL, index);
|
||||||
break;
|
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) {
|
if (err) {
|
||||||
panic("whalemating: thread_fork failed: (%s)\n", strerror(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 (i = 0; i < 3; i++) {
|
||||||
for (j = 0; j < NMATING; j++) {
|
for (j = pivot; j < NMATING; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
P(endsem);
|
P(endsem);
|
||||||
|
total_count--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
whalemating_cleanup();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,19 +429,76 @@ whalemating(int nargs, char **args) {
|
|||||||
* Driver code for the stoplight problem.
|
* 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
|
static
|
||||||
void
|
void
|
||||||
turnright_wrapper(void *index, unsigned long direction)
|
turnright_wrapper(void *index, unsigned long direction)
|
||||||
{
|
{
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
lock_acquire(startlock);
|
lock_acquire(testlock);
|
||||||
|
initialize_car_thread((uint32_t)index, (uint32_t)direction, TURN_RIGHT);
|
||||||
startcount--;
|
startcount--;
|
||||||
if (startcount == 0) {
|
if (startcount == 0) {
|
||||||
cv_broadcast(startcv, startlock);
|
cv_broadcast(startcv, testlock);
|
||||||
} else {
|
} else {
|
||||||
cv_wait(startcv, startlock);
|
cv_wait(startcv, testlock);
|
||||||
}
|
}
|
||||||
lock_release(startlock);
|
lock_release(testlock);
|
||||||
turnright((uint32_t)direction, (uint32_t)index);
|
turnright((uint32_t)direction, (uint32_t)index);
|
||||||
V(endsem);
|
V(endsem);
|
||||||
|
|
||||||
@ -230,14 +509,15 @@ void
|
|||||||
gostraight_wrapper(void *index, unsigned long direction)
|
gostraight_wrapper(void *index, unsigned long direction)
|
||||||
{
|
{
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
lock_acquire(startlock);
|
lock_acquire(testlock);
|
||||||
|
initialize_car_thread((uint32_t)index, (uint32_t)direction, GO_STRAIGHT);
|
||||||
startcount--;
|
startcount--;
|
||||||
if (startcount == 0) {
|
if (startcount == 0) {
|
||||||
cv_broadcast(startcv, startlock);
|
cv_broadcast(startcv, testlock);
|
||||||
} else {
|
} else {
|
||||||
cv_wait(startcv, startlock);
|
cv_wait(startcv, testlock);
|
||||||
}
|
}
|
||||||
lock_release(startlock);
|
lock_release(testlock);
|
||||||
gostraight((uint32_t)direction, (uint32_t)index);
|
gostraight((uint32_t)direction, (uint32_t)index);
|
||||||
V(endsem);
|
V(endsem);
|
||||||
|
|
||||||
@ -248,14 +528,15 @@ void
|
|||||||
turnleft_wrapper(void *index, unsigned long direction)
|
turnleft_wrapper(void *index, unsigned long direction)
|
||||||
{
|
{
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
lock_acquire(startlock);
|
lock_acquire(testlock);
|
||||||
|
initialize_car_thread((uint32_t)index, (uint32_t)direction, TURN_LEFT);
|
||||||
startcount--;
|
startcount--;
|
||||||
if (startcount == 0) {
|
if (startcount == 0) {
|
||||||
cv_broadcast(startcv, startlock);
|
cv_broadcast(startcv, testlock);
|
||||||
} else {
|
} else {
|
||||||
cv_wait(startcv, startlock);
|
cv_wait(startcv, testlock);
|
||||||
}
|
}
|
||||||
lock_release(startlock);
|
lock_release(testlock);
|
||||||
turnleft((uint32_t)direction, (uint32_t)index);
|
turnleft((uint32_t)direction, (uint32_t)index);
|
||||||
V(endsem);
|
V(endsem);
|
||||||
|
|
||||||
@ -264,36 +545,110 @@ turnleft_wrapper(void *index, unsigned long direction)
|
|||||||
|
|
||||||
void
|
void
|
||||||
inQuadrant(int quadrant, uint32_t index) {
|
inQuadrant(int quadrant, uint32_t index) {
|
||||||
(void)index;
|
|
||||||
|
|
||||||
random_yielder(PROBLEMS_MAX_YIELDER);
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
random_spinner(PROBLEMS_MAX_SPINNER);
|
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);
|
kprintf_n("%s in quadrant %d\n", curthread->t_name, quadrant);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
leaveIntersection(uint32_t index) {
|
leaveIntersection(uint32_t index) {
|
||||||
(void)index;
|
|
||||||
|
|
||||||
random_yielder(PROBLEMS_MAX_YIELDER);
|
random_yielder(PROBLEMS_MAX_YIELDER);
|
||||||
random_spinner(PROBLEMS_MAX_SPINNER);
|
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);
|
kprintf_n("%s left the intersection\n", curthread->t_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NCARS 64
|
|
||||||
|
|
||||||
struct semaphore * stoplightMenuSemaphore;
|
|
||||||
|
|
||||||
int stoplight(int nargs, char **args) {
|
int stoplight(int nargs, char **args) {
|
||||||
(void) nargs;
|
(void) nargs;
|
||||||
(void) args;
|
(void) args;
|
||||||
int i, direction, turn, err = 0;
|
int i, direction, turn, err = 0;
|
||||||
char name[32];
|
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();
|
stoplight_init();
|
||||||
|
|
||||||
for (i = 0; i < NCARS; i++) {
|
for (i = 0; i < NCARS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
|
|
||||||
direction = random() % 4;
|
direction = random() % 4;
|
||||||
turn = random() % 3;
|
turn = random() % 3;
|
||||||
@ -301,26 +656,48 @@ int stoplight(int nargs, char **args) {
|
|||||||
snprintf(name, sizeof(name), "Car Thread %d", i);
|
snprintf(name, sizeof(name), "Car Thread %d", i);
|
||||||
|
|
||||||
switch (turn) {
|
switch (turn) {
|
||||||
case 0:
|
case GO_STRAIGHT:
|
||||||
err = thread_fork(name, NULL, gostraight_wrapper, (void *)i, direction);
|
err = thread_fork(name, NULL, gostraight_wrapper, (void *)i, direction);
|
||||||
|
required_quadrant += 2;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case TURN_LEFT:
|
||||||
err = thread_fork(name, NULL, turnleft_wrapper, (void *)i, direction);
|
err = thread_fork(name, NULL, turnleft_wrapper, (void *)i, direction);
|
||||||
|
required_quadrant += 3;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case TURN_RIGHT:
|
||||||
err = thread_fork(name, NULL, turnright_wrapper, (void *)i, direction);
|
err = thread_fork(name, NULL, turnright_wrapper, (void *)i, direction);
|
||||||
|
required_quadrant += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
panic("stoplight: thread_fork failed: (%s)\n", strerror(err));
|
panic("stoplight: thread_fork failed: (%s)\n", strerror(err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NCARS; i++) {
|
for (i = 0; i < NCARS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
P(endsem);
|
P(endsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
stoplight_cleanup();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,9 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Synchronization test code.
|
* 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>
|
#include <types.h>
|
||||||
@ -40,152 +43,134 @@
|
|||||||
#include <kern/secret.h>
|
#include <kern/secret.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
|
|
||||||
|
#define CREATELOOPS 8
|
||||||
#define NSEMLOOPS 63
|
#define NSEMLOOPS 63
|
||||||
#define NLOCKLOOPS 120
|
#define NLOCKLOOPS 120
|
||||||
#define NCVLOOPS 5
|
#define NCVLOOPS 5
|
||||||
#define NTHREADS 32
|
#define NTHREADS 32
|
||||||
|
#define SYNCHTEST_YIELDER_MAX 16
|
||||||
|
|
||||||
static volatile unsigned long testval1;
|
static volatile unsigned long testval1;
|
||||||
static volatile unsigned long testval2;
|
static volatile unsigned long testval2;
|
||||||
static volatile unsigned long testval3;
|
static volatile unsigned long testval3;
|
||||||
static volatile int32_t testval4;
|
static volatile int32_t testval4;
|
||||||
|
|
||||||
static struct semaphore *testsem;
|
static struct semaphore *testsem = NULL;
|
||||||
static struct lock *testlock;
|
static struct lock *testlock = NULL;
|
||||||
static struct cv *testcv;
|
static struct cv *testcv = NULL;
|
||||||
static struct semaphore *donesem;
|
static struct semaphore *donesem = NULL;
|
||||||
|
|
||||||
struct spinlock status_lock;
|
struct spinlock status_lock;
|
||||||
static bool test_status;
|
static bool test_status = FAIL;
|
||||||
|
|
||||||
static unsigned long semtest_current;
|
static unsigned long semtest_current;
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
bool
|
||||||
inititems(void)
|
failif(bool condition) {
|
||||||
{
|
if (condition) {
|
||||||
if (testsem==NULL) {
|
spinlock_acquire(&status_lock);
|
||||||
testsem = sem_create("testsem", 2);
|
test_status = FAIL;
|
||||||
if (testsem == NULL) {
|
spinlock_release(&status_lock);
|
||||||
panic("synchtest: sem_create failed\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (testlock==NULL) {
|
return condition;
|
||||||
testlock = lock_create("testlock");
|
|
||||||
if (testlock == NULL) {
|
|
||||||
panic("synchtest: lock_create failed\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (testcv==NULL) {
|
|
||||||
testcv = cv_create("testlock");
|
|
||||||
if (testcv == NULL) {
|
|
||||||
panic("synchtest: cv_create failed\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (donesem==NULL) {
|
|
||||||
donesem = sem_create("donesem", 0);
|
|
||||||
if (donesem == NULL) {
|
|
||||||
panic("synchtest: sem_create failed\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spinlock_init(&status_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
semtestthread(void *junk, unsigned long num)
|
semtestthread(void *junk, unsigned long num)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
(void)junk;
|
(void)junk;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only one of these should print at a time.
|
* Only one of these should print at a time.
|
||||||
*/
|
*/
|
||||||
random_yielder(4);
|
|
||||||
P(testsem);
|
P(testsem);
|
||||||
semtest_current = num;
|
semtest_current = num;
|
||||||
|
|
||||||
kprintf_n("Thread %2lu: ", num);
|
kprintf_n("Thread %2lu: ", num);
|
||||||
|
|
||||||
for (i=0; i<NSEMLOOPS; i++) {
|
for (i=0; i<NSEMLOOPS; i++) {
|
||||||
kprintf_n("%c", (int)num+64);
|
kprintf_t(".");
|
||||||
|
kprintf_n("%2lu", num);
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
if (semtest_current != num) {
|
failif((semtest_current != num));
|
||||||
spinlock_acquire(&status_lock);
|
|
||||||
test_status = FAIL;
|
|
||||||
spinlock_release(&status_lock);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf_n("\n");
|
kprintf_n("\n");
|
||||||
|
|
||||||
V(donesem);
|
V(donesem);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
semtest(int nargs, char **args)
|
semtest(int nargs, char **args)
|
||||||
{
|
{
|
||||||
int i, result;
|
|
||||||
|
|
||||||
(void)nargs;
|
(void)nargs;
|
||||||
(void)args;
|
(void)args;
|
||||||
|
|
||||||
inititems();
|
int i, result;
|
||||||
test_status = FAIL;
|
|
||||||
kprintf_n("Starting semaphore test...\n");
|
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: ");
|
kprintf_n("If this hangs, it's broken: ");
|
||||||
P(testsem);
|
P(testsem);
|
||||||
P(testsem);
|
P(testsem);
|
||||||
test_status = SUCCESS;
|
kprintf_n("OK\n");
|
||||||
kprintf_n("ok\n");
|
kprintf_t(".");
|
||||||
|
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
result = thread_fork("semtest", NULL, semtestthread, NULL, i);
|
result = thread_fork("semtest", NULL, semtestthread, NULL, i);
|
||||||
if (result) {
|
if (result) {
|
||||||
panic("semtest: thread_fork failed: %s\n",
|
panic("sem1: thread_fork failed: %s\n",
|
||||||
strerror(result));
|
strerror(result));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
V(testsem);
|
V(testsem);
|
||||||
P(donesem);
|
P(donesem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* so we can run it again */
|
sem_destroy(testsem);
|
||||||
V(testsem);
|
sem_destroy(donesem);
|
||||||
V(testsem);
|
testsem = donesem = NULL;
|
||||||
|
|
||||||
kprintf_n("Semaphore test done.\n");
|
kprintf_t("\n");
|
||||||
success(test_status, SECRET, "sy1");
|
success(test_status, SECRET, "sem1");
|
||||||
|
|
||||||
return 0;
|
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
|
static
|
||||||
void
|
void
|
||||||
locktestthread(void *junk, unsigned long num)
|
locktestthread(void *junk, unsigned long num)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
(void)junk;
|
(void)junk;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i=0; i<NLOCKLOOPS; i++) {
|
for (i=0; i<NLOCKLOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
lock_acquire(testlock);
|
lock_acquire(testlock);
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
@ -194,65 +179,174 @@ locktestthread(void *junk, unsigned long num)
|
|||||||
testval3 = num%3;
|
testval3 = num%3;
|
||||||
|
|
||||||
if (testval2 != testval1*testval1) {
|
if (testval2 != testval1*testval1) {
|
||||||
fail(num, "testval2/testval1");
|
goto fail;
|
||||||
}
|
}
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
if (testval2%3 != (testval3*testval3)%3) {
|
if (testval2%3 != (testval3*testval3)%3) {
|
||||||
fail(num, "testval2/testval3");
|
goto fail;
|
||||||
}
|
}
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
if (testval3 != testval1%3) {
|
if (testval3 != testval1%3) {
|
||||||
fail(num, "testval3/testval1");
|
goto fail;
|
||||||
}
|
}
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
if (testval1 != num) {
|
if (testval1 != num) {
|
||||||
fail(num, "testval1/num");
|
goto fail;
|
||||||
}
|
}
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
if (testval2 != num*num) {
|
if (testval2 != num*num) {
|
||||||
fail(num, "testval2/num");
|
goto fail;
|
||||||
}
|
}
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
if (testval3 != num%3) {
|
if (testval3 != num%3) {
|
||||||
fail(num, "testval3/num");
|
goto fail;
|
||||||
|
}
|
||||||
|
random_yielder(4);
|
||||||
|
|
||||||
|
if (!(lock_do_i_hold(testlock))) {
|
||||||
|
goto fail;
|
||||||
}
|
}
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
lock_release(testlock);
|
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);
|
V(donesem);
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
lock_release(testlock);
|
||||||
|
fail2:
|
||||||
|
failif(true);
|
||||||
|
V(donesem);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
locktest(int nargs, char **args)
|
locktest(int nargs, char **args)
|
||||||
{
|
{
|
||||||
int i, result;
|
|
||||||
|
|
||||||
(void)nargs;
|
(void)nargs;
|
||||||
(void)args;
|
(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;
|
test_status = SUCCESS;
|
||||||
kprintf_n("Starting lock test...\n");
|
|
||||||
|
|
||||||
for (i=0; i<NTHREADS; i++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
result = thread_fork("synchtest", NULL, locktestthread, NULL, i);
|
result = thread_fork("synchtest", NULL, locktestthread, NULL, i);
|
||||||
if (result) {
|
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++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
P(donesem);
|
P(donesem);
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf_n("Lock test done.\n");
|
lock_destroy(testlock);
|
||||||
success(test_status, SECRET, "sy2");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -261,13 +355,14 @@ static
|
|||||||
void
|
void
|
||||||
cvtestthread(void *junk, unsigned long num)
|
cvtestthread(void *junk, unsigned long num)
|
||||||
{
|
{
|
||||||
|
(void)junk;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
volatile int j;
|
volatile int j;
|
||||||
struct timespec ts1, ts2;
|
struct timespec ts1, ts2;
|
||||||
|
|
||||||
(void)junk;
|
|
||||||
|
|
||||||
for (i=0; i<NCVLOOPS; i++) {
|
for (i=0; i<NCVLOOPS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
lock_acquire(testlock);
|
lock_acquire(testlock);
|
||||||
while (testval1 != num) {
|
while (testval1 != num) {
|
||||||
testval2 = 0;
|
testval2 = 0;
|
||||||
@ -283,10 +378,8 @@ cvtestthread(void *junk, unsigned long num)
|
|||||||
/* Require at least 2000 cpu cycles (we're 25mhz) */
|
/* Require at least 2000 cpu cycles (we're 25mhz) */
|
||||||
if (ts2.tv_sec == 0 && ts2.tv_nsec < 40*2000) {
|
if (ts2.tv_sec == 0 && ts2.tv_nsec < 40*2000) {
|
||||||
kprintf_n("cv_wait took only %u ns\n", ts2.tv_nsec);
|
kprintf_n("cv_wait took only %u ns\n", ts2.tv_nsec);
|
||||||
kprintf_n("That's too fast... you must be " "busy-looping\n");
|
kprintf_n("That's too fast... you must be busy-looping\n");
|
||||||
spinlock_acquire(&status_lock);
|
failif(true);
|
||||||
test_status = FAIL;
|
|
||||||
spinlock_release(&status_lock);
|
|
||||||
V(donesem);
|
V(donesem);
|
||||||
thread_exit();
|
thread_exit();
|
||||||
}
|
}
|
||||||
@ -304,12 +397,7 @@ cvtestthread(void *junk, unsigned long num)
|
|||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
cv_broadcast(testcv, testlock);
|
cv_broadcast(testcv, testlock);
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
failif((testval1 != testval2));
|
||||||
spinlock_acquire(&status_lock);
|
|
||||||
if (testval1 != testval2) {
|
|
||||||
test_status = FAIL;
|
|
||||||
}
|
|
||||||
spinlock_release(&status_lock);
|
|
||||||
|
|
||||||
kprintf_n("Thread %lu\n", testval2);
|
kprintf_n("Thread %lu\n", testval2);
|
||||||
testval1 = (testval1 + NTHREADS - 1) % NTHREADS;
|
testval1 = (testval1 + NTHREADS - 1) % NTHREADS;
|
||||||
@ -321,29 +409,57 @@ cvtestthread(void *junk, unsigned long num)
|
|||||||
int
|
int
|
||||||
cvtest(int nargs, char **args)
|
cvtest(int nargs, char **args)
|
||||||
{
|
{
|
||||||
int i, result;
|
|
||||||
|
|
||||||
(void)nargs;
|
(void)nargs;
|
||||||
(void)args;
|
(void)args;
|
||||||
|
|
||||||
inititems();
|
int i, result;
|
||||||
kprintf_n("Starting CV test...\n");
|
|
||||||
kprintf_n("Threads should print out in reverse order.\n");
|
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;
|
testval1 = NTHREADS-1;
|
||||||
|
|
||||||
for (i=0; i<NTHREADS; i++) {
|
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) {
|
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++) {
|
for (i=0; i<NTHREADS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
P(donesem);
|
P(donesem);
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf_n("CV test done\n");
|
lock_destroy(testlock);
|
||||||
success(test_status, SECRET, "sy3");
|
cv_destroy(testcv);
|
||||||
|
sem_destroy(donesem);
|
||||||
|
testlock = NULL;
|
||||||
|
testcv = NULL;
|
||||||
|
donesem = NULL;
|
||||||
|
|
||||||
|
kprintf_t("\n");
|
||||||
|
success(test_status, SECRET, "cvt1");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -369,14 +485,15 @@ static
|
|||||||
void
|
void
|
||||||
sleepthread(void *junk1, unsigned long junk2)
|
sleepthread(void *junk1, unsigned long junk2)
|
||||||
{
|
{
|
||||||
unsigned i, j;
|
|
||||||
|
|
||||||
(void)junk1;
|
(void)junk1;
|
||||||
(void)junk2;
|
(void)junk2;
|
||||||
|
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
for (j=0; j<NLOOPS; j++) {
|
for (j=0; j<NLOOPS; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
for (i=0; i<NCVS; i++) {
|
for (i=0; i<NCVS; i++) {
|
||||||
lock_acquire(testlocks[i]);
|
lock_acquire(testlocks[i]);
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
@ -398,26 +515,23 @@ static
|
|||||||
void
|
void
|
||||||
wakethread(void *junk1, unsigned long junk2)
|
wakethread(void *junk1, unsigned long junk2)
|
||||||
{
|
{
|
||||||
unsigned i, j;
|
|
||||||
|
|
||||||
(void)junk1;
|
(void)junk1;
|
||||||
(void)junk2;
|
(void)junk2;
|
||||||
|
|
||||||
|
unsigned i, j;
|
||||||
|
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
|
|
||||||
for (j=0; j<NLOOPS; j++) {
|
for (j=0; j<NLOOPS; j++) {
|
||||||
|
kprintf_t(".");
|
||||||
for (i=0; i<NCVS; i++) {
|
for (i=0; i<NCVS; i++) {
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
P(gatesem);
|
P(gatesem);
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
lock_acquire(testlocks[i]);
|
lock_acquire(testlocks[i]);
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
spinlock_acquire(&status_lock);
|
|
||||||
testval4--;
|
testval4--;
|
||||||
if (testval4 != 0) {
|
failif((testval4 != 0));
|
||||||
test_status = FAIL;
|
|
||||||
}
|
|
||||||
spinlock_release(&status_lock);
|
|
||||||
cv_signal(testcvs[i], testlocks[i]);
|
cv_signal(testcvs[i], testlocks[i]);
|
||||||
random_yielder(4);
|
random_yielder(4);
|
||||||
lock_release(testlocks[i]);
|
lock_release(testlocks[i]);
|
||||||
@ -430,33 +544,44 @@ wakethread(void *junk1, unsigned long junk2)
|
|||||||
int
|
int
|
||||||
cvtest2(int nargs, char **args)
|
cvtest2(int nargs, char **args)
|
||||||
{
|
{
|
||||||
unsigned i;
|
|
||||||
int result;
|
|
||||||
|
|
||||||
(void)nargs;
|
(void)nargs;
|
||||||
(void)args;
|
(void)args;
|
||||||
|
|
||||||
inititems();
|
unsigned i;
|
||||||
test_status = SUCCESS;
|
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++) {
|
for (i=0; i<NCVS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
testlocks[i] = lock_create("cvtest2 lock");
|
testlocks[i] = lock_create("cvtest2 lock");
|
||||||
testcvs[i] = cv_create("cvtest2 cv");
|
testcvs[i] = cv_create("cvtest2 cv");
|
||||||
}
|
}
|
||||||
gatesem = sem_create("gatesem", 0);
|
spinlock_init(&status_lock);
|
||||||
exitsem = sem_create("exitsem", 0);
|
test_status = SUCCESS;
|
||||||
|
|
||||||
kprintf_n("cvtest2...\n");
|
result = thread_fork("cvt2", NULL, sleepthread, NULL, 0);
|
||||||
|
|
||||||
result = thread_fork("cvtest2", NULL, sleepthread, NULL, 0);
|
|
||||||
if (result) {
|
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) {
|
if (result) {
|
||||||
panic("cvtest2: thread_fork failed\n");
|
panic("cvt2: thread_fork failed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
P(exitsem);
|
P(exitsem);
|
||||||
P(exitsem);
|
P(exitsem);
|
||||||
|
|
||||||
@ -464,29 +589,93 @@ cvtest2(int nargs, char **args)
|
|||||||
sem_destroy(gatesem);
|
sem_destroy(gatesem);
|
||||||
exitsem = gatesem = NULL;
|
exitsem = gatesem = NULL;
|
||||||
for (i=0; i<NCVS; i++) {
|
for (i=0; i<NCVS; i++) {
|
||||||
|
kprintf_t(".");
|
||||||
lock_destroy(testlocks[i]);
|
lock_destroy(testlocks[i]);
|
||||||
cv_destroy(testcvs[i]);
|
cv_destroy(testcvs[i]);
|
||||||
testlocks[i] = NULL;
|
testlocks[i] = NULL;
|
||||||
testcvs[i] = NULL;
|
testcvs[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf_n("cvtest2 done\n");
|
kprintf_t("\n");
|
||||||
success(test_status, SECRET, "sy4");
|
success(test_status, SECRET, "cvt2");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
int
|
||||||
* Complete this for ASST1.
|
cvtest3(int nargs, char **args) {
|
||||||
*/
|
(void)nargs;
|
||||||
|
(void)args;
|
||||||
|
|
||||||
int rwtest(int nargs, char **args) {
|
int i;
|
||||||
|
|
||||||
(void) nargs;
|
kprintf_n("Starting cvt3...\n");
|
||||||
(void) args;
|
kprintf_n("(This test panics on success!)\n");
|
||||||
|
for (i=0; i<CREATELOOPS; i++) {
|
||||||
kprintf_n("rwtest unimplemented\n");
|
testlock = lock_create("testlock");
|
||||||
success(FAIL, SECRET, "sy5");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
#include <lib.h>
|
#include <lib.h>
|
||||||
#include <spinlock.h>
|
#include <spinlock.h>
|
||||||
#include <vm.h>
|
#include <vm.h>
|
||||||
|
#include <kern/secret.h>
|
||||||
|
#include <test.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kernel malloc.
|
* Kernel malloc.
|
||||||
@ -743,8 +745,8 @@ kheap_dumpall(void)
|
|||||||
* Print the allocated/freed map of a single kernel heap page.
|
* Print the allocated/freed map of a single kernel heap page.
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
void
|
unsigned long
|
||||||
subpage_stats(struct pageref *pr)
|
subpage_stats(struct pageref *pr, bool quiet)
|
||||||
{
|
{
|
||||||
vaddr_t prpage, fla;
|
vaddr_t prpage, fla;
|
||||||
struct freelist *fl;
|
struct freelist *fl;
|
||||||
@ -780,18 +782,21 @@ subpage_stats(struct pageref *pr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kprintf("at 0x%08lx: size %-4lu %u/%u free\n",
|
if (!quiet) {
|
||||||
(unsigned long)prpage, (unsigned long) sizes[blktype],
|
kprintf("at 0x%08lx: size %-4lu %u/%u free\n",
|
||||||
(unsigned) pr->nfree, n);
|
(unsigned long)prpage, (unsigned long) sizes[blktype],
|
||||||
kprintf(" ");
|
(unsigned) pr->nfree, n);
|
||||||
for (i=0; i<n; i++) {
|
kprintf(" ");
|
||||||
int val = (freemap[i/32] & (1<<(i%32)))!=0;
|
for (i=0; i<n; i++) {
|
||||||
kprintf("%c", val ? '.' : '*');
|
int val = (freemap[i/32] & (1<<(i%32)))!=0;
|
||||||
if (i%64==63 && i<n-1) {
|
kprintf("%c", val ? '.' : '*');
|
||||||
kprintf("\n ");
|
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");
|
kprintf("Subpage allocator status:\n");
|
||||||
|
|
||||||
for (pr = allbase; pr != NULL; pr = pr->next_all) {
|
for (pr = allbase; pr != NULL; pr = pr->next_all) {
|
||||||
subpage_stats(pr);
|
subpage_stats(pr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
spinlock_release(&kmalloc_spinlock);
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////
|
////////////////////////////////////////
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user