Threads and Scheduling
A thread is a sequence of programmed instructions that can be scheduled and executed independently by the kernel. The threads
provide an abstraction for concurrent execution that ultimately provides a method for multitasking.
The kernel schedules CPU time for each of the threads based upon their priority. At any point in the application where a higher priority thread becomes
ready to execute, the kernel will switch the CPU to execute the higher priority thread. This method of scheduling threads provides
the shortest latency for the highest priority threads.
By default, the kernel will schedule threads to run based upon their priority. A higher priority thread will always receive
time on the CPU over that of a lower priority thread. The kernel will interrupt (preempt) a lower priority thread to run a higher
priority thread if it becomes signaled to run. This strategy of scheduling ensures that at all times, the highest priority thread will receive
the CPU with minimal latency.
Threads that share the same priority are scheduled to run in a round-robin fashion. When each thread executes, it
is assigned a 'slice' of processor time in units of kernel ticks. When a thread has consumed its alloted time slice, the kernel will
switch execution to any other threads that are of equal priority. The kernel will not return to run the same thread without
running each of the other equal priority threads.
Basic Usage
The code snippet below illustrates how to create a thread and have it execute a simple forever loop.
#include "Kernel/kernel_thread.h"
#include <assert.h>
static THREAD thread; /* Allocate a thread */
void APP_Example(void)
{
ALIGNED(8) static BYTE stackmem[384]; /* Allocate the thread's stack memory */
STATUS status;
status = THREAD_Create(&thread, /* Create the thread */
stackmem, /* Provide a pointer to the stack memory for the thread */
sizeof(stackmem), /* Indicate the size (in bytes) of the stack memory */
PRIO_NORMAL); /* Specify the priority for the thread */
assert(status == SUCCESS);
/* At this point, the thread has been created
and exists within the kernel, but it is not
alive and executing any code yet. */
status = THREAD_Start(&thread, /* Start execution from the thread */
APP_ThreadFunction, /* The function for the thread to execute */
NULL); /* An optional argument to pass into the function */
assert(status == SUCCESS);
}
void APP_ThreadFunction(void* arg)
{
for (;;) { /* A forever loop */
THREAD_Sleep(100);
}
}
Stopping a Thread
Depending upon the desired functionality of the thread, there are several methods for stopping a thread. For a thread that implements
a forever loop, one method uses cooperation from the thread to gracefully exit. A thread can be signaled to exit by using the THREAD_Abort()
call. If the thread happens to be blocked upon an object when aborted, the thread will be released with the ERR_ABORTED status code. All subsequent
attempts to block the aborted thread will also fail until the thread is restarted.
The code snippet below demonstrates a thread function that performs initialization before entering its forever loop. The thread then
supports exiting via the THREAD_Abort() method (by checking THREAD_IsAborted()) and can subsequently perform any clean-up to reverse what it
performed when it started.
/* A thread function */
static void APP_Thread(void* arg)
{
Initialize(); /* Example of some initialization */
while (!THREAD_IsAborted()) { /* Forever loop (until aborted) */
/* Thread-specific code here... */
}
/* Only here if THREAD_Abort() was called
for this thread */
CleanUp();
}
Use THREAD_Terminate() for a brute force method of stopping a thread. Terminating the thread will cause it to stop execution immediately
no matter where it is executing code; even if it happens to be blocked waiting upon another object. This can cause other objects that have
references (pointers) to the terminated thread to be in an invalid state.
If a thread desires to stop itself, it can simply exit its entry (start) function. When the thread breaks out from its function, the
kernel will be invoked and the thread will be automatically terminated. This feature can be especially helpful when creating
run-to-completion style threads. For example, once a thread has been created, it can be started and commanded to execute any function that has
the form of the THREADSTART function using THREAD_Start(). The function can do its defined task and can simply exit when it has completed. An application
can determine if the thread has completed by checking if the thread is alive using THREAD_IsAlive() or it can block and wait for the thread to
complete using THREAD_Join().
After a thread has stopped execution, it still exists within the kernel, only it is no longer considered to be alive. The thread can be
started again by calling THREAD_Start(). Use THREAD_Destroy() to completely remove and release a thread from the kernel.
API Reference
STATUS THREAD_Create(THREAD* thread, const CHAR* name, void* stk, UINT32 stksize, PRIORITY prio)
Creates a thread with the specified parameters.
PARAMETERS
thread | A pointer to a caller allocated thread to be created and initialized. |
name | A pointer to a NULL terminated string that represents the name for the thread. |
stk | A pointer to the start of the memory to be used for the thread stack. |
stksize | The size in bytes for the thread's stack memory. |
prio | A priority level for the thread. There are 15-available values and must be one of the following.
PRIO_HIGHER_7 | A priority 7 levels above normal. |
PRIO_HIGHER_6 | A priority 6 levels above normal. |
PRIO_HIGHER_5 | A priority 5 levels above normal. |
PRIO_HIGHER_4 | A priority 4 levels above normal. |
PRIO_HIGHER_3 | A priority 3 levels above normal. |
PRIO_HIGHER_2 | A priority 2 levels above normal. |
PRIO_HIGHER_1 | A priority 1 level above normal. |
PRIO_NORMAL | A normal priority level. |
PRIO_LOWER_1 | A priority 1 level below normal. |
PRIO_LOWER_2 | A priority 2 levels below normal. |
PRIO_LOWER_3 | A priority 3 levels below normal. |
PRIO_LOWER_4 | A priority 4 levels below normal. |
PRIO_LOWER_5 | A priority 5 levels below normal. |
PRIO_LOWER_6 | A priority 6 levels below normal. |
PRIO_LOWER_7 | A priority 7 levels below normal. |
|
SUCCESS | The thread has been created. |
ERR_NULLREFERENCE | The argument 'thread' or 'stk' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
STATUS THREAD_Start(THREAD* thread, THREADSTART func, void* arg)
Starts execution of a thread at the given entry function.
PARAMETERS
thread | A pointer to the thread to be started. |
func | An application-defined function that represents the starting (entry) point for the thread. |
arg | (optional) A caller argument to be passed to the given thread function. Can be NULL. |
SUCCESS | The thread has been started. |
ERR_NULLREFERENCE | The argument 'thread' or 'func' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_INVALIDOPERATION | The thread is already alive and executing a function. |
ERR_NOTINITIALIZED | The specified thread does not exist within the kernel. |
BOOLEAN THREAD_IsAlive(THREAD* thread)
Returns an indication of whether a thread is alive. A thread is considered to be alive if it has been started and it has not exited or
has been terminated.
PARAMETERS
thread | A pointer to the target thread to be checked for being alive. |
TRUE if the thread has been started and has not been stopped or terminated; otherwise FALSE.
STATUS THREAD_Abort(THREAD* thread)
Aborts a thread. Once a thread has been aborted, all blocking calls made by the thread will fail with the ERR_ABORTED status code
and any calls to THREAD_Aborted() will return as TRUE.
PARAMETERS
thread | A pointer to the thread to be aborted. |
SUCCESS | The thread has been aborted. |
ERR_NULLREFERENCE | The argument 'thread' was found to be NULL. |
ERR_NOTINITIALIZED | The specified thread does not exist within the kernel. |
BOOLEAN THREAD_Aborted(void)
Returns an indication of whether the calling thread has been aborted.
TRUE if the calling thread has been aborted and should exit; otherwise FALSE.
STATUS THREAD_Join(THREAD* thread, UINT32 timeout)
Blocks the calling thread until a thread terminates.
PARAMETERS
thread | A pointer to the thread to wait for termination. |
timeout | The maximum amount of time, in kernel ticks, to wait for the thread to terminate. Use 0 to return immediately
without blocking or use INFINITE to wait indefinitely. |
SUCCESS | The specified thread has terminated. |
ERR_NULLREFERENCE | The argument 'thread' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_NOTINITIALIZED | The specified thread does not exist within the kernel. |
ERR_TIMEOUT | The specified maximum amount of time has elapsed prior to the thread terminating. |
STATUS THREAD_Terminate(THREAD* thread)
Terminates execution of a thread immediately.
PARAMETERS
thread | A pointer to the thread to be terminated. |
SUCCESS | The thread has been terminated. |
ERR_NULLREFERENCE | The argument 'thread' was found to be NULL. |
ERR_NOTINITIALIZED | The specified thread does not exist within the kernel. |
STATUS THREAD_Destroy(THREAD* thread)
Destroys and removes a thread from the kernel. If the thread is alive, the thread will be terminated.
PARAMETERS
thread | A pointer to the thread to be destroyed and removed from the kernel. |
SUCCESS | The thread has been removed from the kernel. |
ERR_NULLREFERENCE | The argument 'thread' was found to be NULL. |
ERR_INVALIDCONTEXT | The operation is not supported from the context of an interrupt service routine (ISR). |
ERR_NOTINITIALIZED | The specified thread does not exist within the kernel. |