/****************************************************************************/
/*	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 kernel */
/**	@{ */
/**		@defgroup bx_init	Initialisation functions */
/**		@defgroup bx_proc	Process management functions */
/**		@defgroup bx_sigs	Event (signal) functions */
/**		@defgroup bx_sema	Semaphore functions */
/**		@defgroup bx_lock	Mutual exclusivity lock functions */
/**		@defgroup bx_time	Timer functions */
/**		@defgroup bx_irq	Interrupt functions */
/**	@} */

/** @addtogroup kernel
A simple mutithreading kernel.

This executive is a simple multithreading kernel. It gives you the ability
to run separate threads of execution and provides the basic thread
synchronisation mechanisms. In the kernel docs <i>thread</i> and <i>process</i>
are used interchangeably. Since the target system has no MMU, there's no real
distinction between the two.

The kernel has a single data structure that holds its internal state (it is
in the uninitialised data segment). Everything else, including process stacks,
kernel objects and so on are provided by you. The kernel doesn't know your
memory situation so it leaves it to you to allocate your resources.

There is no limit on the number of resources the kernel can handle. As long as
you have the memory to store them, the kernel will handle them. There are no
compile-time configuration parameters or limits.

The kernel tries to keep interrupt latency as low as possible. This goal makes
the kernel more complex, as it can't just disable interrupts and finish whatever
needs to be done, no matter how long it takes. It actually disables interrupts
only when really necessary and re-enabes them as soon as possible. Thus, it
needs to invest some extra effort into keeping events ordered and the system
state consistent. It does not come for free, the kernel is not as fast as it
could be if it didn't care about the interrupts.

@section kbasics Kernel basics
@subsection pstates Processor states

The ARM7TDMI processor has 7 distinct states. The list below explains the
kernel's treatment of these states:

- <i>User state</i><br>
The kernel does not support user state. It needs to control interrupts
and those instructions are not available in user state. Therefore the
kernel assumes that user processes are running in system state, which
is the same as user state but without the instruction restrictions.
If you really want to use the user state, you have to wrap the kernel calls
with functions that switch to system state (via supervisor state) before
calling the kernel.

- <i>Supervisor state</i><br>
The kernel does not directly provide support for the supervisor state. It
treats it the same as system state. You can call kernel functions from
supervisor state, but the burden of maintaining the stacks is on your
shoulders.

- <i>Abort exception state and illegal instruction exception state</i><br>
The kernel does not support the abort and illegal instruction exceptions
at all. Those states are entered when something really bad happened. Do
not call the kernel from the exception handlers.

- <i>Fast interrupt state</i><br>
The kernel is aware of but does not support the fast interrupt state directly.
The fast interrupt is designed for interrupt routines that are very high
priority. For that reason the processor provides a handful of registers
that are saved by the hardware before entering the fast interrupt service
routine. If your interrupt service routine is simple enough, that is all
that you need. If you have a very high priority interrupt, you probably
do not want to slow it down by going through a kernel, save registers and
so on. Therefore the kernel assumes that the fast interrupt is outside of
its domain. The kernel's awareness of the fast interrupt is limited to
providing a functionality to enable and disable the fast interrupt.
Note, however, that it is important not to change the fast interrupt enable
state without the kernel knowing about it.<br>
In addition, functions are provided to atomicly swap a value in a memory
word or byte, with which you can implement spinlocks. If you are in ARM
mode (an interrupt handler always enters in ARM mode), then these functions
will be simple inline assembly instructions. That way the compiler will not
generate register saves and alike.<br>
In short, the kernel is aware of the fast interrupt mechanism, but you
must not call any kernel function from your fast interrupt handler.

- <i>Interrupt state</i><br>
This is a fully supported state. There is one important thing, though.
The kernel does <b>not</b> support nested interrupts. Each interrupt
must run to completion before the next one is accepted. If you enable
interrupts inside an ISR, then the system most likely will crash.
However, the kernel supports delaye interrupt handling, thus you can
keep your ISRs short, minimising the interrupt latency.

- <i>System state</i><br>
This is the state in which all user processes are running. In addition, the
kernel's internal event processing is also executed in system state.

@subsection kstates Kernel states

The kernel itself can be in three states, depending on what is being
executed by the CPU:
- A user process is running
- An interrupt service routine is running
- The kernel is doing some internal work or it has called a <i>delayed ISR</i>
function. Being idle is also a kernel internal state.

Since the kernel knows its own state, there are no separate functions to call
from interrupt service routines and from user routines. The kernel, if it has
to, will differentiate between the calling contexts inside the function.

@subsection kprocess Processes
A process, or thread, is a thread of execution. It has its own stack (provided
by you). It can be in four major states:
- <i>Running</i><br>
The process is currently being executed by the processor.

- <i>Interrupted</i><br>
The process would be executed by the processor but the processor is taken
by an interrupt service routine or by the kernel itself.

- <i>Ready</i><br>
The process is ready to run, but there is an other user process that is
occupying the CPU, either because it has higher priority or because it
is in a protected mode.

- <i>Suspended</i><br>
The process is waiting for some event or resource and can not run.

Processes have a priority associated with them. At any given time, the kernel
selects the highest priority ready process to run. The kernel is pre-emptive,
meaning that is a higher priority process becomes ready, the currently running
process will be kicked off the processor and the higher priority one will
start to run immediately. The kernel provides mechanisms to change the process
priorities as well as to protect a process from being pre-empted.

The kernel does <b>not</b> provide a way to kill a process. Once a process
is started, it will remain alive until it decides to die. There is no way
to kill a process. All you can do is to ask the process to commit suicide.

@subsection keventq	Kernel event queue

Normally, you can not afford to have the kernel's internal state to be in
an inconsistent state when an interrupt occurs because interrupt routines
can call kernel functions that need to operate on the kernel state.
If the kernel disables the interrupts while it processes a request, then
the problem is solved. However, some operations, in particular, the evaluation
of the priority inheritance chain if the resource in question uses priority
inheritance or priority ceiling, might take considerable time as the kernel
has to visit every member of the chain and re-evaluate priorities.
To keep interrupt latencies low, the kernel employs a different technique.
For simple operations which has no consequence on objects other that the
one is operated on, the kernel simply disables the interrupts for the
duration of the operation. If, however, it needs to do something that
involves multiple objects or evaluating priority queues, it uses an event
queue.
<br><br>
The event queue is simply a queue of actions that should be performed by
the kernel. When the kernel decides that an operation can not be done
immediately for any reason, it places the operation into the queue and makes
note that the queue is not empty. When the kernel reaches the point of
returning to a user process, then instead of doing that it will go and
execute the actions noted in the event queue. When the event queue is
empty, <i>then</i> it retruns to the current user process.<br>
While the kernel processes the event queue it usually keeps the interrupts
enabled (except for short periods of time). If an interrupt comes during
queue processing and it calls a kernel function, that function just deposits
an other event into the queue. That way the order of events is maintained.<br>
Naturally, since the event queue is finite in size, if you have a burst of
interrupts, it could overflow. To avoid that the kernel, when the event queue
grows over a watermark level, disables interrupts and does not enable them
again until the event queue dips below the watermark.<br>
Processing the event queue is similar to a process in the sense that it has
its own stack and that it executes in system mode (like all threads). However,
it is a special task because context switches to and from that particular task
are very cheap.
<br>
You can exploit the event queue in your code in two ways:
- <b>Delayed interrupt services</b><br>
	If you can split your interrupt routine to a part that keeps the hardware
	happy and an other part that processes all the software aspects of the
	interrupt, you can delay the software side of things until the actual
	interrupt routine returns. You split your interrupt service routine into
	two functions. One, that deals with the hardware, is registered as your
	actual ISR. That function does the hardware related bits then instructs
	the kernel to queue the calling of the second half of the function. The
	ISR the returns and the kernel will call the second half of your service
	routine. However, thet routine will be called in a system context, with
	interrupts enabled (although you can disable them in your function) thus
	your interrupt latency will not be affected by this second part of the
	service.
- <b>Software interrupts</b><br>
	Nothing stops you to call the function that deposits an action in the
	event queue from a normal thread. If you do that, then the kernel queues
	the activity and immediately switches to event processing mode and does
	not return to you until it finished with the activity. Thus, it is just
	a convoluted form of calling a function. However, the called function will
	run in the kernel's context, with certain privileges (and limitations)
	that you may want to expoit.

*/

