atom.h File Reference

#include "atomtimer.h"
#include "atomport.h"

Go to the source code of this file.

Data Structures

struct  atom_tcb

Defines

#define TRUE   1
#define FALSE   0
#define ATOM_OK   0
#define ATOM_ERROR   1
#define ATOM_TIMEOUT   2
#define ATOM_WOULDBLOCK   3
#define ATOM_ERR_CONTEXT   200
#define ATOM_ERR_PARAM   201
#define ATOM_ERR_DELETED   202
#define ATOM_ERR_OVF   203
#define ATOM_ERR_QUEUE   204
#define ATOM_ERR_TIMER   205
#define ATOM_ERR_NOT_FOUND   206
#define ATOM_ERR_OWNERSHIP   207
#define IDLE_THREAD_PRIORITY   255

Typedefs

typedef struct atom_tcb ATOM_TCB

Functions

uint8_t atomOSInit (void *idle_thread_stack_top, uint32_t stack_size)
void atomOSStart (void)
void atomSched (uint8_t timer_tick)
void atomIntEnter (void)
void atomIntExit (uint8_t timer_tick)
uint8_t tcbEnqueuePriority (ATOM_TCB **tcb_queue_ptr, ATOM_TCB *tcb_ptr)
ATOM_TCBtcbDequeueHead (ATOM_TCB **tcb_queue_ptr)
ATOM_TCBtcbDequeueEntry (ATOM_TCB **tcb_queue_ptr, ATOM_TCB *tcb_ptr)
ATOM_TCBtcbDequeuePriority (ATOM_TCB **tcb_queue_ptr, uint8_t priority)
ATOM_TCBatomCurrentContext (void)
uint8_t atomThreadCreate (ATOM_TCB *tcb_ptr, uint8_t priority, void(*entry_point)(uint32_t), uint32_t entry_param, void *stack_top, uint32_t stack_size)
uint8_t atomThreadStackCheck (ATOM_TCB *tcb_ptr, uint32_t *used_bytes, uint32_t *free_bytes)
void archContextSwitch (ATOM_TCB *old_tcb_ptr, ATOM_TCB *new_tcb_ptr)
void archThreadContextInit (ATOM_TCB *tcb_ptr, void *stack_top, void(*entry_point)(uint32_t), uint32_t entry_param)
void archFirstThreadRestore (ATOM_TCB *new_tcb_ptr)
void atomTimerTick (void)

Variables

ATOM_TCBtcbReadyQ
uint8_t atomOSStarted

Define Documentation

#define ATOM_ERR_CONTEXT   200
#define ATOM_ERR_DELETED   202
#define ATOM_ERR_NOT_FOUND   206

Referenced by atomTimerCancel().

#define ATOM_ERR_OVF   203

Referenced by atomMutexGet(), and atomSemPut().

#define ATOM_ERR_OWNERSHIP   207

Referenced by atomMutexPut().

#define ATOM_ERR_PARAM   201
#define ATOM_ERR_QUEUE   204
#define ATOM_ERR_TIMER   205
#define ATOM_ERROR   1
#define ATOM_OK   0
#define ATOM_TIMEOUT   2
#define ATOM_WOULDBLOCK   3
#define FALSE   0
#define IDLE_THREAD_PRIORITY   255

Referenced by atomOSInit().

#define TRUE   1

Typedef Documentation

typedef struct atom_tcb ATOM_TCB

Function Documentation

void archContextSwitch ( ATOM_TCB old_tcb_ptr,
ATOM_TCB new_tcb_ptr 
)
void archFirstThreadRestore ( ATOM_TCB new_tcb_ptr  ) 

Referenced by atomOSStart().

void archThreadContextInit ( ATOM_TCB tcb_ptr,
void *  stack_top,
void(*)(uint32_t)  entry_point,
uint32_t  entry_param 
)

Referenced by atomThreadCreate().

ATOM_TCB* atomCurrentContext ( void   ) 

atomCurrentContext

Get the current thread context.

Returns a pointer to the current thread's TCB, or NULL if not in thread-context (in interrupt context).

Return values:
Pointer to current thread's TCB, NULL if in interrupt context

Referenced by atomMutexDelete(), atomMutexGet(), atomMutexPut(), atomQueueDelete(), atomQueueGet(), atomQueuePut(), atomSemDelete(), atomSemGet(), atomSemPut(), atomThreadCreate(), and atomTimerDelay().

