thread0.c 6.24 KB
#include <os.h>
#include <rmon.h>
#include "corefunc.h"

/*
 * thread0
 *
 * Tests for:
 *	osCreateThread
 *	osStartThread
 *	osYieldThread
 *
 * Assumed working:
 *	osGetIntMask
 *	osSetIntMask
 *
 * Description:
 *	Check that osCreateThread does not affect interrupt mask
 *	Check that osStartThread does not affect interrupt mask
 *	Check that created threads start with the correct argument
 *	Check that created threads start with the correct interrupt mask
 *	Check that created threads start with a stack pointer within
 *		the specified range
 *	Check that osYieldThread yields the processor
 *	Check that osYieldThread correctly saves all callee saved registers
 *	Check that osYieldThread does not affect interrupt mask
 */

#define NUM_THREAD	9
#define	NUM_LOG 	18

typedef struct {
    int			id;
    void		(*entry)(void *);
    OSPri		pri;
    u64			stack[STACKSIZE/sizeof(u64)];
    OSThread		thread;
    int			numFailures;
} ThreadTabEntry;

static void slave0(void *);
static void slave1(void *);
static void slave2(void *);
static void slave3(void *);
static void slave4(void *);
static void slave5(void *);
static void slave6(void *);
static void slave7(void *);
static void slave8(void *);

static void slave(ThreadTabEntry *, ThreadTabEntry *);

static int logExecution(int);

static ThreadTabEntry threadTab[NUM_THREAD] = {
    { 100, slave0, 10 }, 
    { 101, slave1, 10 }, 
    { 102, slave2, 10 }, 
    { 103, slave3, 10 }, 
    { 104, slave4, 10 }, 
    { 105, slave5, 10 }, 
    { 106, slave6, 10 }, 
    { 107, slave7, 10 }, 
    { 108, slave8, 10 }, 
};

static int		doneCount = 0;

static int		logTab[NUM_LOG];
static int		*logPtr = logTab;
static int		expLogTab[NUM_LOG] = {
    100, 101, 102, 103, 104, 105, 106, 107, 108,
    100, 101, 102, 103, 104, 105, 106, 107, 108
};

int
thread0(void)
{
    OSIntMask savedMask, currentMask;
    ThreadTabEntry *t;
    int i;
    int numFailures = 0;
    
    savedMask = osSetIntMask(OS_IM_ALL);

    /*
     * Create and start a number of threads with given parameters.
     */
    for (t = threadTab; t < &threadTab[NUM_THREAD]; t++) {
    	osCreateThread(&t->thread, t->id, t->entry, t,
			t->stack+STACKSIZE/sizeof(u64), t->pri);

    	currentMask = osGetIntMask();
    	if (currentMask != OS_IM_ALL) {
    	    osSyncPrintf("thread0: expected interrupt mask 0x%x, actual 0x%x\n",
    			OS_IM_ALL, currentMask);
    	    numFailures++;
    	}

    	osStartThread(&t->thread);

    	currentMask = osGetIntMask();
    	if (currentMask != OS_IM_ALL) {
    	    osSyncPrintf("thread0: expected interrupt mask 0x%x, actual 0x%x\n",
    			OS_IM_ALL, currentMask);
    	    numFailures++;
    	}
    }

    /*
     * Wait for them to complete and return results.
     */
    while (doneCount < NUM_THREAD)
	osYieldThread();

    for (t = threadTab; t < &threadTab[NUM_THREAD]; t++)
	numFailures += t->numFailures;

    /*
     * Verify everybody ran when they were supposed to.
     */
    if (logPtr != &logTab[NUM_LOG]) {
	osSyncPrintf("thread0: log table underflow\n");
	numFailures++;
    }
    for (i = 0; i < logPtr - logTab; i++) {
	if (expLogTab[i] != logTab[i]) {
	    osSyncPrintf("thread0: expected log id %d, actual %d at entry %d\n",
		expLogTab[i], logTab[i], i);
	    numFailures++;
	}
    }

    /*
     * Restore original interrupt mask and check it once more.
     */
    currentMask = osSetIntMask(savedMask);
    if (currentMask != OS_IM_ALL) {
	osSyncPrintf("thread0: expected interrupt mask 0x%x, actual 0x%x\n",
		OS_IM_ALL, currentMask);
	numFailures++;
    }
    return(numFailures);
}

static void
slave0(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[0]);
}

static void
slave1(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[1]);
}

static void
slave2(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[2]);
}

static void
slave3(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[3]);
}

static void
slave4(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[4]);
}

static void
slave5(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[5]);
}

static void
slave6(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[6]);
}

static void
slave7(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[7]);
}

static void
slave8(void *arg)
{
    slave((ThreadTabEntry *)arg, &threadTab[8]);
}

static void slave(ThreadTabEntry *expected, ThreadTabEntry *actual)
{
    int numFailures = 0;
    OSIntMask currentMask;
    auto char stackMark;

    /*
     * Check thread argument.
     */
    if (expected != actual) {
    	osSyncPrintf("thread0: expected thread argument 0x%x, actual 0x%x\n",
    		expected, actual);
    	numFailures++;
    }

    /*
     * Check interrupt mask.
     */
    currentMask = osGetIntMask();
    if (OS_IM_ALL != currentMask) {
    	osSyncPrintf("thread0: expected interrupt mask 0x%x, actual 0x%x\n",
    		OS_IM_ALL, currentMask);
    	numFailures++;
    }

    /*
     * Check that stack is within given range.
     */
    if ((&stackMark < (char *)expected->stack) ||
        (&stackMark >= (char *)(expected->stack+STACKSIZE/sizeof(u64)))) {
          osSyncPrintf("thread0: expected stack range [0x%x, 0x%x), actual 0x%x\n",
    	     expected->stack, expected->stack+STACKSIZE/sizeof(u64),
	     &stackMark);
    	numFailures++;
    }

    /*
     * Change to a new interrupt mask.
     */
    osSetIntMask(OS_IM_NONE);

    if (logExecution(expected->id))
	numFailures++;

    /*
     * Dirty callee saved registers, yield the processor,
     * and then make sure they are restored correctly.
     */
    
    if (yieldAndCheck((expected-threadTab) << 16)) {
    	osSyncPrintf("thread0: callee saved registers corrupted\n");
    	numFailures++;
    }

    if (logExecution(expected->id))
	numFailures++;

    /*
     * Check that the restored interrupt mask is the new one,
     * not the original one.
     */
    currentMask = osGetIntMask();
    if (OS_IM_NONE != currentMask) {
    	osSyncPrintf("thread0: expected interrupt mask 0x%x, actual 0x%x\n",
    		OS_IM_NONE, currentMask);
    	numFailures++;
    }

    expected->numFailures = numFailures;
    doneCount++;
}

static int
logExecution(int id)
{
    if (logPtr >= &logTab[NUM_LOG]) {
	osSyncPrintf("thread0: log table overflow\n");
	return(1);
    }
/*
    osSyncPrintf("%d. log %d\n", logPtr-logTab, id);
*/
    *logPtr++ = id;
    return(0);
}