/** @addtogroup bx_proc

This group of functions is responsible for the handling of processes.
Processes have two attributes. One is their <i>priority</i>. It is simply
a number, assigned by you. The kernel selects the process with the highest
priority to run. There is no timeslicing between identical priority
processes, if a process starts to run, it is let to run until it goes
to wait or a higher priority process becomes active.<br>
A process actually has two priorities assigned to it. One is the number
that you set as its priority. It is called its <i>real</i> priority.
However, it is possible that the kernel temporarily raises the priority
of a process through the priority ceiling or priority inheritance mechanism.
That elevated priority is called the <i>effective</i> priority. When the
kernel selects the process to run, it looks at the effective priority of
the processes.
<br><br>
The other attribute is the process' <i>protection level</i>. It indicates
what can interrupt the process. Four levels are defined.

- If a process is in normal level, then it can be preempted (kicked off
from the CPU) by interrupt routines, the kernel itself or by any process
that has higher priority and becomes active.

- If a process is at the cooperative level, the interrupts and the kernel
itself can interrupt it, but even if a higher priority process becomes
ready, it will not be allowed to run until the process at the cooperative
protection level voluntarily gives up the CPU, either by dropping is
protection level to normal or by calling a kernel function that suspends it.

- If a process is in disabled IRQ mode, then the processor's IRQ (hardware
interrupt will be disabled). The only thing that can possibly cause the
CPU to execute code other than that of the protected process if the fast
interrupt, FIQ. Note, however, that in that level it is illegal for the
process to call any kernel function that can cause it get suspended.

- If a process is in disabled FIQ mode, then both IRQ and FIQ are disabled
on the CPU. The process has absolute control over the processor and will
not be interrupted for any reason. Like in the disabled IRQ case, it is
illegale for the process to call any function that could potentially
suspend it.

*/

