os161/kern/test/synchtest.c
2015-12-23 00:50:04 +00:00

402 lines
8.0 KiB
C

/*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
* The President and Fellows of Harvard College.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Synchronization test code.
*/
#include <types.h>
#include <lib.h>
#include <clock.h>
#include <thread.h>
#include <synch.h>
#include <test.h>
#define NSEMLOOPS 63
#define NLOCKLOOPS 120
#define NCVLOOPS 5
#define NTHREADS 32
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
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");
}
}
}
static
void
semtestthread(void *junk, unsigned long num)
{
int i;
(void)junk;
/*
* Only one of these should print at a time.
*/
P(testsem);
kprintf("Thread %2lu: ", num);
for (i=0; i<NSEMLOOPS; i++) {
kprintf("%c", (int)num+64);
}
kprintf("\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: ");
P(testsem);
P(testsem);
kprintf("ok\n");
for (i=0; i<NTHREADS; i++) {
result = thread_fork("semtest", NULL, semtestthread, NULL, i);
if (result) {
panic("semtest: thread_fork failed: %s\n",
strerror(result));
}
}
for (i=0; i<NTHREADS; i++) {
V(testsem);
P(donesem);
}
/* so we can run it again */
V(testsem);
V(testsem);
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;
for (i=0; i<NLOCKLOOPS; i++) {
lock_acquire(testlock);
testval1 = num;
testval2 = num*num;
testval3 = num%3;
if (testval2 != testval1*testval1) {
fail(num, "testval2/testval1");
}
if (testval2%3 != (testval3*testval3)%3) {
fail(num, "testval2/testval3");
}
if (testval3 != testval1%3) {
fail(num, "testval3/testval1");
}
if (testval1 != num) {
fail(num, "testval1/num");
}
if (testval2 != num*num) {
fail(num, "testval2/num");
}
if (testval3 != num%3) {
fail(num, "testval3/num");
}
lock_release(testlock);
}
V(donesem);
}
int
locktest(int nargs, char **args)
{
int i, result;
(void)nargs;
(void)args;
inititems();
kprintf("Starting lock test...\n");
for (i=0; i<NTHREADS; i++) {
result = thread_fork("synchtest", NULL, locktestthread,
NULL, i);
if (result) {
panic("locktest: thread_fork failed: %s\n",
strerror(result));
}
}
for (i=0; i<NTHREADS; i++) {
P(donesem);
}
kprintf("Lock test done.\n");
return 0;
}
static
void
cvtestthread(void *junk, unsigned long num)
{
int i;
volatile int j;
struct timespec ts1, ts2;
(void)junk;
for (i=0; i<NCVLOOPS; i++) {
lock_acquire(testlock);
while (testval1 != num) {
gettime(&ts1);
cv_wait(testcv, testlock);
gettime(&ts2);
/* 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");
V(donesem);
thread_exit();
}
}
kprintf("Thread %lu\n", num);
testval1 = (testval1 + NTHREADS - 1)%NTHREADS;
/*
* loop a little while to make sure we can measure the
* time waiting on the cv.
*/
for (j=0; j<3000; j++);
cv_broadcast(testcv, testlock);
lock_release(testlock);
}
V(donesem);
}
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");
testval1 = NTHREADS-1;
for (i=0; i<NTHREADS; i++) {
result = thread_fork("synchtest", NULL, cvtestthread, NULL, i);
if (result) {
panic("cvtest: thread_fork failed: %s\n",
strerror(result));
}
}
for (i=0; i<NTHREADS; i++) {
P(donesem);
}
kprintf("CV test done\n");
return 0;
}
////////////////////////////////////////////////////////////
/*
* Try to find out if going to sleep is really atomic.
*
* What we'll do is rotate through NCVS lock/CV pairs, with one thread
* sleeping and the other waking it up. If we miss a wakeup, the sleep
* thread won't go around enough times.
*/
#define NCVS 250
#define NLOOPS 40
static struct cv *testcvs[NCVS];
static struct lock *testlocks[NCVS];
static struct semaphore *gatesem;
static struct semaphore *exitsem;
static
void
sleepthread(void *junk1, unsigned long junk2)
{
unsigned i, j;
(void)junk1;
(void)junk2;
for (j=0; j<NLOOPS; j++) {
for (i=0; i<NCVS; i++) {
lock_acquire(testlocks[i]);
V(gatesem);
cv_wait(testcvs[i], testlocks[i]);
lock_release(testlocks[i]);
}
kprintf("sleepthread: %u\n", j);
}
V(exitsem);
}
static
void
wakethread(void *junk1, unsigned long junk2)
{
unsigned i, j;
(void)junk1;
(void)junk2;
for (j=0; j<NLOOPS; j++) {
for (i=0; i<NCVS; i++) {
P(gatesem);
lock_acquire(testlocks[i]);
cv_signal(testcvs[i], testlocks[i]);
lock_release(testlocks[i]);
}
kprintf("wakethread: %u\n", j);
}
V(exitsem);
}
int
cvtest2(int nargs, char **args)
{
unsigned i;
int result;
(void)nargs;
(void)args;
for (i=0; i<NCVS; i++) {
testlocks[i] = lock_create("cvtest2 lock");
testcvs[i] = cv_create("cvtest2 cv");
}
gatesem = sem_create("gatesem", 0);
exitsem = sem_create("exitsem", 0);
kprintf("cvtest2...\n");
result = thread_fork("cvtest2", NULL, sleepthread, NULL, 0);
if (result) {
panic("cvtest2: thread_fork failed\n");
}
result = thread_fork("cvtest2", NULL, wakethread, NULL, 0);
if (result) {
panic("cvtest2: thread_fork failed\n");
}
P(exitsem);
P(exitsem);
sem_destroy(exitsem);
sem_destroy(gatesem);
exitsem = gatesem = NULL;
for (i=0; i<NCVS; i++) {
lock_destroy(testlocks[i]);
cv_destroy(testcvs[i]);
testlocks[i] = NULL;
testcvs[i] = NULL;
}
kprintf("cvtest2 done\n");
return 0;
}