recvmesg.c 2.34 KB
/**************************************************************************
 *									  *
 *		 Copyright (C) 1994, Silicon Graphics, Inc.		  *
 *									  *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *									  *
 **************************************************************************/

#include "osint.h"
/* #include "assert.h" */

/*
 * Name:   osRecvMesg
 *
 * Description:
 *	This routine reads a message from a given queue. Argument flags is
 *	used to let the call block (M_BLOCK) on an empty queue. If flags is
 *	set to OS_MESG_NOBLOCK, the routine returns immediately if the
 *	queue is empty.
 *
 *	Upon successful completion, a copy of a message is returned.
 *	Otherwise, value of -1 is returned.
 *
 * Globals Referenced: 
 *	None
 */
s32
osRecvMesg(OSMesgQueue *mq, OSMesg *msg, s32 flags)
{
	register u32 saveMask;

	/* Ensure that message queue is not null */
	/* assert(mq != NULL); */

#ifdef _DEBUG
	/* Ensure that flags contain valid data */
	if ((flags != OS_MESG_NOBLOCK) && (flags != OS_MESG_BLOCK)) {
		__osError(ERR_OSRECVMESG, 1, flags);
		return(-1);
	}
#endif

	/* Disable interrupts */
	saveMask = __osDisableInt();

	/* 
	 * Check for empty queue 
	 */
	while (MQ_IS_EMPTY(mq)) {
		if (flags == OS_MESG_NOBLOCK) {
			/* Restore interrupts */
			__osRestoreInt(saveMask);
			return(-1);
		} else {
			/* Yield and enqueue the running thread */
			__osRunningThread->state = OS_STATE_WAITING;
			__osEnqueueAndYield(&mq->mtqueue);
		}
	}

	/* Copy message content to given buffer (if requested) */
	if (msg != (OSMesg *)NULL)
		*msg = mq->msg[mq->first];

	/* Advance the message queue read index */
	mq->first = (mq->first + 1) % mq->msgCount;

	/* Decrement valid message counter */
	mq->validCount--;

	/* 
	 * There is now space in the message buffer. If a thread was
	 * previously blocked on full queue condition, restart it.
	 */
	if (mq->fullqueue->next != NULL) {
		osStartThread(__osPopThread(&mq->fullqueue));
	}

	/* Restore interrupts */
	__osRestoreInt(saveMask);

	return(0);

}  /* end of osRecvMesg */