void atomIntEnter ( void   ) 

atomIntEnter

Interrupt handler entry routine.

Must be called at the start of any interrupt handlers that may call an OS primitive and make a thread ready.

Returns:
None
void atomIntExit ( uint8_t  timer_tick  ) 

atomIntExit

Interrupt handler exit routine.

Must be called at the end of any interrupt handlers that may call an OS primitive and make a thread ready.

This is responsible for calling the scheduler at the end of interrupt handlers to determine whether a new thread has now been made ready and should be scheduled in.

Parameters:
timer_tick TRUE if this is a timer tick
Returns:
None

References atomSched().

uint8_t atomOSInit ( void *  idle_thread_stack_top,
uint32_t  idle_thread_stack_size 
)

atomOSInit

Initialise the atomthreads OS.

Must be called before any application code uses the atomthreads APIs. No threads are actually started until the application calls atomOSStart().

Callers must provide a pointer to some storage for the idle thread stack. The caller is responsible for calculating the appropriate space required for their particular architecture.

Applications should use the following initialisation sequence:

Interrupts should be disabled until the first thread restore is complete, to avoid any complications due to interrupts occurring while crucial operating system facilities are being initialised. They are normally enabled by the archFirstThreadRestore() routine in the architecture port.

Parameters:
[in] idle_thread_stack_top Ptr to top of stack area for idle thread
[in] idle_thread_stack_size Size of idle thread stack in bytes
Return values:
ATOM_OK Success
ATOM_ERROR Initialisation error

References atomOSStarted, atomThreadCreate(), FALSE, IDLE_THREAD_PRIORITY, and uint8_t.

void atomOSStart ( void   ) 

atomOSStart

Start the highest priority thread running.

This function must be called after all OS initialisation is complete, and at least one application thread has been created. It will start executing the highest priority thread created (or first created if multiple threads share the highest priority).

Interrupts must still be disabled at this point. They must only be enabled when the first thread is restored and started by the architecture port's archFirstThreadRestore() routine.

Returns:
None

Enable the OS started flag. This stops routines like atomThreadCreate() attempting to schedule in a newly-created thread until the scheduler is up and running.

