The CrossWorks Tasking Library provides a multi-priority, pre-emptive, task switching and synchronisation facility. Additionally (and optionally) the library also provides timer and interrupt handling support.
You will typically use a task when you have some algorithmic or protocol processing that must work (suspend it's execution) whilst other activities occur. For example you may have a protocol processing task and a user interface task.
A task is a CPU execution context which is typically a subset of the CPU register state. When a task switch occurs the CPU execution context is saved on to the stack of the current task, a new task is selected to run and its saved CPU execution context is restored. The process of selecting a new task to run is called scheduling.
Note that the stack requirements of a task is the size of the CPU execution context plus the maximum stack depth the task can execute. The CPU execution context to be saved could be quite large (16-32 words depending upon the CPU) - so you may find this library unsuitable on systems that have limited RAM availability.
Task switching can be co-operative or pre-emptive. Co-operative task switching occurs when tasks call functions of the library that cause scheduling. Pre-emptive task switching occurs as a result of an interrupt service routine (ISR) execution that calls the appropriate library function. Note that interrupt service routines are not tasks and cannot be context switched.
A task has a priority associated with it, the lowest priority is 0 the highest is 255. A task is either executing (the current task) or it is queued in a task list. The task list is kept in priority order - highest priority first. The current task will always have a priority that is greater than or equal to the first runnable task in the task list.
In general a task switch occurs when a task that is in the task list becomes runnable and has a priority that is higher than the current task. However when a co-operative task switch occurs and the next task ready to run is of the same priority as the current task then a task switch will occur. This is sometimes referred to as round robin scheduling.
There is one executing task and there must always be a task ready to execute i.e. the task list must have a runnable task queued on it. Typically there will always be an idle task that loops and perhaps puts the CPU into a power save mode.
A task on the task list is either runnable, finished, waiting on an event set and/or waiting for a timer.
When a task switch occurs interrupts will be enabled. So you can safely call the library functions with interrupts disabled.
Tasks synchronise with other tasks (or ISR's) and serialise resource usage using an event set. An event set is a word sized variable upon which tasks can wait for specific bits (events) to be set to 1. You can wait for any specified events in an event set or for all of the specified events. You can also specify that the events the task are waiting on are automatically cleared (set to 0) when the task has completed it's wait.
Use of event sets can provide a facility comparable to a priority ordered binary semaphore. If all the tasks that use an event set are of the same priority then the facility is comparable to a binary semaphore. Currently there is no facility provided that supplies a full semaphore capability.
If your application can provide a periodic timer interrupt (for example one to keep a watch dog alive) then you can use the timer wait facility of the library. This is a simple software counter that is incremented by your timer interrupt. You can use this to specify a wakeup time and to prevent systems waiting forever on an event set.
Some systems have programmable interrupt controllers. On such systems the CrossWorks tasking library provides functions that enable you to write ISR's as C functions and associate the required hardware priority to their execution. On systems that have fixed ISR schemes examples and documentation are provided that enable you to create ISR's that co-operate with the CrossWorks tasking library.