/****************************************************************************/
/*	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 or 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.																	*/
/****************************************************************************/

/**	@addtogroup coop */
/**	@{ */
/**		@defgroup coop_init		Initialisation functions */
/**		@defgroup coop_proc		Process management functions */
/**		@defgroup coop_event	Event (signal) functions */
/**		@defgroup coop_lock		Mutual exclusivity lock functions */
/**		@defgroup coop_sema		Counting semaphore */
/**		@defgroup coop_port		Message port functions */
/**		@defgroup coop_time		Timer functions */
/**		@defgroup coop_irq		Interrupt control */
/**	@} */

/** @addtogroup coop

A simple co-operative mutithreading kernel.

The library package contains a pre-emptive kernel, see @ref kernel. However,
that kernel is fairly large. In addition, in pre-emptive systems a lot of
attention as well as code should be spent in guaranteeing resource integrity
and coherence. When building simpler systems it would often be good to have
most of the advantages of a multi-threading kernel available, but in a small
footprint and preferably without the hassle associated with pre-emption.

The co-operative kernel is a possible solution. Cooperative mutitasking means
that once a process (or thread, in our case it's the same) gets the processor,
no other process will run until the current thread voluntarily gives up
control. It means that once you started working on a shared object, you can
finish working on it as long as you do not call a kernel function that would
cause a scheduler run. That eliminates a significant amount of resource locking.
Furthermore, the kernel's scheduler is much simpler since context switches can
not occur at any time; only when the running process calls specific kernel
functions. Of course, it comes at a price. When an external event happens, the
process responsible to react to it will not be woken up until the current
thread gives up the processor. If a thread never calls a function that would
suspend it, then it can hog the processor indefinitely, even if more important
processes are waiting for the CPU.

Since this library is intended to be used in embedded systems where you write
every thread running on the processor, one can assume that you know what you
are doing and you will not create rogue threads to kill the system. If you
can live with the lack of pre-emption and all the associated process latency
issues, then you can use the co-operative kernel. It is fairly small
(it is suitable even for systems with only 16K of FLASH or even less),
has little overhead and low interrupt latency.

Each thread has its own stack that you have to provide. Threads are identified
by small integers. In fact, these numbers are just indices into the process
table, for which you must also provide the RAM but must not touch otherwise.
You can choose between round-robin or priority based scheduling. Whenever
the current thread relinguishes the processor, the kernel needs to select
the next thread to run. It is done by going through the process table and
start the first thread that is ready to run. If you choose round-robin
scheduling policy, then the kernel will scan the process table starting
at the process with the process identifier (PID, i.e. the index to the
process table) one less than the process that gave up the processor. It will
then continue to go down to 0, wrapping around to the highest PID and counting
down again. If you selected priority scheduling, then the scan will always
start at the highest PID, thus the kernel will find the highest runnable PID.
If the kernel finds no runnable process at all, that is, the system is idle,
then it will call a function that you have to provide. In that function you
can stop the processor to conserve power, assuming that you have hardware
support to wake up when an external event (i.e. an interrupt) needs servicing.

In order to keep the code small, the kernel does very little error checking.
It assumes that you know what you're doing. Please read the warnings in the
documentation in particular about calling kernel functions from interrupt
routines.

*/

