/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version	*/
/*	3, with the exemptions that 1) the header files installed by this 	 	*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source 	*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor	*/
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss of reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such	*/
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly	*/
/*	yours.																	*/
/****************************************************************************/

#include "kernel.h"

/****************************************************************************/
/*					Public API functions									*/
/****************************************************************************/

/** @addtogroup bx_sigs */
/** @{ */

/**
*	Wait for one or more events (signals).
*
*	The function suspends the caller until at least one signal in the
*	argument signal set gets set. If the signal set can not be empty.
*	The function returns all signals that are or became set in the
*	requested set. These signals are also deleted from the pending
*	set. Signals in the pending set that are not in the waiting set
*	are not affected. If the waiting set contains the BX_SIGNAL_ALWAYS
*	signal, then the function will return without suspending the caller
*	even if no signail in the waiting set is present in the pending set.
*
*	@param	wait	The set of event to wait for. Can't be 0.
*
*	@retval	>0				All events in the wait set that were pending or
*							became active while the process was suspended.
*	@retval =0				The wait set contained the BX_EVENT_ALWAYS event
*							but no event in the waiting set was in the
*							pending set.
*	@retval BX_ERR_PARAM	Empty wait set was passed to the function.
*	@retval BX_ERR_CONTEXT	The function was called from an ISR context.
*	@retval	BX_ERR_SUSPEND	The caller should be suspended but its current
*							protection level is above BX_PROT_COOP.
*
*	@attention
*		This function should not be called from an ISR or delayed ISR.
*		This function can suspend the caller.
*/

int		BX_EventWait( int wait )
{
int		cpsr;
BX_PROC	*self;

	if ( _bx_state.exec[ BX_EXEC_MOD ] != BX_MODE_USR ) {

		// We can only be called from user land,

		return( BX_ERR_CONTEXT );
	}

	if ( ! wait ) {

		// An empty wait mask is an error, because the caller
		// would never wake up.

		return( BX_ERR_PARAM );
	}

	// Get our own process descriptor and disable the interrupts

	self = _bx_ProcSelf();
	cpsr = _bx_IrqDis();

	if ( self->sigs & wait ) {

		// We got at least one signal from the wait set pending.
		// Get all common signals and delete them from the pending set.

		wait &= self->sigs;
		self->sigs ^= wait;
	}
	else {

		// The wait set and the pending set has nothing in common

		if ( wait & BX_EVENT_ALWAYS ) {

			// The user requests for immediate return.
			// We return and report that no signals in the requested
			// set are pending at the moment.

			wait = 0;
		}
		else {

			// We must suspend

			if ( self->prot > BX_PROT_COOP ) {

				// We can't suspend the caller, so report error

				wait = BX_ERR_SUSPEND;
			}
			else {

				// Prepare for suspension. We want interrupts
				// to be disabled when we wake up.

				self->mask = wait;

				_bx_QueueEvent( cpsr | ARM_IRQDI_MASK,
							   _bx_ProcSuspend, self, /*NULL*/ (void*)1 );

				// Work out the final signals

				wait &= self->sigs;
				self->sigs ^= wait;
			}
		}
	}

	// Restore the IRQ status and return with the result

	_bx_IrqEnaUsr( cpsr );
	return( wait );
}

/** @} */