/** @addtogroup bx_sigs

Events, or signals, are the simplest (and fastest) interprocess communication
mechanism. Each process has 31 1-bit signals. Posting an event to a process
means setting one of those bits to 1. Waiting for events suspends the process
until at least one bit from a subset of that 31 bits (the subset selected by
the process) becomes 1. When the waiting process wakes up, all bits that are
set in its selected subset are returned to it (so it knows why it woke up)
and then they are reset to 0, ready to accept new signals.
<br><br>
The advantages of this mechanism are that it is very simple and fast, and that
it allows you to wait for multiple events at the same time. The disadvantage
is that events can be lost. If you post an event (i.e. set a bit to 1) and
then post the same event again before the process had a chance to evaluate
its signal status, you effectively set a bit to 1 that was already 1, that
is, you did nothing. The receiving process will get only one notification
even though you posted the event twice.

*/

/** @addtogroup bx_sema

Semaphores are resource counters. A semaphore maintains a count, which is
an unsigned integer. A process can request a certain amount of resources.
If the semaphore's count is at least as large as the requested amount,
the process is let to run and the counter is decremented by the requested
amount. As the process finishes with the resources, it can give them back
to the semaphore, which basically means incrementing its counter.
<br><br>
If the semaphore does not have enough resources, then the requesting process
will be suspended until the semaphore receives resources. As soon as the
semaphore's counter reaches the requested amount, the process gets unblocked,
that is, its request is satisfied.
<br><br>
Most semaphore implementations allow you to take or give back one resource
at the time. This implementation allows you to request and return an arbitrary
number of resources. This latter method is more complex to implement, but it
has certain advantages.<br>
First, it is faster. If you need 10 resources, then if you have to request
them one at a time, you have to call the kernel 10 times. It is obviously
much more efficient to call the kernel only once.<br>
Second, the one at a time method can lead to a deadlock. Let's say a semaphore
has 10 resources. Process A wants to get 8 of them, so it starts to get them
one after the other in a loop. Now let's assume that when it has already
acquired 6 of them, process B, which has higher priority than A wakes up.
Therefore, B will start to run. Let's assume that it also need the resources
maintained by the semaphore, namely 5 of them. So it starts to get them in a
loop. Since A has already taken 6 from the semaphore, there are only 4 left.
After B gets that 4, it will be suspended on the semaphore, as it is now
empty. Due to B being suspended, A starts to run again, trying to obtain the
last 2 resources. Alas, the semaphore is now empty, so A gets suspended on its
next request. The net effect is that both A and B are suspended and they are
also stuck, because neither of them can give back the resources it took.
With the version implemented in the kernel A requests 8 items, it gets them
in one hit. If B wakes up and asks for its 5 resources, it will be suspended
on the semaphore (as it only has 2 left), but <i>A is running</i>, thus it
can release the resources it took. There's no deadlock.
<br><br>
Now what happens if more than one process is waiting for resources on the
same semaphore? When the semaphore gets enough resources, which of the
waiting processes will get them? That depends on the <i>policy</i> of the
semaphore. You can use 4 policies in this kernel:

- FIFO<br>
	The requests are satisfied in the order they arrived onto the semaphore.
	If process A comes first and ask for N resources (and gets suspended
	because the semaphore doesn't have any) then process B comes and asks
	for just a single resource, B will be suspended and will not run until
	the request of A can be satisfied first. Note that B gets suspended even
	if the semaphore could satisfy its request, because the policy says that
	the processes must leave the semaphore in the same order as they arrived
	to it.

- By priority<br>
	The processing order is determined by the effective priority of the
	waiting processes; the highest priority process gets served first. The
	arbitration between identical priority processes is random.

- Smallest requests first<br>
	The smallest requested amount is served first. If there are
	identical amounts, the order is random.

- Largest requests first<br>
	The largest requested amount is served first. If there are
	identical amounts, the order is random.

In addition, semaphores support a timeout, where the caller can specify
a maximum amount of time it is willing to wait for the resources.

Semaphores are represented by the <tt>BX_SEMA</tt> structure. You have to
define the smeaphores you want to use, that is, the memory for the
semaphore structure is provided by you. You must also initialise them either
using a static initialiser (the <tt>BX_SEMA_INIT()</tt> macro) or by
calling the initialiser function, <tt>BX_SemaInit()</tt>. The initialisation
sets the semaphore's policy and the initial amount of resources it holds.

*/