/** @addtogroup coop_init

Before using, you must initialise the kernel. The BZ_Init() function does that.
It must be called from an interrupt context and a configuration structure is
passed to the function. Based on the structure the function initialises the
kernel and then switches from interrupt state to system state and starts the
first thread. From that thread you can start all the other threads.

The initialisation structure contains all the parameters and pointers to the
verious memory resurces that the kernel uses. The following structure fields
are defined:

- <b>idle</b><br>
	This is a pointer to a function that takes no parameter and returns
	nothing. The kernel will call this function whenever there are no
	threads to run. This function should suspend the processor until
	an external event happens (that is, interrupt request). This
	function is called with interrupts disabled. It can enable the
	interrupts if it wants. The function executes in the context of
	a user thread, therefore it must limit its stack usage to the minimum.
	This function must <b>not</b> call any kernel functions; if it does,
	then the system will crash. If you have no means to stop the CPU
	until an interrupt happens, it is safe to return immediately without
	doing anything; the system will work fine but it will burn CPU cycles
	and thus power while idling.

- <b>irqs</b><br>
	This is a pointer to a void function taking no parameter. This
	function will be called by the kernel's interrupt entry routine.
	It can be either an ARM or THUMB function. The function will
	execute in interrupt context (i.e. it uses the interrupt satck)
	and is entered with interrupts disabled. It must <b>not</b>
	enable interrupts or call kernel functions for which it is
	stated that they should not be called from interrupst; if it
	does, the system will crash. Note that you must <b>not</b>
	use the interrupt attribute on this function, it is a normal
	C function. The interrupt prologue/epilogue will be taken care
	of by the kernel.

- <b>proc_tab</b> and <b>proc_num</b><br>
	A pointer to the process table, an array of BZ_PROC structures and
	the number of array elements. The process table belongs to the
	kernel and you should never touch it. A process table entry is
	12 bytes long. The table must be as large as many processes you
	intend to start. The process table must reside in RAM, of course.
	The max number of processes is 255.

- <b>port_tab</b> and <b>port_num</b><br>
	A pointer to the message port table, an array of BZ_PORT structures
	the number of array elements. The message port table holds the
	message ports used by the messaging subsystem. They must reside in
	RAM and belong to the kernel, you must never touch them. The table
	must be as large as many message ports you intend to use. If you
	do not use messaging, then set <tt>port_tab</tt> to NULL and
	<tt>port_num</tt> to 0. A message port is 4 bytes long.
	The max number of ports is 255.

- <b>mesg_tab</b> and <b>mesg_num</b><br>
	A pointer to an array of BZ_MESG structures and the number of array
	elements. This will be the message pool for the message subsystem.
	Thenumber of messages in the pool is the limit of messages waiting
	on message ports, not delivered yet. The number is limited 255.
	A message is 8 bytes. If you do not want to use the message subsystem
	then specify NULL for <tt>mesg_tab</tt> and 0 for <tt>mesg_num</tt>.

- <b>init</b>
	A pointer to a function taking no arguments and returning nothing.
	This will be the first user process to start. In fact, BZ_Init()
	does not return, rather, it switches the processor into system
	state and jumps to the function specified by <tt>init</tt>. The
	function will be started with interrupts disabled, you have to
	explicitely enable them later. It can be either an ARM or a THUMB
	function.

- <b>init_stk</b><br>
	A pointer to the stack for the <tt>init</tt> process. As with the
	BZ_ProcSpawn() function, this is the actual stackpointer value.
	Since the ARM uses decrement before push, if you declare the
	stack as an array of 32-bit integers, then it should point to
	the element just beyond the array. That is, if you declare your
	stack as <tt>int stack[ STACKSIZE ];</tt> then you should set
	<tt>init_stk</tt> to <tt>stack + STACKSIZE</tt>.
	In theory, this pointer should be 8-byte aligned but in reality
	it is sufficient if it is 4-byte aligned.

- <b>init_pid</b><br>
	The process ID of the <tt>init</tt> process. Every thread in the
	system has an ID between 0 and <tt>proc_num-1</tt>, which is basically
	the index into the process table. If you choose priority scheduling,
	then the higher the process ID, the more important the process. If
	you use round-robin scheduling, then the actual value of the PID
	does not matter. This parameter is the PID for the first process
	to be started, that is, the slot in the process table that this
	process will use.

- <b>schedule</b><br>
	If this parameter is 0, then the kernel will use round-robin
	scheduling. If it is non-zero, then priority scheduling will
	be used. The kernel will still be co-operative, so a process
	is only suspended if it explicitely asks for it. If round-robin
	scheduling is used, then if you have N processes (PIDs going from
	0 to N-1) and process k is suspended, then the kernel will check
	if k-1, k-2 .. 1, 0, N-1, N-2 ... is runnable and start the first one
	it finds. If priority scheduling is selected, then the testing
	order is always N-1, N-2, .. 0 regardless of the PID of the
	process giving up the CPU.

The following example illustrates the initialisation of the kernel, both
the assembly that gets from reset to the C code and the C code until the
first user thread is started:

@include coop-init.S
@include coop-init.c

*/

/** @addtogroup coop_event

Event (signal) handling.
Events or signals are just fancy names for bits which can be set by a
thread or interrupt routine. In addition, a thread can wait for a bit to
become set. Each thread has 31 such bits (32, but one bit is always set).
A few of these bits are used by the kernel, the rest is available for the
user code. A thread or an interrupt routine can set one or more bits in the
set of any thread (that is, it can <i>post</i> events to the thread) and a
thread can wait for any bit of a sepcified subset of its event bits to become
set. When a thread waiting for events wakes up, it gets a bitmap that indicates
which events that it was waiting for became active and those bits in its set
will also be cleared.

While it is a very simple mechanism, it is also pretty efficient. The event
posting overhead is very small and waiting for multiple events simultaneously
is also very simple, since the thread's 32 event bits are in fact a single
integer word and bitwise operations can work on the bits in parallel.

For that reason the kernel uses the event mechanism as a basis for every other
interprocess communication and synchronisation mechanism. The two basic
operations, posting and waiting, can be described by these pseudo procedures,
assuming atomic operations:
@code
post( thread, event_bits )
	thread.events |= event_bits

wait( event_mask )
	while ( self.events & event_mask == 0 ) sleep()
	self.events &= ~event_mask
@endcode

Naturally, signals can get lost. If a bit is already set and you set it again,
there's no indication that you acted on it twice. So these bits indicate that
an event occured <i>at least once</i> since you checked them last time. You
have to keep that in mind when you design your system.
*/