Application calls to atomThreadCreate() should have added at least one thread to the ready queue. Take the highest priority one off and schedule it in. If no threads were created, the OS will simply start the idle thread (the lowest priority allowed to be scheduled is the idle thread's priority, 255).

References archFirstThreadRestore(), atomOSStarted, tcbDequeuePriority(), and TRUE.

void atomSched ( uint8_t  timer_tick  ) 

atomSched

This is an internal function not for use by application code.

This is the main scheduler routine. It is called by the various OS library routines to check if any threads should be scheduled in now. If so, the context will be switched from the current thread to the new one.

The scheduler is priority-based with round-robin performed on threads with the same priority. Round-robin is only performed on timer ticks however. During reschedules caused by an OS operation (e.g. after giving or taking a semaphore) we only allow the scheduling in of threads with higher priority than current priority. On timer ticks we also allow the scheduling of same-priority threads - in that case we schedule in the head of the ready list for that priority and put the current thread at the tail.

Parameters:
[in] timer_tick Should be TRUE when called from the system tick
Returns:
None

Check the OS has actually started. As long as the proper initialisation sequence is followed there should be no calls here until the OS is started, but we check to handle badly-behaved ports.

If the current thread is going into suspension, then unconditionally dequeue the next thread for execution.

Dequeue the next ready to run thread. There will always be at least the idle thread waiting. Note that this could actually be the suspending thread if it was unsuspended before the scheduler was called.

Don't need to add the current thread to any queue because it was suspended by another OS mechanism and will be sitting on a suspend queue or similar within one of the OS primitive libraries (e.g. semaphore).

Otherwise the current thread is still ready, but check if any other threads are ready.

Current priority is already highest (0), don't allow preempt by threads of any priority because this is not a time-slice.

References atomOSStarted, CRITICAL_END, CRITICAL_START, CRITICAL_STORE, FALSE, int16_t, atom_tcb::priority, atom_tcb::suspended, tcbDequeueHead(), tcbDequeuePriority(), tcbEnqueuePriority(), TRUE, and uint8_t.

Referenced by atomIntExit(), atomMutexDelete(), atomMutexGet(), atomMutexPut(), atomQueueDelete(), atomQueueGet(), atomQueuePut(), atomSemDelete(), atomSemGet(), atomSemPut(), atomThreadCreate(), and atomTimerDelay().

uint8_t atomThreadCreate ( ATOM_TCB tcb_ptr,
uint8_t  priority,
void(*)(uint32_t)  entry_point,
uint32_t  entry_param,
void *  stack_top,
uint32_t  stack_size 
)

atomThreadCreate

Creates and starts a new thread.

Callers provide the ATOM_TCB structure storage, these are not obtained from an internal TCB free list.

The function puts the new thread on the ready queue and calls the scheduler. If the priority is higher than the current priority, then the new thread may be scheduled in before the function returns.

Optionally prefills the thread stack with a known value to enable stack usage checking (if the ATOM_STACK_CHECKING macro is defined).

Parameters:
[in] tcb_ptr Pointer to the thread's TCB storage
[in] priority Priority of the thread (0 to 255)
[in] entry_point Thread entry point
[in] entry_param Parameter passed to thread entry point
[in] stack_top Top of the stack area
[in] stack_size Size of the stack area in bytes
Return values:
ATOM_OK Success
ATOM_ERR_PARAM Bad parameters
ATOM_ERR_QUEUE Error putting the thread on the ready queue

Store the thread entry point and parameter in the TCB. This may not be necessary for all architecture ports if they put all of this information in the initial thread stack.

Additional processing only required if stack-checking is enabled. Incurs a slight overhead on each thread creation and uses some additional storage in the TCB, but can be compiled out if not desired.

Call the arch-specific routine to set up the stack. This routine is responsible for creating the context save area necessary for allowing atomThreadSwitch() to schedule it in. The initial archContextSwitch() call when this thread gets scheduled in the first time will then restore the program counter to the thread entry point, and any other necessary register values ready for it to start running.

If the OS is started and we're in thread context, check if we should be scheduled in now.

References archThreadContextInit(), ATOM_ERR_PARAM, ATOM_ERR_QUEUE, ATOM_OK, atomCurrentContext(), atomOSStarted, atomSched(), CRITICAL_END, CRITICAL_START, CRITICAL_STORE, atom_tcb::entry_param, atom_tcb::entry_point, FALSE, atom_tcb::next_tcb, atom_tcb::prev_tcb, atom_tcb::priority, STACK_CHECK_BYTE, atom_tcb::suspend_timo_cb, atom_tcb::suspended, tcbEnqueuePriority(), TRUE, and uint8_t.

Referenced by atomOSInit().

uint8_t atomThreadStackCheck ( ATOM_TCB tcb_ptr,
uint32_t *  used_bytes,
uint32_t *  free_bytes 
)
void atomTimerTick ( void   ) 

atomTimerTick

System tick handler.

User ports are responsible for calling this routine once per system tick.

On each system tick this routine is called to do the following: 1. Increase the system tick count 2. Call back to any registered timer callbacks

Returns:
None

References atomOSStarted.

ATOM_TCB* tcbDequeueEntry ( ATOM_TCB **  tcb_queue_ptr,
ATOM_TCB tcb_ptr 
)

tcbDequeueEntry

This is an internal function not for use by application code.

Dequeues a particular TCB from the queue pointed to by tcb_queue_ptr.

The TCB will be removed from the queue.

tcb_queue_ptr may be modified by the routine if the dequeued TCB was the list head. It is valid for tcb_queue_ptr to point to a NULL pointer, which is the case if the queue is currently empty. In this case the function returns NULL.

NOTE: Assumes that the caller is already in a critical section.

Parameters:
[in,out] tcb_queue_ptr Pointer to TCB queue head pointer
[in] tcb_ptr Pointer to TCB to dequeue
Returns:
Pointer to the dequeued TCB, or NULL if entry wasn't found

References atom_tcb::next_tcb, and atom_tcb::prev_tcb.

Referenced by atomMutexGet(), atomQueueGet(), atomQueuePut(), and atomSemGet().

ATOM_TCB* tcbDequeueHead ( ATOM_TCB **  tcb_queue_ptr  ) 

tcbDequeueHead

This is an internal function not for use by application code.

Dequeues the highest priority TCB on the queue pointed to by tcb_queue_ptr.

The TCB will be removed from the queue. Same priority TCBs are dequeued in FIFO order.

tcb_queue_ptr will be modified by the routine if a TCB is dequeued, as this will be the list head. It is valid for tcb_queue_ptr to point to a NULL pointer, which is the case if the queue is currently empty. In this case the function returns NULL.

NOTE: Assumes that the caller is already in a critical section.

Parameters:
[in,out] tcb_queue_ptr Pointer to TCB queue head pointer
Returns:
Pointer to highest priority TCB on queue, or NULL if queue empty

References atom_tcb::next_tcb, and atom_tcb::prev_tcb.

Referenced by atomMutexDelete(), atomMutexPut(), atomQueueDelete(), atomSched(), atomSemDelete(), and atomSemPut().

ATOM_TCB* tcbDequeuePriority ( ATOM_TCB **  tcb_queue_ptr,
uint8_t  priority 
)

tcbDequeuePriority

This is an internal function not for use by application code.

Dequeues the first TCB of the given priority or higher, from the queue pointed to by tcb_queue_ptr. Because the queue is ordered high priority first, we only ever dequeue the list head, if any. If the list head is lower priority than we wish to dequeue, then all following ones will also be lower priority and hence are not parsed.

The TCB will be removed from the queue. Same priority TCBs will be dequeued in FIFO order.

tcb_queue_ptr may be modified by the routine if the dequeued TCB was the list head. It is valid for tcb_queue_ptr to point to a NULL pointer, which is the case if the queue is currently empty. In this case the function returns NULL.

NOTE: Assumes that the caller is already in a critical section.

Parameters:
[in,out] tcb_queue_ptr Pointer to TCB queue head pointer
[in] priority Minimum priority to qualify for dequeue
Returns:
Pointer to the dequeued TCB, or NULL if none found within priority

References atom_tcb::next_tcb, and atom_tcb::prev_tcb.

Referenced by atomOSStart(), and atomSched().

uint8_t tcbEnqueuePriority ( ATOM_TCB **  tcb_queue_ptr,
ATOM_TCB tcb_ptr 
)

tcbEnqueuePriority

This is an internal function not for use by application code.

Enqueues the TCB tcb_ptr on the TCB queue pointed to by tcb_queue_ptr. TCBs are placed on the queue in priority order. If there are existing TCBs at the same priority as the TCB to be enqueued, the enqueued TCB will be placed at the end of the same-priority TCBs. Calls to tcbDequeuePriority() will dequeue same-priority TCBs in FIFO order.

tcb_queue_ptr may be modified by the routine if the enqueued TCB becomes the new list head. It is valid for tcb_queue_ptr to point to a NULL pointer, which is the case if the queue is currently empty.

NOTE: Assumes that the caller is already in a critical section.

Parameters:
[in,out] tcb_queue_ptr Pointer to TCB queue head pointer
[in] tcb_ptr Pointer to TCB to enqueue
Return values:
ATOM_OK Success
ATOM_ERR_PARAM Bad parameters

References ATOM_ERR_PARAM, ATOM_OK, atom_tcb::next_tcb, atom_tcb::prev_tcb, atom_tcb::priority, and uint8_t.

Referenced by atomMutexDelete(), atomMutexGet(), atomMutexPut(), atomQueueDelete(), atomQueueGet(), atomQueuePut(), atomSched(), atomSemDelete(), atomSemGet(), atomSemPut(), and atomThreadCreate().


Variable Documentation

uint8_t atomOSStarted

Set to TRUE when OS is started and running threads

Referenced by atomOSInit(), atomOSStart(), atomSched(), atomThreadCreate(), and atomTimerTick().

This is the head of the queue of threads that are ready to run. It is ordered by priority, with the higher priority threads coming first. Where there are multiple threads of the same priority, the TCB (task control block) pointers are FIFO-ordered.

Dequeuing the head is a fast operation because the list is ordered. Enqueuing may have to walk up to the end of the list. This means that context-switch times depend on the number of threads on the ready queue, but efficient use is made of available RAM on tiny systems by avoiding priority tables etc. This scheme can be easily swapped out for other scheduler schemes by replacing the TCB enqueue and dequeue functions.

Once a thread is scheduled in, it is not present on the ready queue or any other kernel queue while it is running. When scheduled out it will be either placed back on the ready queue (if still ready), or will be suspended on some OS primitive if no longer ready (e.g. on the suspended TCB queue for a semaphore, or in the timer list if suspended on a timer delay).

Referenced by atomMutexDelete(), atomMutexPut(), atomQueueDelete(), atomSemDelete(), and atomSemPut().


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