/** @addtogroup bx_time

The kernel supports an unlimited number of software timers.
The timers, like any other kernel object, are statically allocated by the user.

@section res Resolution and time units

The timing subsystem calculates everything in microseconds. However, it does
not use a hardware timer - it can not know your microcontroller or your
timer allocation strategy. Therefore, it is your responsibility to set up
a timer interrupt and from that handler you must call the BX_TimerTick()
function. This function has one parameter, which is the number of microseconds
elapsed since the previous call to the function. In some cases you have a timer
interrupt source of which the period is not an exact multiple of a microsecond.
A very simple trick in your timer interrupt routine can solve that problem.
Here is an example. Let's assume that you get your timer interrupt from your
real-time clock, which generates a 2048Hz interrupt, divided from the 32.768kHz
watch crystal. The period of 2048Hz is 488.28125µs. If you simply ignore the
fractional bit and call BX_TimerTick() with 488 as parameter, you generate a
roughly 0.06% error. It doesn't sound too much, but in a day it adds up to
almost a minute. You want better than that. Basically, you are losing
0.28125µs or 281250ps at every call. So, if you start accumulating the
error and add 1µs every time your accumulated error reaches one microsec
(and then subtract it from the accumulated error), you can guarantee that
you are always within 1µs of the real time. So, every time you receive the
2048Hz interrupt, you add 281250ps to an accumulator. If the accumulator
is less than 1000000, that is, 1µs, you tell the kernel's timer subsystem
that 488µs has elapsed. If the accumulator goes above 1000000, then you know
that you have accumulated 1µs error. Thus, you tell the kernel that 489µs
has elapsed, subtract 1000000 from the accumulator and keep going.<br>
This method is well known and widely used. It is often implemented in
hardware, under the names of <i>modulus counter</i> or <i>fractional
divider</i>.
As the name implies, what you are in effect doing is a division and of course
you can always simplify a division by the GCD of the dividend and the divisior.
In our case 1000000 and 281250 has a GCD of 31250, thus we can replace them
with 32 and 9, respectively. Using constants less than 256 has code efficiency
advantages on the ARM, so the simplification is actually useful. Here's a
simple code snippet to show a possible implementation:
@code
#define	DENOMINATOR		32
#define	NUMERATOR		9

static int accu = 0;	// Accumulator for the modulus counter

void TimerISR( void )
{
	// Do all sorts of things to keep the interrupt system happy

	...

	// Process the modulus counter

	accu += NUMERATOR;

	if ( accu >= DENOMINATOR ) {

		// The accumulator (i.e. the numerator) is larger than or equal
		// to the denominator. That is, the fraction became >= 1. This
		// means that we have collected a full microsec. Take it from
		// the accumulator ...

		accu -= DENOMINATOR;

		// ... and call the timer subsystem with an extra microsec.

		BX_TimerTick( 488 + 1 );
	}
	else {

		// We haven't accumulated a full microsec error yet, just
		// tell the timer subsystem that 488 microsecs have elapsed.

		BX_TimerTick( 488 );
	}
}
@endcode

As you can see, the extra code is very little and rather simple. As long as
you can express your period as an integer plus a fraction of two integers,
of which the sum is less than 2^32 - 1 (so that you can be sure that your
addition never overflows), the timing subsystem will not deviate from
your crystal.<br>
The example also indicates that BX_TimerTick() does not expect you to call
it with the same argument every time. You can call it at any time you wish,
passing it the number of microsecs since the last call.
<br><br>
So, the timer system now keeps track of microseconds. However, there's a
question: how can it handle a timer of, say, 30µs if you call the
BX_TimerTick() function once in every 488µs?<br>
Well, it can't. The timer subsystem uses microsecond units, but its
<i>actual resolution</i> is no better than the resolution of
calls to the BX_TimerTick() function.
Timers expire only when you call that function. If you need a real 30µs timer,
then you have to create one using a hardware timer. With a 2048Hz timer
interrupt your timers will be pretty accurate in the tens of milliseconds
range but useless in the tens of microseconds range.<br><br>

@section isr Calling timer functions from ISRs

The BX_TimerTick() function is a fast function. It does not actually do
anythinhg with the timers. It knows if a timer will expire or not and if
yes, it signals the kernel that it should switch to system mode and process
the expiring timers. That's all BX_TimerTick() does, and it returns to your
ISR immediately.
Therefore, in your ISR, even if you know that the next call to BX_TimerTick()
will expire a particular timer, you can not expect to see it being expired
when the call returns.<br><br>
This is true to all timer function calls. If you call them from an ISR, all
they do is leave a message to the kernel, indicating what should be done, but
they do not wait for it to be finished.
The return value you receive about success or failure is still true. The
routine called from the ISR knows up front if the requested action will
succeed or not. For example, if you have a running timer and you cancel it
from an ISR, you get a success return value, but the timer is still attached
to the timer subsystem. If a subsequent ISR also cancels the timer, before
the kernel had time to actually detach it, the second ISR will get a return
value indicating that the timer was already cancelled. The consistency is
maintained, even though the timer in fact is still a running timer.
Before the kernel returns to a <i>user</i> process, however, the timer will be
cancelled and truly detached from the timer subsystem.

@section act Timer action

When a timer expires, it performs an action defined by you. More precisely,
it generates a soft interrupt of your choice. That is, it will call a function
with two parameters and that function will execute in the system context.
The function as well as its argument can be defined by a timer by timer basis,
and you can change it even on a running timer. The BX_TimerAction() call is
used to set it up. Quite often timers are used as a timeout for some external
condition. So, you would do something like this (error checks are omitted):

@code

// We have a timer, quite intuitively called "timer".
// Let's assume that it's already initialised and is not
// doing anything at the moment.

static BX_TIME	timer;

void	SomeFunction( void )
{
int		event;

	// We start some hardware operation now. It will send us a signal
	// at completion; we specify the signal in the argument.

	StartSomeHardware( MY_HW_DONE_SIGNAL );

	// Now we specify the timer action for the timer. We want to get a
	// signal when the timer expires. The timer calls a function with
	// two (32-bit) parameters. The BX_SignalSend() function is like that,
	// although its prototype is different, but the number (and size) of
	// the arguments match. So we just cast it to the proper type and we
	// also cast its parameters to the proper type:

	BX_TimerAction( &timer, (BX_DISR_FUNC) BX_SignalSend,
				    (void *) BX_ProcSelf(), (void *) MY_TIMEOUT_SIGNAL );

	// Let's start the timer

	BX_TimerStart( &timer, TIMEOUT_TIME_IN_MICROSEC, 0 );

	// We can now wait for either the timeout or the HW to finish

	event = BX_EventWait( MY_HW_DONE_SIGNAL | MY_TIMEOUT_SIGNAL );

	if ( event & MY_TIMEOUT_SIGNAL ) {

		// We had a timeout, stop the hardware and do whatever we have to.
	}
	else {

		// The hardware finished in time, cancel the timer

		BX_TimerCancel( &timer );
	}

	...
@endcode

@section init Initialisation

Before use, a timer has to be initialised. The initialisation only prepares
the data structure to act as a timer, but otherwise it doesn't do anything.
You can either call BX_TimerInit() or you can initialise the timer structure
statically using the TIMER_INIT() macro. Note that using a timer that has not
been initialised will cause either the functions returning a run-time error
code (if they realise that the timer was not initialised), or, if you are
unlucky and the memory image of the structure contains data that looks like
a timer, a system crash. Initialising a running timer will also cause a
system crash. Statically allocated timers need to be initialised once, at
startup, and never again.<br>
You can also allocate timers on the stack, if you make sure about
two things:
- You initialise the timer before you use it
- You cancel the timer before you leave the function and the stackframe with
the timer gets deallocated.

If you forget either of these, you will end up with very hard to debug crashes.

@section start Starting a timer

Once you initialised your timer and set up its action, you can start it. The
BX_TimerStart() function gets a timer and two time values. The first time value
is the time to the first expiry of the timer. If the second value is 0, then
that's all the timer does. If it is not 0, however, then the timer, when it
expires, will restart itself with that value. The difference between you
restarting the timer in the timer expiry soft interrupt and the timer
restarting itself is that the timer takes the latencies into account.
If you set up a periodic timer with 10ms period, there might be some variation
between subsequent expiry times, but on average the associated soft interrupt
will be activated at 100Hz. When you do it on your own, the delay between the
timer expiring and your soft interrupt restarting the timer is not compensated
anywhere and your average frequency will be less than 100Hz. However, keep in
mind that if one soft interrupt from a periodic timer is late, it will
compensate for it and thus your next soft interrupt will arrive in less time
than the period of timer is. You can not rely on two consecutive soft interrupts
to be at least a period apart. A periodic timer is most useful if you want to
guarantee that some activity happens with a certain frequency, at least on
average.

@section rest Reloading a timer

If you have a timer running, sometimes you just want to restart it. The
BX_TimerReload() function does that for you. A practical scenario is a
serial comms handler that expects that characters are coming more or
less constantly from the other end. Small delays are accepted, but if
the other end stops for an extended period, you have to signal error.<br>
You can set up a timer with the expiry time of the too long silence and
whenever you receive a character, you just restart it. Note that once the
timer expires, you can not restart it any more. Also note that this technique
is more suitable for slow comms. If you have a 115.2kbaud line, then calling
BX_TimerReload() after each character, i.e. with 10kHz will work but it will
consume a serious amount of CPU time. For a 9600baud line the technique is
fine.

@section canc Cancelling a timer

If you do not need a timer any more, you can cancel it. After the cancellation
the timer will not be attached to the kernel's timer subsystem in any way and
you can, if you want, release the timer structure. The BX_TimerCancel() call
leaves the structure initialised and it's action settings intack, so you can
call BX_TimerStart() after a cancel without any other timer calls. You do not
have to cancel a timer that has expired and did not restart itself; from
the user's point of view the only difference between a non-periodic timer
expiring and cancelling a timer is that cancellation does not call the timer's
associated action function.

*/

