Overview of ECROS Tasks

An ECROS client application consists of start-up initialization and some number of tasks.  After start-up initialization is complete, all the work of the application is done by tasks.  Tasks have "events" (see Overview of Events) which are set to make the task "ready".  Tasks also have a "task function" which is bound to it during initialization.  When a task becomes ready, ECROS places it in a queue behind other tasks that are ready.  When it reaches the head of the queue, ECROS runs the task by calling its task function.  A task's event pattern is passed to the task function as an argument, although there are other ways for a task to inspect its event pattern.  Generally, a task accepts events so that they are clear when it terminates, but this is not required.

ECROS provides API functions to:

Dividing a real-time system into tasks is normally the first step in design decomposition.  As compared to creating a real-time application without an operating system, ECROS immediately lends structure to the design and speeds up development.

Task Priority and Scheduling

A client application assigns a priority to each task.  ECROS provides four priorities, high, medium, low and idle, although most applications will use only the first three priorities.  Tasks should be assigned a priority by the client application.  There are no restrictions on priority assignment.  More than one task can be assigned the same priority, all tasks can have the same priority, etc.

ECROS always runs ready tasks of high priority before tasks of a lower priority.  When more than one task of the same priority is ready, they are run in the order in which they became ready (first-come-first-served).  If high priority tasks are always ready, lower priority tasks are "starved" and will not run.

The "Idle" Task

ECROS itself creates a task called the "idle" task at the idle priority.  This absorbs any CPU cycles not used by the client application tasks and performs some non-essential housekeeping.  It is not required that the idle task run, therefore the client application can safely lock it out with higher priority tasks.  Any client task at the idle priority will be queued in the normal first-come-first-served manner with the idle task.  Because the idle task is always ready, such tasks will run at best no more often than the idle task.

Collaborative Multi-tasking

Because ECROS has a collaborative scheduler, tasks are never preempted by another task.  In other words, a task retains control of the CPU until it is finished, except for interrupts.  Task functions must return after some unit of work has been accomplished so that ECROS can operate correctly.  How long a task function should run depends on the application.  The length of time the longest task function takes to complete limits the speed with which all other tasks can respond to events, independent of the relative priority of the tasks.  This is different from a preemptive scheduler, which will suspend a low priority task so that a high priority task can run almost immediately it becomes ready.  However, the lack of pre-emption makes the tasks themselves much easier to create and avoids issues of synchronization between tasks that access the same data structures or other system resources.

Communication Between Tasks

Tasks can communicate with each other using events, ECROS messages or application-defined ad hoc methods.  To make a task ready, an event must be sent directly or indirectly via a timer or message.  Ad hoc methods are therefore best for carrying the content of inter-task communication and the ECROS event mechanism should be use to alert the task to the fact that communication is taking place.  Events, being boolean, can tell a task that something needs to be done but cannot carry data.  Messages have enough bits to pass the address of a data structure and therefore can carry an arbitrary amount of data.  If they are passed through an appropriately configured message queue, they can send events to the task receiving of the data (see Overview of Messages).

Because tasks do not preempt each other, the design of data structures shared between tasks is greatly simplified.  For example, a linked list can be used and any number of tasks can add and remove items from the list without danger of the links becoming corrupted.  It is not neccessary to bracket linked list manipulation with instructions to the scheduler to inhibit preemption as would be the case with a preemptive operating system.  Note that data structures shared with interrupt service routines do require normal attention to synchronization.  If potential exists for corruption, interrupts must be turned off while the task accesses the data structure.

Advanced

The task function that is bound to a task can be changed at any time and need not remain fixed after initialization.  A task can also be unbound from all task functions if it is known that it will not become ready again.  For more information, see API function OsTaskBindFunction().


Last edited December 11, 2002.  All material Copyright © 2002 Graham Davies, ECROS Technology.