thread6.c 9.34 KB
#include <os.h>
#include <rmon.h>
#include "corefunc.h"

/*
 * thread6
 *
 * Tests for:
 *	osDestroyThread (on blocked threads)
 *
 * Assumed working:
 *	osCreateThread
 *	osStartThread
 *	osSetThreadPri
 *	osYieldThread
 *	osCreateMesgQueue
 *	osJamMesg
 *	osSendMesg
 *	osRecvMesg
 *	osGetIntMask
 *	osSetIntMask
 *
 * Description:
 *	Check that osDestroyThread applied on thread blocked on message
 *		receive does not corrupt queue.
 *	Check that osDestroyThread applied on thread blocked on message
 *		send does not corrupt queue.
 *	Check that osDestroyThread does not affect interrupt mask.
 */

#define	NUM_LOG		42
#define	NUM_SLAVES	2
#define	MAX_MESSAGES	2

static void		slave1(void *);
static void		slave2(void *);
static void		slave3(void *);
static void		slave4(void *);

static int		logExecution(int);

static OSMesgQueue	mesgQueue;
static OSMesg		mesgBuf[MAX_MESSAGES];

static OSMesgQueue	slaveMesgQueue;
static OSMesg		slaveMesgBuf[NUM_SLAVES];

static OSThread		slave1Thread, slave2Thread, slave3Thread, slave4Thread;
static char		slave1Stack[STACKSIZE];
static char		slave2Stack[STACKSIZE];
static char		slave3Stack[STACKSIZE];
static char		slave4Stack[STACKSIZE];

static int		logTab[NUM_LOG];
static int		*logPtr = logTab;
static int		expLogTab[NUM_LOG] = {
	0, 1, 2, 0, 0, 0, 2,
	0, 1, 2, 0, 0, 0, 2,
	0, 1, 2, 0, 0, 0, 2,
	0, 3, 4, 0, 0, 4, 0,
	0, 3, 4, 0, 0, 4, 0,
	0, 3, 4, 0, 0, 4, 0 };

