/****************************************************************************/
/*	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 "coop.h"

/** @addtogroup coop_proc */
/** @{ */

/**
*	Spawn a new thread.
*
*	The function will start a new thread. The function will not suspend the
*	caller, it merely creates a new thread and sets it in a runnable state.
*	It will have the chance to run when the caller voluntarily suspends.
*	The new thread will be started with interrupts enabled.
*
*	@param	pid		The process ID of the new thread. It must be between 0
*					and the maximum number of processes specified for the
*					BZ_Init() function when the kernel was started. The
*					process ID should not be identical to the caller. It
*					also should not be the same as any already existing
*					process, but if it is, then that process will be killed
*					and substituted with the new one.
*
*	@param	stack	A pointer to the end of a memory are that will be the
*					stack for the new thread. It should be at 8-byte
*					aligned, although on the ARM7TDMI core 4-byte alignment
*					is sufficient. Note that if you create the stack by
*					declaring and integer array, the pointer you pass here
*					must be a pointer to the integer after the last element
*					of the array. That is, if you define
*					@code static int stack[ SIZE ]; @endcode
*					then you must pass <tt><i>stack + SIZE</i></tt> here.
*
*	@param	func	A pointer to a void function taking a void pointer
*					argument. That will be the entry point of your new thread.
*					That function must never return; if it does, the system
*					will crash.
*
*	@param	parm	The argument to pass to the new thread when it starts.
*
*	@retval	BZ_ILLEGAL_PID	The <tt>pid</tt> argument was out of bounds or
*							was the same as that of the caller.
*
*	@retval	0				Success.
*/

int		BZ_ProcSpawn( int pid, int *stack, void (*func)( void *), void *parm )
{
BZ_STAT		*base;
BZ_PROC		*proc;
unsigned	stat;

	base = &_bz_stat;

	if ( (unsigned) pid >= base->maxp || (unsigned) pid == base->self )

		return( BZ_ILLEGAL_PID );

	stat = BZ_IrqDisable( 1 );
	proc = base->proc + pid;
	stack -= 9;

	stack[ 0 ] = (int) parm;			// R4
	stack[ 1 ] = (int) func;			// R5
	stack[ 8 ] = (int) _bz_start;		// R14

	proc->sigs = BZ_EVENT_ALWAYS;
	proc->mask = BZ_EVENT_ALWAYS;
	proc->cntx = stack;

	BZ_IrqDisable( stat );
	return( 0 );
}

/** @} */