/** @addtogroup coop_port

The kernel provides a mechanism for sending messages from a thread or interrupt
routine to some other thread. The messages themselves are of a fixed structure,
containing an 8-bit, a 16-bit and a 32-bit field, intended to be used as
message type byte and two parameters that can either deliver a short and an
int or, casting a pointer to int, a pointer to the actual message and the
length of the message. However, you can use the three fields any way you
seem fit, the message subsystem simply delivers them and does not try to
interpret their content in any way.

The message delivery is through message ports. These are small objects that
are created when you call BZ_Init(). Before using it, a port must be opened
by calling BZ_PortOpen(). The calling process will then own that port and
whenever a message is available on the port, the process will get an event
(see @ref coop_event). The process then can call BZ_PortRead() which will
deliver the next available message from the port. Only one process can own
a port at any given time. Like threads, ports are identified by small integers
instead of pointers.

The message system is asynchronous, that is, when you send a message you are
not suspended until the message is actually read. That of course requires that
the kernel buffers the messages, which it does, in the buffer area you provided
when you called BZ_Init(). The finite amount of buffer space also means that
you can run out of buffers and messages can get lost. You have to make sure
that your message consumers do actually consume the messages. Sending a message
is fairly fast, it is feasible to use BZ_PortSend() from interrupt routines.
*/

/** @addtogroup coop_lock

Locks are objects that can be used to guarantee exclusive access to some
resource. A lock is either free or it has an <i>owner</i>. When you want
to use a the shared resource, you obtain the lock. If the lock is owned
by an other thread, you will be suspended until that thread finishes with
the resource and releases the lock. At that moment you became the owner of
the lock and you are free to use the resource, all other threads will be
suspended on the lock. When you finished with the resource, you have to
release a lock, thus granting access to the resource to other threads.

When multiple threads are waiting for a lock, then the order of them getting
the lock when it becomes available depends on the scheduling policy of the
kernel. In priority scheduling mode the highest priority waiting process
will get the lock, in round-robin mode any one of the waiting threads can
get it. In effect when the lock is released they all become runable and the
first one scheduled by the kernel gets the lock, all the others go back to
wait.

The locking code is very short but rather unsophisticated. If you use a
lot of locks and many threads suspended on locks, then you will burn
CPU cycles unnecessarily. Do not use locks as general purpose
synchronisation mechanism. Use then only as intended, providin a mutually
exclusive access to a shared resource.

*/

/** @addtogroup coop_sema

Semaphores are objects that can be used to manage a finite pool os resources.
They hold a count of resources that are available in the pool. Threads can
ask for a given number of resources and get suspended if the request can not
be satisfied. Threads holding resources can return them to the pool when they
are not used any more; the returned resources can be then given out to threads
waiting for them.

The semaphore code is very short but rather unsophisticated. If you use a
lot of semaphores and many threads suspended on them, then you will use
a lot of CPU rather unnecessarily. Do not use semaphores as general purpose
synchronisation mechanism; try to use the event system, which is much more
efficient.

*/

/** @addtogroup coop_time

The kernel contains a simple timer subsystem.

You do not have to use the subsystem. It is possible to set up an interrupt
routine on a hardware timer and send a broadcast signel to every thread from
the interrupt routine. Counting the number of signals you receive you can
implement as many timers as you wish. That is a sensible approach if you
have a system that is full of state machines and many timers. If you want,
however, a more sophisticated approach, you can use the timer subsystem of
the kernel. It is still based on signals, but instead of getting a single,
regular event, you can set up independent timers, each of which delivers a
different event.

To keep track of the passage of time, you have to call the BZ_TimerTick()
function regularly and tell it how many microseconds have passed since its
last call. Timers are represented by BZ_TIME structures that reside in your
memory. You can start a timer by calling the BZ_TimerStart() function. When
the timer expires it will deliver an event to a thread, both the thread and
the event being specified by the BZ_TimerStart() function call.
You can also cancel a running timer, have periodic timers and you can get
the uptime of the system by further functions.

*/

/** @addtogroup coop_irq

Interrupt control.

When dealing with hardware, you often must disable interrupts for short
intervals. The kernel provides functions that allow you to enable and
disable them. Furthermore, even though the kernel does not support the
fast interrupt mechanism of the ARM core, it provides the functions to
enable and disable FIQ, in case you want to implement your own FIQ handler.
In addition, the atomic swap with a memory word is also provided.

*/