/** @addtogroup bx_lock

Locks are guaranteeing mutually exclusive access to some resource. If you want
to use the resource, you first <i>obtain</i> the lock. If the lock is already
<i>owned</i> by an other process, you will be suspended until the other
process <i>releases</i> it. Once you own the lock, you know that no other
process can get it until you release it.<br>
A lock is also known as a <i>mutex</i> or a <i>binary semaphore</I>.
<br><br>
If more than one process waits for a lock, the question arises which one of
the waiting processes gets it when the current owner releases the lock.
The kernel supports two policies, one is FIFO, where the processes are served
according to their request order. The other is by priority, in which case the
highest priority waiting process will get the lock.
<br><br>
There is an interesting phenomenon, though, that warrants consideration.
Let's assume that we have two processes, a low priority one that we'll
call L and a high priority one, H. Let L take the lock. Then, if H wakes
up, it will suspend L as H has higher priority. Now if H wants to access
the resource protected by the lock, it tries to obtain the lock. Since it
is already owned by L, H will be suspended, L resumes execution and when
it finishes with the resource and releases the lock, it will immediately
be given to H. Thus, H becomes ready, L gets suspended and H can chug away
doing whatever it has to.<br>
Let us introduce a third process, M, which has a priority between that of
L and H. As before, L takes the lock, H wakes up, tries to obtain the lock,
gets suspended. However, before L could finish with the resource, M wakes up
and starts a lengthy operation that has nothing to do with the protected
resources. Since M has higher priority than L, L will be suspended. Since
L is suspended, it can not release the lock. Therefore H is also suspended
as long as M is running, even though they do not compete for the resource.
In effect, a high priority process is held up by a lower priority one.
This phenomena is known as <i>priority inversion</i>. There are two methods
commonly used to avoid it.

- Priority ceiling<br>
	A lock has a priority associated with it, which is usually the priority
	of the highest priority process that can obtain the lock. If a process
	gets the lock, its priority is elevated to the level associated with
	the lock and dropped back to its normal level when the lock is released.
	This way it is guaranteed that as long as process holds the resource,
	no process at a lower priority that the highest priority potential lock
	owner can suspend it. While this method avoids priority inversion, it
	has two problems. One is that you need to know <i>a priori</i> the
	highest priority of the processes that can take the lock. The other is
	that since a low priority process will be elevated to the lock's priority
	as soon as it takes the lock, it will stop all other processes below that
	high priority even if there's no competition for the lock.

- Priority inheritance<br>
	This method solves the problems associated with priority ceiling. When
	a process gets the lock, nothing changes. However, if an other process
	comes to obtain the lock, then if the new process' priority is higher
	than that of the lock owner, then the owner's priority will be temporarily
	raised to that of the waiting process. If yet an other process comes to
	wait with an even higher priority, then the owner's priority will be
	raised again, to match that. In general, the lock owner's priority is
	raised to the largest of the priorities of the processes waiting for the
	lock.

While these methods seem simple enough, they get a bit complicated when
you have multiple locks. Let us have two locks, A and B, using priority
inheritance. If a process takes A and then goes to take B as well but B
is already taken, then the process gets suspended on B. Naturally, B's
owner's priority will be raised to match that of this process. Now if a
third process with a priority even higher goes to wait on A, then the
priority of the process that owns A is raised. That process waits on B,
thus the priority of the owner of B must also be raised. So the kernel
has to evaluate the ownership chain. The situation is even more complex
when you have timeouts, because if a high priority process ceases to wait
for a lock, you have to check if you can lower the priority of the lock
owner.
<br><br>
Since the priority ceiling and inheritance mechanisms are orthogonal concepts
to the ordering of the waiting queue, the locks support 6 different policies:

- Queue order is FIFO, no priority inheritance or ceiling
- Queue order is FIFO, priority ceiling
- Queue order is FIFO, priority inheritance
- Queue order is by priority, no priority inheritance or ceiling
- Queue order is by priority, priority ceiling
- Queue order is by priority, priority inheritance

Locks, like any other kernel object, are allocated by you in your memory.
Before you can use a lock, you must initialise it, using either the
BX_LOCK_INIT() static initialiser macro or the BX_LockInit() function.

*/

