Semaphore functions
[Pre-emptive, soft real-time scheduler]

Semaphores are resource counters. More...

Data Structures

struct  BX_SEMA
 Semaphore object. More...

Defines

#define BX_SEMA_INIT(policy, count)
 Static initialiser for a semaphore.

Functions

int BX_SemaGet (BX_SEMA *sema, unsigned int value, unsigned int timeout)
 Waits for a number of resources on a semaphore.
int BX_SemaInit (BX_SEMA *sema, BX_POLICY policy, unsigned int value)
 Initialises a semaphore.
int BX_SemaPut (BX_SEMA *sema, unsigned int value)
 Add resources to a semaphore.

Detailed Description

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.

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.

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.
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.
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 A is running, thus it can release the resources it took. There's no deadlock.

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 policy of the semaphore. You can use 4 policies in this kernel:

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 BX_SEMA 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 BX_SEMA_INIT() macro) or by calling the initialiser function, BX_SemaInit(). The initialisation sets the semaphore's policy and the initial amount of resources it holds.


Define Documentation

#define BX_SEMA_INIT ( policy,
count   ) 
Value:
{                                                               \
    .base = {                                                   \
        .type = BX_TYPE_SEMA,                                   \
        .head = NULL,                                           \
        .tail = NULL,                                           \
        .ftab = (struct _bx_poli *) (                           \
                (policy) == BX_POLICY_SRQF ? &_bx_poli_srqf :   \
                (policy) == BX_POLICY_LRQF ? &_bx_poli_lrqf :   \
                (policy) == BX_POLICY_PRIO ? &_bx_poli_prio :   \
                &_bx_poli_fifo )                                \
    },                                                          \
    .cntr = (count)                                             \
}

Static initialiser for a semaphore.

Parameters:
policy The semaphore's waiting policy, one of BX_POLICY_FIFO, BX_POLICY_PRIO, BX_POLICY_LRQF or BX_POLICY_SRQF.
count The initial count on the semaphore.

Function Documentation

int BX_SemaGet ( BX_SEMA sema,
unsigned int  value,
unsigned int  timeout 
)

Waits for a number of resources on a semaphore.

Parameters:
sema Pointer to a semaphore
value The number of resources to be taken
timeout The maximum time to wait, in microsecs. If the value is -1 (cast to unsigned), then there is no timeout, the function will wait indefinitely. If the timeout value is 0, then the function will not wait, it will return to the caller immediately.
Return values:
>0 Success, the given number of resources were taken
=0 Timeout, no resources were taken
BX_ERR_OBJECT The semaphore was not initialised.
BX_ERR_CONTEXT The function was called from an ISR or delayed ISR.
BX_ERR_SUSPEND The caller would have to wait but it is currently running with IRQ or FIQ disabled and thus can not be suspended.
Note:
Although the timeout value is specified in microseconds, the actual resolution depends on the frequency of calls to the BX_TimerTick() function.
Attention:
This function should not be called from an ISR or delayed ISR. This function can suspend the caller.
int BX_SemaInit ( BX_SEMA sema,
BX_POLICY  policy,
unsigned int  value 
)

Initialises a semaphore.

Parameters:
sema Pointer to the semaphore structure
value Initial value (resource count) of the semaphore
policy The semaphore queueing policy. It must be one of BX_POLICY_FIFO, BX_POLICY_PRIO, BX_POLICY_LRQF or BX_POLICY_SRQF.
Return values:
>0 Success
BX_ERR_PARAM The policy parameter is not valid for a sempaphore
Attention:
This function does not suspend the caller. This function should not be called from an ISR or delayed ISR. Note, however, that the function does not check this criteria, to allow initialisation of semaphores before the kernel is started (which must happen in IRQ context). In addition, during the initialisation interrupts are not disabled.
int BX_SemaPut ( BX_SEMA sema,
unsigned int  value 
)

Add resources to a semaphore.

The counter of the semaphore will be incremented by the amount specified by the parameter. If the increment would overflow the semaphore's counter, then the counter will be set to its maximum value (0xffffffff).

Parameters:
sema Pointer to a semaphore
value The number of resources to be added to the semaphore
Return values:
>0 Success, the semaphore count was increased
BX_ERR_OBJECT The semaphore was not initialised.
Attention:
This function can be called from user, ISR or delayed ISR context. This function does not suspend the caller but can cause a context switch if a higher priority process is woken up by the call.
Generated on Fri Aug 13 12:02:25 2010 by  doxygen 1.6.3