atomsem.c File Reference

#include <stdio.h>
#include "atom.h"
#include "atomsem.h"
#include "atomtimer.h"

Data Structures

struct  sem_timer

Typedefs

typedef struct sem_timer SEM_TIMER

Functions

uint8_t atomSemCreate (ATOM_SEM *sem, uint8_t initial_count)
uint8_t atomSemDelete (ATOM_SEM *sem)
uint8_t atomSemGet (ATOM_SEM *sem, int32_t timeout)
uint8_t atomSemPut (ATOM_SEM *sem)
uint8_t atomSemResetCount (ATOM_SEM *sem, uint8_t count)

Detailed Description

Semaphore library.

This module implements a counting semaphore library with the following features:

Flexible blocking APIs
Threads which wish to decrement a semaphore can choose whether to block, block with timeout, or not block if the semaphore has reached zero.
Interrupt-safe calls
All APIs can be called from interrupt context. Any calls which could potentially block have optional parameters to prevent blocking if you wish to call them from interrupt context. Any attempt to make a call which would block from interrupt context will be automatically and safely prevented.
Priority-based queueing
Where multiple threads are blocking on a semaphore, they are woken in order of the threads' priorities. Where multiple threads of the same priority are blocking, they are woken in FIFO order.
Count up to 255
Semaphore counts can be initialised and incremented up to a maximum of 255.
Smart semaphore deletion
Where a semaphore is deleted while threads are blocking on it, all blocking threads are woken and returned a status code to indicate the reason for being woken.


Usage instructions:

All semaphore objects must be initialised before use by calling atomSemCreate(). Once initialised atomSemGet() and atomSemPut() are used to decrement and increment the semaphore count respectively.

If a semaphore count reaches zero, further calls to atomSemGet() will block the calling thread (unless the calling parameters request no blocking). If a call is made to atomSemPut() while threads are blocking on a zero-count semaphore, the highest priority thread is woken. Where multiple threads of the same priority are blocking, they are woken in the order in which the threads started blocking.

A semaphore which is no longer required can be deleted using atomSemDelete(). This function automatically wakes up any threads which are waiting on the deleted semaphore.


Notes:

Note that those considering using a semaphore initialised to 1 for mutual exclusion purposes may wish to investigate the mutex library available in Atomthreads.


Typedef Documentation

typedef struct sem_timer SEM_TIMER

Function Documentation

uint8_t atomSemCreate ( ATOM_SEM sem,
uint8_t  initial_count 
)

atomSemCreate

Initialises a semaphore object.

Must be called before calling any other semaphore library routines on a semaphore. Objects can be deleted later using atomSemDelete().

Does not allocate storage, the caller provides the semaphore object.

This function can be called from interrupt context.

Parameters:
[in] sem Pointer to semaphore object
[in] initial_count Initial count value
Return values:
ATOM_OK Success
ATOM_ERR_PARAM Bad parameters

References ATOM_ERR_PARAM, ATOM_OK, atom_sem::count, atom_sem::suspQ, and uint8_t.

uint8_t atomSemDelete ( ATOM_SEM sem  ) 

atomSemDelete

Deletes a semaphore object.

Any threads currently suspended on the semaphore will be woken up with return status ATOM_ERR_DELETED. If called at thread context then the scheduler will be called during this function which may schedule in one of the woken threads depending on relative priorities.

This function can be called from interrupt context, but loops internally waking up all threads blocking on the semaphore, so the potential execution cycles cannot be determined in advance.

Parameters:
[in] sem Pointer to semaphore object
Return values:
ATOM_OK Success
ATOM_ERR_QUEUE Problem putting a woken thread on the ready queue
ATOM_ERR_TIMER Problem cancelling a timeout on a woken thread

Only call the scheduler if we are in thread context, otherwise it will be called on exiting the ISR by atomIntExit().

References ATOM_ERR_DELETED, ATOM_ERR_PARAM, ATOM_ERR_QUEUE, ATOM_ERR_TIMER, ATOM_OK, atomCurrentContext(), atomSched(), atomTimerCancel(), CRITICAL_END, CRITICAL_START, CRITICAL_STORE, FALSE, atom_tcb::suspend_timo_cb, atom_tcb::suspend_wake_status, atom_sem::suspQ, tcbDequeueHead(), tcbEnqueuePriority(), tcbReadyQ, TRUE, and uint8_t.

uint8_t atomSemGet ( ATOM_SEM sem,
int32_t  timeout 
)

atomSemGet

Perform a get operation on a semaphore.

This decrements the current count value for the semaphore and returns. If the count value is already zero then the call will block until the count is incremented by another thread, or until the specified timeout is reached. Blocking threads will also be woken if the semaphore is deleted by another thread while blocking.

Depending on the timeout value specified the call will do one of the following if the count value is zero:

timeout == 0 : Call will block until the count is non-zero
timeout > 0 : Call will block until non-zero up to the specified timeout
timeout == -1 : Return immediately if the count is zero