int
thread6(void)
{
    OSIntMask savedMask, currentMask;
    OSMesg actualMesg, expectedMesg;
    int i, j, k;
    int addFailures, numFailures = 0;

    savedMask = osSetIntMask(OS_IM_ALL);

    /*
     * Set thread priority to the same as slaves.
     */
    osSetThreadPri(NULL, 10);

    /*
     * Create a message queue of fixed size, and push the read/write
     * pointers to various locations in the circular buffer, but
     * leave the message queue empty.
     */
    for (i = 0; i < MAX_MESSAGES+1; i++) {
	osCreateMesgQueue(&mesgQueue, mesgBuf, MAX_MESSAGES);

        for (j = 0; j < i; j++) {
	    (void)osSendMesg(&mesgQueue, (OSMesg)NULL, OS_MESG_BLOCK);
	    (void)osRecvMesg(&mesgQueue, (OSMesg *)NULL, OS_MESG_BLOCK);
	}

	osCreateMesgQueue(&slaveMesgQueue, slaveMesgBuf, NUM_SLAVES);

	/*
	 * Create and start up a thread that will block on a message receive.
	 */
	osCreateThread(&slave1Thread, 101, slave1, (void *)0,
			slave1Stack+STACKSIZE, 10);
	osStartThread(&slave1Thread);

	/*
	 * Create and start up a thread that will also do a blocking
	 * receive (later).
	 */
	osCreateThread(&slave2Thread, 102, slave2, (void *)i,
			slave2Stack+STACKSIZE, 10);

	osStartThread(&slave2Thread);

	if (logExecution(0))	/* 0, 7, 14 */
		numFailures++;

	osYieldThread();	/* allow slaves to run */

	if (logExecution(0))	/* 3, 10, 17 */
		numFailures++;

	/*
	 * Destroy the first thread that is blocked.
	 */
	osDestroyThread(&slave1Thread);

	if (logExecution(0))	/* 4, 11, 18 */
		numFailures++;

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

	/*
	 * Send a message that will unblock the second thread.
	 */
	expectedMesg = (OSMesg)((i<<24)|(i<<16)|(i<<8)|i);
	(void)osSendMesg(&mesgQueue, expectedMesg, OS_MESG_BLOCK);

	if (logExecution(0))	/* 5, 12, 19 */
		numFailures++;

	/*
	 * Reap results.
	 */
	for (k = 0; k < NUM_SLAVES; k++) {
	    (void)osRecvMesg(&slaveMesgQueue, (OSMesg *)&addFailures,
		OS_MESG_BLOCK);
	    numFailures += addFailures;
	}
    }

     /*
      * Create a message queue of fixed size, and push the read/write
      * pointers to various locations in the circular buffer, but
      * leave the message queue full.
      */
    for (i = 0; i < MAX_MESSAGES+1; i++) {
	osCreateMesgQueue(&mesgQueue, mesgBuf, MAX_MESSAGES);

        for (j = 0; j < i; j++) {
	    (void)osSendMesg(&mesgQueue, (OSMesg)NULL, OS_MESG_BLOCK);
	    (void)osRecvMesg(&mesgQueue, (OSMesg *)NULL, OS_MESG_BLOCK);
	}
	for (j = 0; j < MAX_MESSAGES; j++) {
	    expectedMesg = (OSMesg)((j<<24)|(j<<16)|(j<<8)|j);
	    (void)osSendMesg(&mesgQueue, expectedMesg, OS_MESG_BLOCK);
	}
	osCreateMesgQueue(&slaveMesgQueue, slaveMesgBuf, NUM_SLAVES);

	/*
	 * Create and start up a thread that will block on a message send.
	 */
	osCreateThread(&slave3Thread, 103, slave3, (void *)0,
			slave3Stack+STACKSIZE, 10);
	osStartThread(&slave3Thread);

	osCreateThread(&slave4Thread, 104, slave4, (void *)MAX_MESSAGES,
		       slave4Stack+STACKSIZE, 10);

	/*
	 * Create and start up a thread that will also do a blocking
	 * send (later).
	 */
	osStartThread(&slave4Thread);

	if (logExecution(0))	/* 21, 28, 35 */
		numFailures++;

	osYieldThread();		/* allow slaves to run */

	if (logExecution(0))	/* 24, 31, 38 */
		numFailures++;

	/*
	 * Destroy the first thread that is blocked.
	 */
	osDestroyThread(&slave3Thread);

	if (logExecution(0))	/* 25, 32, 39 */
		numFailures++;

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

	/*
	 * Receive and check all messages, which should unblock the second
	 * thread.
	 */
	for (j = 0; j < MAX_MESSAGES; j++) {
	    expectedMesg = (OSMesg)((j<<24)|(j<<16)|(j<<8)|j);
	    (void)osRecvMesg(&mesgQueue, &actualMesg,OS_MESG_NOBLOCK);
	    if (expectedMesg != actualMesg) {
		osSyncPrintf("thread6: expected message 0x%x, actual 0x%x\n",
			expectedMesg, actualMesg);
		numFailures++;
	    }
	}

	expectedMesg = (OSMesg)((MAX_MESSAGES<<24)|(MAX_MESSAGES<<16)|
				(MAX_MESSAGES<<8)|MAX_MESSAGES);
	(void)osRecvMesg(&mesgQueue, &actualMesg, OS_MESG_BLOCK);

	if (logExecution(0))	/* 27, 34, 41 */
		numFailures++;

	if (expectedMesg != actualMesg) {
	    osSyncPrintf("thread6: expected message 0x%x, actual 0x%x\n",
		expectedMesg, actualMesg);
	    numFailures++;
	}

	for (k = 0; k < NUM_SLAVES; k++) {
	    (void)osRecvMesg(&slaveMesgQueue, (OSMesg *)&addFailures,
			OS_MESG_BLOCK);
	    numFailures += addFailures;
	}
    }

    /*
     * Verify everybody ran when they were supposed to.
     */
    if (logPtr != &logTab[NUM_LOG]) {
	osSyncPrintf("thread6: log table underflow\n");
	numFailures++;
    }
    for (i = 0; i < logPtr - logTab; i++) {
	if (expLogTab[i] != logTab[i]) {
	    osSyncPrintf("thread6: 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("thread6: expected interrupt mask 0x%x, actual 0x%x\n",
		OS_IM_ALL, currentMask);
	numFailures++;
    }
    return(numFailures);
}

static void
slave1(void *arg)
{
    int numFailures = 0;
    OSMesg dummyMesg;

    if (logExecution(1))	/* 1, 8, 15 */
	numFailures++;

    /*
     * Have to send this now, since we shouldn't live beyond this.
     */
    osSendMesg(&slaveMesgQueue, (OSMesg)numFailures, OS_MESG_BLOCK);

    /*
     * Receive a message, which will block.
     */
    (void)osRecvMesg(&mesgQueue, &dummyMesg, OS_MESG_BLOCK);

    (void)logExecution(1);	/* should not get here */
}

static void
slave2(void *arg)
{
    OSIntMask currentMask;
    OSMesg expectedMesg, actualMesg;
    int i;
    int numFailures = 0;

    if (logExecution(2));	/* 2, 9, 16 */
	numFailures;

    /*
     * Receive a message, which will block.  This will eventually complete.
     */
    i = (int)arg;
    expectedMesg = (OSMesg)((i<<24)|(i<<16)|(i<<8)|i);
    (void)osRecvMesg(&mesgQueue, &actualMesg, OS_MESG_BLOCK);

    if (logExecution(2))	/* 6, 13, 20 */
	numFailures;

    if (expectedMesg != actualMesg) {
	osSyncPrintf("thread6: expected message 0x%x, actual 0x%x\n",
    		expectedMesg, actualMesg);
	numFailures++;
    }

    currentMask = osGetIntMask();
    if (currentMask != OS_IM_ALL) {
	osSyncPrintf("thread6: expected interrupt mask 0x%x, actual 0x%x\n",
	       OS_IM_ALL, currentMask);
	numFailures++;
    }
    osSendMesg(&slaveMesgQueue, (OSMesg)numFailures, OS_MESG_BLOCK);
}

static void
slave3(void *arg)
{
    int numFailures = 0;

    if (logExecution(3))	/* 22, 29, 36 */
	numFailures;

    /*
     * Have to send this now, since we shouldn't live beyond this.
     */
    (void)osSendMesg(&slaveMesgQueue, (OSMesg)numFailures, OS_MESG_BLOCK);

    /*
     * Send a message, which will block.
     */
    (void)osJamMesg(&mesgQueue, (OSMesg)0xaaaaaaaa, OS_MESG_BLOCK);

    (void)logExecution(3);	/* should not get here */
}

static void
slave4(void *arg)
{
    OSIntMask currentMask;
    OSMesg expectedMesg;
    int i;
    int numFailures = 0;

    if (logExecution(4))	/* 23, 30, 37 */
	numFailures;

    i = (int)arg;
    expectedMesg = (OSMesg)((i<<24)|(i<<16)|(i<<8)|i);
    (void)osSendMesg(&mesgQueue, expectedMesg, OS_MESG_BLOCK);

    if (logExecution(4))	/* 26, 33, 40 */
	numFailures++;

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

    /*
     * Send a message, which will block.  This will eventually complete.
     */
    osSendMesg(&slaveMesgQueue, (OSMesg)numFailures, OS_MESG_BLOCK);
}

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