@@ -33,13 +33,19 @@
|
||||
#include <types.h>
|
||||
#include <kern/errno.h>
|
||||
#include <lib.h>
|
||||
#include <cpu.h>
|
||||
#include <thread.h>
|
||||
#include <synch.h>
|
||||
#include <vm.h> /* for PAGE_SIZE */
|
||||
#include <test.h>
|
||||
#include <kern/test161.h>
|
||||
#include <mainbus.h>
|
||||
|
||||
#include "opt-dumbvm.h"
|
||||
|
||||
// from arch/mips/vm/ram.c
|
||||
extern vaddr_t firstfree;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// km1/km2
|
||||
|
||||
@@ -58,6 +64,12 @@
|
||||
#define ITEMSIZE 997
|
||||
#define NTHREADS 8
|
||||
|
||||
#define PROGRESS(iter) do { \
|
||||
if ((iter % 100) == 0) { \
|
||||
kprintf("."); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static
|
||||
void
|
||||
kmallocthread(void *sm, unsigned long num)
|
||||
@@ -69,15 +81,16 @@ kmallocthread(void *sm, unsigned long num)
|
||||
int i;
|
||||
|
||||
for (i=0; i<NTRIES; i++) {
|
||||
PROGRESS(i);
|
||||
ptr = kmalloc(ITEMSIZE);
|
||||
if (ptr==NULL) {
|
||||
if (sem) {
|
||||
kprintf("thread %lu: kmalloc returned NULL\n",
|
||||
num);
|
||||
goto done;
|
||||
panic("kmalloc test failed");
|
||||
}
|
||||
kprintf("kmalloc returned null; test failed.\n");
|
||||
goto done;
|
||||
panic("kmalloc test failed");
|
||||
}
|
||||
if (oldptr2) {
|
||||
kfree(oldptr2);
|
||||
@@ -85,7 +98,7 @@ kmallocthread(void *sm, unsigned long num)
|
||||
oldptr2 = oldptr;
|
||||
oldptr = ptr;
|
||||
}
|
||||
done:
|
||||
|
||||
if (oldptr2) {
|
||||
kfree(oldptr2);
|
||||
}
|
||||
@@ -105,7 +118,8 @@ kmalloctest(int nargs, char **args)
|
||||
|
||||
kprintf("Starting kmalloc test...\n");
|
||||
kmallocthread(NULL, 0);
|
||||
kprintf("kmalloc test done\n");
|
||||
kprintf("\n");
|
||||
success(TEST161_SUCCESS, SECRET, "km1");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -140,7 +154,8 @@ kmallocstress(int nargs, char **args)
|
||||
}
|
||||
|
||||
sem_destroy(sem);
|
||||
kprintf("kmalloc stress test done\n");
|
||||
kprintf("\n");
|
||||
success(TEST161_SUCCESS, SECRET, "km2");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -252,6 +267,7 @@ kmalloctest3(int nargs, char **args)
|
||||
curpos = 0;
|
||||
cursizeindex = 0;
|
||||
for (i=0; i<numptrs; i++) {
|
||||
PROGRESS(i);
|
||||
cursize = sizes[cursizeindex];
|
||||
ptr = ptrblocks[curblock][curpos];
|
||||
KASSERT(ptr != NULL);
|
||||
@@ -282,13 +298,15 @@ kmalloctest3(int nargs, char **args)
|
||||
|
||||
/* Free the lower tier. */
|
||||
for (i=0; i<numptrblocks; i++) {
|
||||
PROGRESS(i);
|
||||
KASSERT(ptrblocks[i] != NULL);
|
||||
kfree(ptrblocks[i]);
|
||||
}
|
||||
/* Free the upper tier. */
|
||||
kfree(ptrblocks);
|
||||
|
||||
kprintf("kmalloctest3: passed\n");
|
||||
kprintf("\n");
|
||||
success(TEST161_SUCCESS, SECRET, "km3");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -300,20 +318,24 @@ void
|
||||
kmalloctest4thread(void *sm, unsigned long num)
|
||||
{
|
||||
#define NUM_KM4_SIZES 5
|
||||
#define ITERATIONS 50
|
||||
static const unsigned sizes[NUM_KM4_SIZES] = { 1, 3, 5, 2, 4 };
|
||||
|
||||
struct semaphore *sem = sm;
|
||||
void *ptrs[NUM_KM4_SIZES];
|
||||
unsigned p, q;
|
||||
unsigned i;
|
||||
unsigned i, j, k;
|
||||
uint32_t magic;
|
||||
|
||||
for (i=0; i<NUM_KM4_SIZES; i++) {
|
||||
ptrs[i] = NULL;
|
||||
}
|
||||
p = 0;
|
||||
q = NUM_KM4_SIZES / 2;
|
||||
magic = random();
|
||||
|
||||
for (i=0; i<NTRIES; i++) {
|
||||
PROGRESS(i);
|
||||
if (ptrs[q] != NULL) {
|
||||
kfree(ptrs[q]);
|
||||
ptrs[q] = NULL;
|
||||
@@ -324,6 +346,24 @@ kmalloctest4thread(void *sm, unsigned long num)
|
||||
"allocating %u pages failed\n",
|
||||
num, sizes[p]);
|
||||
}
|
||||
|
||||
// Write to each page of the allocated memory and make sure nothing
|
||||
// overwrites it.
|
||||
for (k = 0; k < sizes[p]; k++) {
|
||||
*((uint32_t *)ptrs[p] + k*PAGE_SIZE/sizeof(uint32_t)) = magic;
|
||||
}
|
||||
|
||||
for (j = 0; j < ITERATIONS; j++) {
|
||||
random_yielder(4);
|
||||
for (k = 0; k < sizes[p]; k++) {
|
||||
uint32_t actual = *((uint32_t *)ptrs[p] + k*PAGE_SIZE/sizeof(uint32_t));
|
||||
if (actual != magic) {
|
||||
panic("km4: expected %u got %u. Your VM is broken!",
|
||||
magic, actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
magic++;
|
||||
p = (p + 1) % NUM_KM4_SIZES;
|
||||
q = (q + 1) % NUM_KM4_SIZES;
|
||||
}
|
||||
@@ -375,6 +415,193 @@ kmalloctest4(int nargs, char **args)
|
||||
}
|
||||
|
||||
sem_destroy(sem);
|
||||
kprintf("Multipage kmalloc test done\n");
|
||||
|
||||
kprintf("\n");
|
||||
success(TEST161_SUCCESS, SECRET, "km4");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline
|
||||
void
|
||||
km5_usage()
|
||||
{
|
||||
kprintf("usage: km5 [--avail <num_pages>] [--kernel <num_pages>]\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and free all physical memory a number of times. Along the we, we
|
||||
* check coremap_used_bytes to make sure it's reporting the number we're
|
||||
* expecting.
|
||||
*/
|
||||
int
|
||||
kmalloctest5(int nargs, char **args)
|
||||
{
|
||||
#define KM5_ITERATIONS 5
|
||||
|
||||
// We're expecting an even number of arguments, less arg[0].
|
||||
if (nargs > 5 || (nargs % 2) == 0) {
|
||||
km5_usage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned avail_page_slack = 0, kernel_page_limit = 0;
|
||||
int arg = 1;
|
||||
|
||||
while (arg < nargs) {
|
||||
if (strcmp(args[arg], "--avail") == 0) {
|
||||
arg++;
|
||||
avail_page_slack = atoi(args[arg++]);
|
||||
} else if (strcmp(args[arg], "--kernel") == 0) {
|
||||
arg++;
|
||||
kernel_page_limit = atoi(args[arg++]);
|
||||
} else {
|
||||
km5_usage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#if OPT_DUMBVM
|
||||
kprintf("(This test will not work with dumbvm)\n");
|
||||
#endif
|
||||
|
||||
// First, we need to figure out how much memory we're running with and how
|
||||
// much space it will take up if we maintain a pointer to each allocated
|
||||
// page. We do something similar to km3 - for 32 bit systems with
|
||||
// PAGE_SIZE == 4096, we can store 1024 pointers on a page. We keep an array
|
||||
// of page size blocks of pointers which in total can hold enough pointers
|
||||
// for each page of available physical memory.
|
||||
unsigned orig_used, ptrs_per_page, num_ptr_blocks, max_pages;
|
||||
unsigned total_ram, avail_ram, magic, orig_magic, known_pages;
|
||||
|
||||
ptrs_per_page = PAGE_SIZE / sizeof(void *);
|
||||
total_ram = mainbus_ramsize();
|
||||
avail_ram = total_ram - (uint32_t)(firstfree - MIPS_KSEG0);
|
||||
max_pages = (avail_ram + PAGE_SIZE-1) / PAGE_SIZE;
|
||||
num_ptr_blocks = (max_pages + ptrs_per_page-1) / ptrs_per_page;
|
||||
|
||||
// The array can go on the stack, we won't have that many
|
||||
// (sys161 16M max => 4 blocks)
|
||||
void **ptrs[num_ptr_blocks];
|
||||
|
||||
for (unsigned i = 0; i < num_ptr_blocks; i++) {
|
||||
ptrs[i] = kmalloc(PAGE_SIZE);
|
||||
if (ptrs[i] == NULL) {
|
||||
panic("Can't allocate ptr page!");
|
||||
}
|
||||
bzero(ptrs[i], PAGE_SIZE);
|
||||
}
|
||||
|
||||
kprintf("km5 --> phys ram: %uk avail ram: %uk (%u pages) ptr blocks: %u\n", total_ram/1024,
|
||||
avail_ram/1024, max_pages, num_ptr_blocks);
|
||||
|
||||
// Initially, there must be at least 1 page allocated for each thread stack,
|
||||
// one page for kmalloc for this thread struct, plus what we just allocated).
|
||||
// This probably isn't the GLB, but its a decent lower bound.
|
||||
orig_used = coremap_used_bytes();
|
||||
known_pages = num_cpus + num_ptr_blocks + 1;
|
||||
if (orig_used < known_pages * PAGE_SIZE) {
|
||||
panic ("Not enough pages initially allocated");
|
||||
}
|
||||
if ((orig_used % PAGE_SIZE) != 0) {
|
||||
panic("Coremap used bytes should be a multiple of PAGE_SIZE");
|
||||
}
|
||||
|
||||
// Test for kernel bloat.
|
||||
if (kernel_page_limit > 0) {
|
||||
uint32_t kpages = (total_ram - avail_ram + PAGE_SIZE) / PAGE_SIZE;
|
||||
if (kpages > kernel_page_limit) {
|
||||
panic("You're kernel is bloated! Max allowed pages: %d, used pages: %d",
|
||||
kernel_page_limit, kpages);
|
||||
}
|
||||
}
|
||||
|
||||
orig_magic = magic = random();
|
||||
|
||||
for (int i = 0; i < KM5_ITERATIONS; i++) {
|
||||
// Step 1: allocate all physical memory, with checks along the way
|
||||
unsigned int block, pos, oom, pages, used, prev;
|
||||
void *page;
|
||||
|
||||
block = pos = oom = pages = used = 0;
|
||||
prev = orig_used;
|
||||
|
||||
while (pages < max_pages+1) {
|
||||
PROGRESS(pages);
|
||||
page = kmalloc(PAGE_SIZE);
|
||||
if (page == NULL) {
|
||||
oom = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure we can write to the page
|
||||
*(uint32_t *)page = magic++;
|
||||
|
||||
// Make sure the number of used bytes is going up, and by increments of PAGE_SIZE
|
||||
used = coremap_used_bytes();
|
||||
if (used != prev + PAGE_SIZE) {
|
||||
panic("Allocation not equal to PAGE_SIZE. prev: %u used: %u", prev, used);
|
||||
}
|
||||
prev = used;
|
||||
|
||||
ptrs[block][pos] = page;
|
||||
pos++;
|
||||
if (pos >= ptrs_per_page) {
|
||||
pos = 0;
|
||||
block++;
|
||||
}
|
||||
pages++;
|
||||
}
|
||||
|
||||
// Step 2: Check that we were able to allocate a reasonable number of pages
|
||||
unsigned expected;
|
||||
if (avail_page_slack > 0 ) {
|
||||
// max avail pages + what we can prove we allocated + some slack
|
||||
expected = max_pages - (known_pages + avail_page_slack);
|
||||
} else {
|
||||
// At the very least, just so we know things are working.
|
||||
expected = 3;
|
||||
}
|
||||
|
||||
if (pages < expected) {
|
||||
panic("Expected to allocate at least %d pages, only allocated %d",
|
||||
expected, pages);
|
||||
}
|
||||
|
||||
// We tried to allocate 1 more page than is available in physical memory. That
|
||||
// should fail unless you're swapping out kernel pages, which you should
|
||||
// probably not be doing.
|
||||
if (!oom) {
|
||||
panic("Allocated more pages than physical memory. Are you swapping kernel pages?");
|
||||
}
|
||||
|
||||
// Step 3: free everything and check that we're back to where we started
|
||||
for (block = 0; block < num_ptr_blocks; block++) {
|
||||
for (pos = 0; pos < ptrs_per_page; pos++) {
|
||||
if (ptrs[block][pos] != NULL) {
|
||||
// Make sure we got unique addresses
|
||||
if ((*(uint32_t *)ptrs[block][pos]) != orig_magic++) {
|
||||
panic("km5: expected %u got %u - your VM is broken!",
|
||||
orig_magic-1, (*(uint32_t *)ptrs[block][pos]));
|
||||
}
|
||||
kfree(ptrs[block][pos]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we're back to where we started
|
||||
used = coremap_used_bytes();
|
||||
if (used != orig_used) {
|
||||
panic("orig (%u) != used (%u)", orig_used, used);
|
||||
}
|
||||
}
|
||||
|
||||
//Clean up the pointer blocks
|
||||
for (unsigned i = 0; i < num_ptr_blocks; i++) {
|
||||
kfree(ptrs[i]);
|
||||
}
|
||||
|
||||
kprintf("\n");
|
||||
success(TEST161_SUCCESS, SECRET, "km5");
|
||||
|
||||
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>
|
||||
@@ -37,185 +40,303 @@
|
||||
#include <thread.h>
|
||||
#include <synch.h>
|
||||
#include <test.h>
|
||||
#include <kern/test161.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 struct semaphore *testsem;
|
||||
static struct lock *testlock;
|
||||
static struct cv *testcv;
|
||||
static struct semaphore *donesem;
|
||||
static volatile int32_t testval4;
|
||||
|
||||
static struct semaphore *testsem = NULL;
|
||||
static struct semaphore *testsem2 = NULL;
|
||||
static struct lock *testlock = NULL;
|
||||
static struct lock *testlock2 = NULL;
|
||||
static struct cv *testcv = NULL;
|
||||
static struct semaphore *donesem = NULL;
|
||||
|
||||
struct spinlock status_lock;
|
||||
static bool test_status = TEST161_FAIL;
|
||||
|
||||
static unsigned long semtest_current;
|
||||
|
||||
static
|
||||
void
|
||||
inititems(void)
|
||||
{
|
||||
if (testsem==NULL) {
|
||||
testsem = sem_create("testsem", 2);
|
||||
if (testsem == NULL) {
|
||||
panic("synchtest: sem_create failed\n");
|
||||
}
|
||||
}
|
||||
if (testlock==NULL) {
|
||||
testlock = lock_create("testlock");
|
||||
if (testlock == NULL) {
|
||||
panic("synchtest: lock_create failed\n");
|
||||
}
|
||||
}
|
||||
if (testcv==NULL) {
|
||||
testcv = cv_create("testlock");
|
||||
if (testcv == NULL) {
|
||||
panic("synchtest: cv_create failed\n");
|
||||
}
|
||||
}
|
||||
if (donesem==NULL) {
|
||||
donesem = sem_create("donesem", 0);
|
||||
if (donesem == NULL) {
|
||||
panic("synchtest: sem_create failed\n");
|
||||
}
|
||||
bool
|
||||
failif(bool condition) {
|
||||
if (condition) {
|
||||
spinlock_acquire(&status_lock);
|
||||
test_status = TEST161_FAIL;
|
||||
spinlock_release(&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.
|
||||
*/
|
||||
P(testsem);
|
||||
kprintf("Thread %2lu: ", num);
|
||||
semtest_current = num;
|
||||
|
||||
kprintf_n("Thread %2lu: ", num);
|
||||
for (i=0; i<NSEMLOOPS; i++) {
|
||||
kprintf("%c", (int)num+64);
|
||||
kprintf_t(".");
|
||||
kprintf_n("%2lu", num);
|
||||
random_yielder(4);
|
||||
failif((semtest_current != num));
|
||||
}
|
||||
kprintf("\n");
|
||||
kprintf_n("\n");
|
||||
|
||||
V(donesem);
|
||||
}
|
||||
|
||||
int
|
||||
semtest(int nargs, char **args)
|
||||
{
|
||||
int i, result;
|
||||
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
inititems();
|
||||
kprintf("Starting semaphore test...\n");
|
||||
kprintf("If this hangs, it's broken: ");
|
||||
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 = TEST161_SUCCESS;
|
||||
|
||||
kprintf_n("If this hangs, it's broken: ");
|
||||
P(testsem);
|
||||
P(testsem);
|
||||
kprintf("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);
|
||||
sem_destroy(testsem);
|
||||
sem_destroy(donesem);
|
||||
testsem = donesem = NULL;
|
||||
|
||||
kprintf_t("\n");
|
||||
success(test_status, SECRET, "sem1");
|
||||
|
||||
kprintf("Semaphore test done.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
fail(unsigned long num, const char *msg)
|
||||
{
|
||||
kprintf("thread %lu: Mismatch on %s\n", num, msg);
|
||||
kprintf("Test failed\n");
|
||||
|
||||
lock_release(testlock);
|
||||
|
||||
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);
|
||||
|
||||
testval1 = num;
|
||||
testval2 = num*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();
|
||||
kprintf("Starting lock test...\n");
|
||||
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 = TEST161_SUCCESS;
|
||||
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
result = thread_fork("synchtest", NULL, locktestthread,
|
||||
NULL, 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("Lock test done.\n");
|
||||
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;
|
||||
|
||||
kprintf_n("Starting lt2...\n");
|
||||
kprintf_n("(This test panics on success!)\n");
|
||||
|
||||
testlock = lock_create("testlock");
|
||||
if (testlock == NULL) {
|
||||
panic("lt2: lock_create failed\n");
|
||||
}
|
||||
|
||||
secprintf(SECRET, "Should panic...", "lt2");
|
||||
lock_release(testlock);
|
||||
|
||||
/* Should not get here on success. */
|
||||
|
||||
success(TEST161_FAIL, SECRET, "lt2");
|
||||
|
||||
lock_destroy(testlock);
|
||||
testlock = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
locktest3(int nargs, char **args) {
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
kprintf_n("Starting lt3...\n");
|
||||
kprintf_n("(This test panics on success!)\n");
|
||||
|
||||
testlock = lock_create("testlock");
|
||||
if (testlock == NULL) {
|
||||
panic("lt3: lock_create failed\n");
|
||||
}
|
||||
|
||||
secprintf(SECRET, "Should panic...", "lt3");
|
||||
lock_acquire(testlock);
|
||||
lock_destroy(testlock);
|
||||
|
||||
/* Should not get here on success. */
|
||||
|
||||
success(TEST161_FAIL, SECRET, "lt3");
|
||||
|
||||
testlock = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -224,35 +345,38 @@ 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;
|
||||
random_yielder(4);
|
||||
gettime(&ts1);
|
||||
cv_wait(testcv, testlock);
|
||||
gettime(&ts2);
|
||||
random_yielder(4);
|
||||
|
||||
/* ts2 -= ts1 */
|
||||
timespec_sub(&ts2, &ts1, &ts2);
|
||||
|
||||
/* Require at least 2000 cpu cycles (we're 25mhz) */
|
||||
if (ts2.tv_sec == 0 && ts2.tv_nsec < 40*2000) {
|
||||
kprintf("cv_wait took only %u ns\n",
|
||||
ts2.tv_nsec);
|
||||
kprintf("That's too fast... you must be "
|
||||
"busy-looping\n");
|
||||
kprintf_n("cv_wait took only %u ns\n", ts2.tv_nsec);
|
||||
kprintf_n("That's too fast... you must be busy-looping\n");
|
||||
failif(true);
|
||||
V(donesem);
|
||||
thread_exit();
|
||||
}
|
||||
|
||||
testval2 = 0xFFFFFFFF;
|
||||
}
|
||||
kprintf("Thread %lu\n", num);
|
||||
testval1 = (testval1 + NTHREADS - 1)%NTHREADS;
|
||||
testval2 = num;
|
||||
|
||||
/*
|
||||
* loop a little while to make sure we can measure the
|
||||
@@ -260,7 +384,13 @@ cvtestthread(void *junk, unsigned long num)
|
||||
*/
|
||||
for (j=0; j<3000; j++);
|
||||
|
||||
random_yielder(4);
|
||||
cv_broadcast(testcv, testlock);
|
||||
random_yielder(4);
|
||||
failif((testval1 != testval2));
|
||||
|
||||
kprintf_n("Thread %lu\n", testval2);
|
||||
testval1 = (testval1 + NTHREADS - 1) % NTHREADS;
|
||||
lock_release(testlock);
|
||||
}
|
||||
V(donesem);
|
||||
@@ -269,30 +399,57 @@ cvtestthread(void *junk, unsigned long num)
|
||||
int
|
||||
cvtest(int nargs, char **args)
|
||||
{
|
||||
|
||||
int i, result;
|
||||
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
inititems();
|
||||
kprintf("Starting CV test...\n");
|
||||
kprintf("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("cvt1: 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 = TEST161_SUCCESS;
|
||||
|
||||
testval1 = NTHREADS-1;
|
||||
|
||||
for (i=0; i<NTHREADS; i++) {
|
||||
result = thread_fork("synchtest", NULL, cvtestthread, NULL, 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("CV test done\n");
|
||||
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;
|
||||
}
|
||||
@@ -318,19 +475,28 @@ 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);
|
||||
V(gatesem);
|
||||
random_yielder(4);
|
||||
spinlock_acquire(&status_lock);
|
||||
testval4++;
|
||||
spinlock_release(&status_lock);
|
||||
cv_wait(testcvs[i], testlocks[i]);
|
||||
random_yielder(4);
|
||||
lock_release(testlocks[i]);
|
||||
}
|
||||
kprintf("sleepthread: %u\n", j);
|
||||
kprintf_n("sleepthread: %u\n", j);
|
||||
}
|
||||
V(exitsem);
|
||||
}
|
||||
@@ -339,19 +505,28 @@ 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);
|
||||
testval4--;
|
||||
failif((testval4 != 0));
|
||||
cv_signal(testcvs[i], testlocks[i]);
|
||||
random_yielder(4);
|
||||
lock_release(testlocks[i]);
|
||||
}
|
||||
kprintf("wakethread: %u\n", j);
|
||||
kprintf_n("wakethread: %u\n", j);
|
||||
}
|
||||
V(exitsem);
|
||||
}
|
||||
@@ -359,30 +534,44 @@ wakethread(void *junk1, unsigned long junk2)
|
||||
int
|
||||
cvtest2(int nargs, char **args)
|
||||
{
|
||||
unsigned i;
|
||||
int result;
|
||||
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
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 = TEST161_SUCCESS;
|
||||
|
||||
kprintf("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);
|
||||
|
||||
@@ -390,12 +579,194 @@ 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("cvtest2 done\n");
|
||||
kprintf_t("\n");
|
||||
success(test_status, SECRET, "cvt2");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
cvtest3(int nargs, char **args) {
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
kprintf_n("Starting cvt3...\n");
|
||||
kprintf_n("(This test panics on success!)\n");
|
||||
|
||||
testlock = lock_create("testlock");
|
||||
if (testlock == NULL) {
|
||||
panic("cvt3: lock_create failed\n");
|
||||
}
|
||||
testcv = cv_create("testcv");
|
||||
if (testcv == NULL) {
|
||||
panic("cvt3: cv_create failed\n");
|
||||
}
|
||||
|
||||
secprintf(SECRET, "Should panic...", "cvt3");
|
||||
cv_wait(testcv, testlock);
|
||||
|
||||
/* Should not get here on success. */
|
||||
|
||||
success(TEST161_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;
|
||||
|
||||
kprintf_n("Starting cvt4...\n");
|
||||
kprintf_n("(This test panics on success!)\n");
|
||||
|
||||
testlock = lock_create("testlock");
|
||||
if (testlock == NULL) {
|
||||
panic("cvt4: lock_create failed\n");
|
||||
}
|
||||
testcv = cv_create("testcv");
|
||||
if (testcv == NULL) {
|
||||
panic("cvt4: cv_create failed\n");
|
||||
}
|
||||
|
||||
secprintf(SECRET, "Should panic...", "cvt4");
|
||||
cv_broadcast(testcv, testlock);
|
||||
|
||||
/* Should not get here on success. */
|
||||
|
||||
success(TEST161_FAIL, SECRET, "cvt4");
|
||||
|
||||
lock_destroy(testlock);
|
||||
cv_destroy(testcv);
|
||||
testcv = NULL;
|
||||
testlock = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
sleeperthread(void *junk1, unsigned long junk2) {
|
||||
(void)junk1;
|
||||
(void)junk2;
|
||||
|
||||
random_yielder(4);
|
||||
lock_acquire(testlock);
|
||||
random_yielder(4);
|
||||
failif((testval1 != 0));
|
||||
testval1 = 1;
|
||||
cv_signal(testcv, testlock);
|
||||
|
||||
random_yielder(4);
|
||||
cv_wait(testcv, testlock);
|
||||
failif((testval1 != 3));
|
||||
testval1 = 4;
|
||||
random_yielder(4);
|
||||
lock_release(testlock);
|
||||
random_yielder(4);
|
||||
|
||||
V(exitsem);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
wakerthread(void *junk1, unsigned long junk2) {
|
||||
(void)junk1;
|
||||
(void)junk2;
|
||||
|
||||
random_yielder(4);
|
||||
lock_acquire(testlock2);
|
||||
failif((testval1 != 2));
|
||||
testval1 = 3;
|
||||
|
||||
random_yielder(4);
|
||||
cv_signal(testcv, testlock2);
|
||||
random_yielder(4);
|
||||
lock_release(testlock2);
|
||||
random_yielder(4);
|
||||
|
||||
V(exitsem);
|
||||
}
|
||||
|
||||
int
|
||||
cvtest5(int nargs, char **args) {
|
||||
(void)nargs;
|
||||
(void)args;
|
||||
|
||||
int result;
|
||||
|
||||
kprintf_n("Starting cvt5...\n");
|
||||
|
||||
testlock = lock_create("testlock");
|
||||
if (testlock == NULL) {
|
||||
panic("cvt5: lock_create failed\n");
|
||||
}
|
||||
testlock2 = lock_create("testlock2");
|
||||
if (testlock == NULL) {
|
||||
panic("cvt5: lock_create failed\n");
|
||||
}
|
||||
testcv = cv_create("testcv");
|
||||
if (testcv == NULL) {
|
||||
panic("cvt5: cv_create failed\n");
|
||||
}
|
||||
exitsem = sem_create("exitsem", 0);
|
||||
if (exitsem == NULL) {
|
||||
panic("cvt5: sem_create failed\n");
|
||||
}
|
||||
spinlock_init(&status_lock);
|
||||
test_status = TEST161_SUCCESS;
|
||||
testval1 = 0;
|
||||
|
||||
lock_acquire(testlock);
|
||||
lock_acquire(testlock2);
|
||||
|
||||
result = thread_fork("cvt5", NULL, sleeperthread, NULL, 0);
|
||||
if (result) {
|
||||
panic("cvt5: thread_fork failed\n");
|
||||
}
|
||||
result = thread_fork("cvt5", NULL, wakerthread, NULL, 0);
|
||||
if (result) {
|
||||
panic("cvt5: thread_fork failed\n");
|
||||
}
|
||||
|
||||
random_yielder(4);
|
||||
cv_wait(testcv, testlock);
|
||||
failif((testval1 != 1));
|
||||
testval1 = 2;
|
||||
random_yielder(4);
|
||||
lock_release(testlock);
|
||||
random_yielder(4);
|
||||
lock_release(testlock2);
|
||||
|
||||
P(exitsem);
|
||||
P(exitsem);
|
||||
failif((testval1 != 4));
|
||||
|
||||
sem_destroy(exitsem);
|
||||
cv_destroy(testcv);
|
||||
lock_destroy(testlock2);
|
||||
lock_destroy(testlock);
|
||||
|
||||
success(test_status, SECRET, "cvt5");
|
||||
|
||||
exitsem = NULL;
|
||||
testcv = NULL;
|
||||
testlock2 = NULL;
|
||||
testlock = NULL;
|
||||
testsem2 = NULL;
|
||||
testsem = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -66,10 +66,7 @@ fakethread_create(const char *name)
|
||||
}
|
||||
/* ignore most of the fields, zero everything for tidiness */
|
||||
bzero(t, sizeof(*t));
|
||||
t->t_name = kstrdup(name);
|
||||
if (t->t_name == NULL) {
|
||||
panic("threadlisttest: Out of memory\n");
|
||||
}
|
||||
strcpy(t->t_name, name);
|
||||
t->t_stack = FAKE_MAGIC;
|
||||
threadlistnode_init(&t->t_listnode, t);
|
||||
return t;
|
||||
@@ -84,7 +81,6 @@ fakethread_destroy(struct thread *t)
|
||||
{
|
||||
KASSERT(t->t_stack == FAKE_MAGIC);
|
||||
threadlistnode_cleanup(&t->t_listnode);
|
||||
kfree(t->t_name);
|
||||
kfree(t);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user