If the call needs to block and timeout is zero, it will block indefinitely until atomSemPut() or atomSemDelete() is called on the semaphore.

If the call needs to block and timeout is non-zero, the call will only block for the specified number of system ticks after which time, if the thread was not already woken, the call will return with ATOM_TIMEOUT.

If the call would normally block and timeout is -1, the call will return immediately with ATOM_WOULDBLOCK.

This function can only be called from interrupt context if the timeout parameter is -1 (in which case it does not block).

Parameters:
[in] sem Pointer to semaphore object
[in] timeout Max system ticks to block (0 = forever)
Return values:
ATOM_OK Success
ATOM_TIMEOUT Semaphore timed out before being woken
ATOM_WOULDBLOCK Called with timeout == -1 but count is zero
ATOM_ERR_DELETED Semaphore was deleted while suspended
ATOM_ERR_CONTEXT Not called in thread context and attempted to block
ATOM_ERR_PARAM Bad parameter
ATOM_ERR_QUEUE Problem putting the thread on the suspend queue
ATOM_ERR_TIMER Problem registering the timeout

Store the timer details in the TCB so that we can cancel the timer callback if the semaphore is put before the timeout occurs.

Current thread now blocking, schedule in a new one. We already know we are in thread context so can call the scheduler from here.

Normal atomSemPut() wakeups will set ATOM_OK status, while timeouts will set ATOM_TIMEOUT and semaphore deletions will set ATOM_ERR_DELETED.

If we have been woken up with ATOM_OK then another thread incremented the semaphore and handed control to this thread. In theory the the posting thread increments the counter and as soon as this thread wakes up we decrement the counter here, but to prevent another thread preempting this thread and decrementing the semaphore before this section was scheduled back in, we emulate the increment and decrement by not incrementing in the atomSemPut() and not decrementing here. The count remains zero throughout preventing other threads preempting before we decrement the count again.

References ATOM_ERR_CONTEXT, ATOM_ERR_PARAM, ATOM_ERR_QUEUE, ATOM_ERR_TIMER, ATOM_OK, ATOM_WOULDBLOCK, atomCurrentContext(), atomSched(), atomTimerRegister(), atom_timer::cb_data, atom_timer::cb_func, atom_timer::cb_ticks, atom_sem::count, CRITICAL_END, CRITICAL_START, CRITICAL_STORE, FALSE, POINTER, sem_timer::sem_ptr, atom_tcb::suspend_timo_cb, atom_tcb::suspend_wake_status, atom_tcb::suspended, atom_sem::suspQ, sem_timer::tcb_ptr, tcbDequeueEntry(), tcbEnqueuePriority(), TRUE, and uint8_t.

uint8_t atomSemPut ( ATOM_SEM sem  ) 

atomSemPut

Perform a put operation on a semaphore.

This increments the current count value for the semaphore and returns.

If the count value was previously zero and there are threads blocking on the semaphore, the call will wake up the highest priority thread suspended. Only one thread is woken per call to atomSemPut(). If multiple threads of the same priority are suspended, they are woken in order of suspension (FIFO).

This function can be called from interrupt context.

Parameters:
[in] sem Pointer to semaphore object
Return values:
ATOM_OK Success
ATOM_ERR_OVF The semaphore count would have overflowed (>255)
ATOM_ERR_PARAM Bad parameter
ATOM_ERR_QUEUE Problem putting a woken thread on the ready queue
ATOM_ERR_TIMER Problem cancelling a timeout for a woken thread

Threads are woken up in priority order, with a FIFO system used on same priority threads. We always take the head, ordering is taken care of by an ordered list enqueue.

The scheduler may now make a policy decision to thread switch if we are currently in thread context. If we are in interrupt context it will be handled by atomIntExit().

References ATOM_ERR_OVF, ATOM_ERR_PARAM, ATOM_ERR_QUEUE, ATOM_ERR_TIMER, ATOM_OK, atomCurrentContext(), atomSched(), atomTimerCancel(), atom_sem::count, CRITICAL_END, CRITICAL_START, CRITICAL_STORE, FALSE, atom_tcb::suspend_timo_cb, atom_tcb::suspend_wake_status, atom_sem::suspQ, tcbDequeueHead(), tcbEnqueuePriority(), tcbReadyQ, and uint8_t.

uint8_t atomSemResetCount ( ATOM_SEM sem,
uint8_t  count 
)

atomSemResetCount

Set a new count value on a semaphore.

Care must be taken when using this function, as there may be threads suspended on the semaphore. In general it should only be used once a semaphore is out of use.

This function can be called from interrupt context.

Parameters:
[in] sem Pointer to semaphore object
[in] count New count value
Return values:
ATOM_OK Success
ATOM_ERR_PARAM Bad parameter

References ATOM_ERR_PARAM, ATOM_OK, atom_sem::count, and uint8_t.


Generated on Fri Jun 4 01:00:01 2010 for atomthreads by  doxygen 1.6.1