In order to build a generic and versatile framework for emulating traditional RTOS, we chose to concentrate on a set of common behaviours they all exhibit. A limited set of specific RTOS features which are not so common, but would be more efficiently implemented into the nucleus than into the emulators, has also been retained. The basic behaviours selected cover four distinct fields:
Multi-threading provides the fundamental mechanism for an application to control and react to multiple, discrete external events. The nucleus provides the basic multi-threading environment.
Thread states. The nucleus has to maintain the current state of each thread in the system. A state transition from one state to another may occur as the result of specific nucleus services called by the RTOS emulator. The fundamental thread states defined by the nucleus are:
DORMANT and SUSPENDED states are cumulative, meaning that the newly created thread will still remain in a suspended state after being resumed from the DORMANT state.
PENDING and SUSPENDED states are cumulative too, meaning that a thread can be forcibly suspended by another thread or service routine while pending on a synchronization resource (e.g. semaphore, message queue). In such a case, the resource is dispatched to it, but it remains suspended until explicitely resumed by the proper nucleus service.
PENDING and DELAYED states may be combined to express a timed wait on a resource. In such a case, the time the thread can be blocked is bound to a limit enforced by a watchdog.
Scheduling policies. By default, threads are scheduled according to a fixed priority value, using a preemptive algorithm. There is also a support for round-robin scheduling among a group of threads having the same priority, allowing them to run during a given time slice, in rotation. Moreover, each thread undergoing the round-robin scheduling is given an individual time quantum.
Priority management. It is possible to use whether an increasing or decreasing thread priority ordering, depending on an initial configuration. In other words, numerically highest priority values could whether represent highest or lowest scheduling priorities depending on the configuration choosen. This feature is motivated by the existence of this two possible ordering among traditional RTOS. For instance, VxWorks, VRTX, ThreadX and Chorus O/S use a reversed priority management scheme, where the highest the value, the lowest the priority. pSOS+ instead uses the opposite ordering, in which the highest the value, the highest the priority.
Running thread. At any given time, the highest priority thread which has been ready to run for the longuest time among the currently runnable threads (i.e. not currently blocked by any delay or resource wait) is elected to run by the scheduler.
Preemption. When preempted by a more prioritary thread, the running thread is put at front of the ready thread queue waiting for the processor resource, provided it has not been suspended or blocked in any way. Thus it is expected to regain the processor resource as soon as no other prioritary activity (i.e. a thread having a higher priority level, or an interrupt service routine) is eligible for running.
Manual round-robin. As a side-effect of attempting to resume an already runnable thread or the running thread itself, this thread is moved at the end of its priority group in the ready thread queue. This operation is functionally equivalent to a manual round-robin scheduling.
Even if they are not as widespread as those above in traditional RTOS, the following features are also retained for the sake of efficiency in the implementation of some emulators:
Priority inversion. In order to provide support for preventing priority inversion when using inter-thread synchronization services, the priority inheritance protocol is supported.
Signaling. A support for sending signals to threads and running asynchronous service routines to process them is available. The asynchronous service routine is run on behalf of the signaled thread context the next time it returns from the nucleus level of execution, as soon as one or more signals are pending.
Disjunctive wait. A thread is able to wait in a disjunctive manner on multiple resources. The nucleus unblocks the thread when at least one among the pended resources is available.
Traditional RTOS provide a large spectrum of inter-thread communication facilities involving thread synchronization, such as semaphores, message queues, event flags or mailboxes. Looking at them closely, we can define the characteristics of a basic mechanism which will be usable in turn to build these facilities.
Pending mode. The thread synchronization facility provides a mean for threads to pend either by priority or FIFO ordering. Multiple threads should be able to pend on a single resource.
Priority inheritance protocol. In order to prevent priority inversion problems, the thread synchronization facility implements a priority inheritance protocol in conjunction with the thread scheduler. The implementation allows for supporting the priority ceiling protocol as a derivative of the priority inheritance protocol.
Time-bounded wait. The thread synchronization facility provides a mean to limit the time a thread waits for a given resource using a watchdog.
Forcible deletion. It is legal to destroy a resource while threads are pending on it. This action resumes all waiters atomically.
Since the handling of interrupts is one of the least well defined areas in RTOS design, the nucleus focuses on providing a simple mechanism with sufficient hooks for specific implementations to be built onto according to the emulated RTOS flavour.
Nesting. Interrupt management code is reentrant in order to support interrupt nesting safely.
Atomicity. Interrupts are associated with dedicated service routines called ISRs. In order for these routines not to be preempted by thread execution, the rescheduling procedure is locked until the outer ISR has exited (i.e. in case of nested interrupts).
Priority. ISRs is always considered as prioritary over thread execution. Interrupt prioritization is left to the underlying hardware.
Traditional RTOS usually represent time in units of ticks. These are clock-specific time units and are usually the period of the hardware timer interrupt, or a multiple thereof. Since it needs to support both periodic and aperiodic time sources, the nucleus transparently switches from periodic jiffies to time-stamp counter values depending on the current timer operating mode.
Software timer support. A watchdog facility is provided to manage time-bound operations by the nucleus.
Absolute and relative clock. The nucleus keeps a global clock value which can be set by the RTOS emulator as being the system-defined epoch.
Some RTOS like pSOS+ also provide support for date-based timing, but conversion of ticks into conventional time and date units is an uncommon need that should be taken in charge by the RTOS emulator itself.
After having selected the basic behaviours shared by traditional RTOS, we have implemented them in a nucleus exporting a few service classes. These generic services will then serve as a founding layer for developing each emulated RTOS API, according to their own flavour and semantics.
In order for this layer to be architecture neutral, the needed support for hardware control and real-time capabilities will be obtained from an underlying host software architecture, through a rather simple standardized interface. Thus, porting the nucleus to a new real-time architecture will solely consist in implementing this low-level interface for the target platform.
The host software architecture is expected to provide the primary real-time capabilities to the RTOS abstraction layer. Basically, the host real-time layer must handle at least the following tasks:
Start/stop dispatching on request the external interrupts to a specialized handler ;
Provide a mean to mask and unmask interrupts ;
Provide a mean to create new threads of control in their simplest form ;
Provide support for periodic and aperiodic interrupt sources used in timer management ;
Provide support for allocating chunks of non-pageable memory.
Xenomai aims at helping application designers relying on traditional RTOS to move as smoothly as possible to a GNU/Linux-based execution environment, without having to rewrite their applications entirely. Aside of the advantages of using GNU/Linux as an embedded system, the benefits expected from the described approach is mainly a reduced complexity in designing new RTOS emulations. The architecture-neutral abstraction layer provides the foundation for developing accurate emulations of traditional RTOS API, saving the burden of implementing each time their fundamental real-time behaviours. Since the abstraction layer also favours code sharing and mutualization, we can expect the RTOS emulations to take advantage of them in terms of code stability and reliability.
© 2004 RTAI Project