Schedulers – Comtrol eCos User Manual
Page 28

Kernel Overview
loosely defined because of the many configuration options. For example
cyg_mutex_lock
will always attempt to
lock a mutex, but various configuration options determine the behaviour when the mutex is already locked and
there is a possibility of priority inversion.
The optional nature of the kernel package presents some complications for other code, especially device drivers.
Wherever possible a device driver should work whether or not the kernel is present. However there are some
parts of the system, especially those related to interrupt handling, which should be implemented differently
in multi-threaded environments containing the eCos kernel and in single-threaded environments without the
kernel. To cope with both scenarios the common HAL package provides a driver API, with functions such as
cyg_drv_interrupt_attach
. When the kernel package is present these driver API functions map directly on to
the equivalent kernel functions such as
cyg_interrupt_attach
, using macros to avoid any overheads. When the
kernel is absent the common HAL package implements the driver API directly, but this implementation is simpler
than the one in the kernel because it can assume a single-threaded environment.
Schedulers
When a system involves multiple threads, a scheduler is needed to determine which thread should currently be
running. The eCos kernel can be configured with one of two schedulers, the bitmap scheduler and the multi-level
queue (MLQ) scheduler. The bitmap scheduler is somewhat more efficient, but has a number of limitations. Most
systems will instead use the MLQ scheduler. Other schedulers may be added in the future, either as extensions to
the kernel package or in separate packages.
Both the bitmap and the MLQ scheduler use a simple numerical priority to determine which thread should be
running. The number of priority levels is configurable via the option
CYGNUM_KERNEL_SCHED_PRIORITIES
, but
a typical system will have up to 32 priority levels. Therefore thread priorities will be in the range 0 to 31, with 0
being the highest priority and 31 the lowest. Usually only the system’s idle thread will run at the lowest priority.
Thread priorities are absolute, so the kernel will only run a lower-priority thread if all higher-priority threads are
currently blocked.
The bitmap scheduler only allows one thread per priority level, so if the system is configured with 32 priority levels
then it is limited to only 32 threads — still enough for many applications. A simple bitmap can be used to keep
track of which threads are currently runnable. Bitmaps can also be used to keep track of threads waiting on a mutex
or other synchronization primitive. Identifying the highest-priority runnable or waiting thread involves a simple
operation on the bitmap, and an array index operation can then be used to get hold of the thread data structure
itself. This makes the bitmap scheduler fast and totally deterministic.
The MLQ scheduler allows multiple threads to run at the same priority. This means that there is no limit on the
number of threads in the system, other than the amount of memory available. However operations such as finding
the highest priority runnable thread are a little bit more expensive than for the bitmap scheduler.
Optionally the MLQ scheduler supports timeslicing, where the scheduler automatically switches from one runnable
thread to another when some number of clock ticks have occurred. Timeslicing only comes into play when there
are two runnable threads at the same priority and no higher priority runnable threads. If timeslicing is disabled
then a thread will not be preempted by another thread of the same priority, and will continue running until either it
explicitly yields the processor or until it blocks by, for example, waiting on a synchronization primitive. The con-
figuration options
CYGSEM_KERNEL_SCHED_TIMESLICE
and
CYGNUM_KERNEL_SCHED_TIMESLICE_TICKS
control
timeslicing. The bitmap scheduler does not provide timeslicing support. It only allows one thread per priority level,
so it is not possible to preempt the current thread in favour of another one with the same priority.
Another
important
configuration
option
that
affects
the
MLQ
scheduler
is
CY-
GIMP_KERNEL_SCHED_SORTED_QUEUES
. This determines what happens when a thread blocks, for example by
28