RTAI

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen

RTAI (Real Time Application Interface) ist eine Erweiterung von Linux zu einem Echtzeitbetriebssystem. Entworfen wurde RTAI von Paolo Mantegazza vom Dipartimento di Ingegneria Aerospaziale der Technischen Universität Mailand. RTAI wurde vom Beginn an als Open-Source-Projekt von einer größeren Entwicklergemeinde weiterentwickelt, wobei heute neben dem weiterhin koordinierend tätigen Mantegazza vor allem Philippe Gerum als sehr aktiver Mitarbeiter zu nennen ist.

Es gibt inzwischen auch eine Reihe diverser verwandter oder kooperierender Projekte, wie zum Beispiel RTnet (ein Echtzeit-Netzwerk-Protokoll) und Linux Trace Toolkit.

Ein großer Pluspunkt von RTAI ist, dass es mit der Variante LXRT möglich ist, Hard-Realtime-Tasks im Userspace laufen zu lassen und damit die Schutzmechanismen von Linux zu nutzen. Dies erfolgt ohne größere Einbußen im Bereich der Latenzzeiten und ohne großen Overhead. Bei anderen Echtzeit-Systemen, welche ausschließlich im Kernelspace laufen, kann sich ein Fehler im Programmablauf verheerend auswirken.

RTAI wird von einer großen Zahl von Entwicklern in vielen Ländern als Basis für ihre Entwicklungen im Realtime-Bereich verwendet, hat aber ebenso wie RTLinux naturgemäß für den Standard-Büro-Desktop-Computer-Anwender keine direkte Bedeutung.

Architektur[Bearbeiten | Quelltext bearbeiten]

Die Grundlage von RTAI-Linux ist ein normaler Linux-Kernel, der mit dem RTAI-Patch (Realtime Application Interface) erweitert wird. Wie in der Abbildung zu sehen ist, fügt der Patch einen Echtzeit-Kernel zwischen der Hardware (Prozessor) und dem Linux-Kernel ein. Dieser übernimmt die Interruptverwaltung des Prozessors. Somit kann Software auf der Kernel-Ebene keine Interrupts mehr blockieren oder freigeben. Die dafür verwendeten Befehle cli() und sti() ersetzt RTAI durch Makros und ist somit in der Lage den Kernel-Code zu unterbrechen.

RTAI-Architektur

Der Linux-Kernel selbst ist ebenfalls ein Echtzeit-Task. Er besitzt jedoch die kleinste Priorität (Idle-Task) und wird immer nur dann ausgeführt, wenn die Echtzeit-Tasks nichts zu tun haben. Nach dem Ausführen eines Echtzeit-Tasks werden alle Register wiederhergestellt, so dass der Kernel die Unterbrechung nicht bemerkt.

Realtime Hardware Abstraction Layer RTHAL[Bearbeiten | Quelltext bearbeiten]

Damit deterministische Interrupt-Latenzzeiten erzielt werden können, muss die Interruptverwaltung an RTAI übergeben werden. Die Umleitung der Interrupt-Kontrolle wird mit Hilfe des Realtime Hardware Abstraction Layers (RTHAL) realisiert. RTHAL wird mit dem RTAI-Patch in den Source-Code des Linux-Kernels integriert.

In der folgenden Abbildung sind die möglichen Kommunikationswege innerhalb eines modifizierten Kernels dargestellt. Im Fall A ist die Abstraktion transparent, das heißt die Interrupt-Kontrolle liegt nach wie vor beim Linux-Kernel, was der Nutzung eines Standard-Kernels entspricht. Bei B wird dem Linux-Kernel die direkte Kontrolle über die Interrupts entzogen und der Echtzeiterweiterung zugewiesen.

RTAI-Architektur

RTAI arbeitet autonom von Linux auf der Hardware. Abgefangene Interrupts werden auch an RTHAL weitergegeben, damit der Kernel darauf entsprechend reagieren kann. RTAI wird durch verschiedene Kernel-Module implementiert. Solange diese Module nicht geladen sind, behält der Linux-Kernel die Interrupt-Kontrolle (Fall A). Erst beim Laden der RTAI-Module wird die direkte Interrupt-Kontrolle an RTAI übertragen (Fall B). So kann die Echtzeiterweiterung während der Laufzeit nach Belieben in den Kernel eingefügt und wieder entfernt werden. Dank dieser modularen Struktur lassen sich Fehlerquellen leichter isolieren. Arbeitet zum Beispiel ein RTAI-System fehlerhaft, kann man einfach die RTAI-Module entfernen, um zu testen, ob der Fehler bei Linux oder RTAI liegt.

RTHAL besteht im Wesentlichen aus einer Struktur von Funktionspointern, welche beim Systemstart auf die Interrupt-Handling-Funktionen des Linux-Kernels zeigen. Beim Laden der RTAI-Module werden die Funktionspointer auf RTAI interne Funktionen umgelenkt. So übernimmt RTAI die Interrupt-Kontrolle, ohne dass der Linux-Kernel etwas davon bemerkt. Nach dem Entfernen der RTAI-Module zeigen die Pointer der Struktur rthal wieder auf die Standard-Kernel-Funktionen.

Interrupt-Handling[Bearbeiten | Quelltext bearbeiten]

Wenn RTAI die Interrupt-Kontrolle übernimmt, werden interruptspezifische Funktionsaufrufe des Linux-Kernels mit Hilfe von RTHAL an RTAI interne Funktionen umgeleitet. So implementiert RTAI zum Beispiel einen Ersatz für das Funktionspaar sti() und cli(). Diese RTAI-Funktionen setzen Flags in RTAI internen Datenstrukturen, um festzuhalten, ob Linux über eingehende Interrupts informiert werden möchte (sti) oder nicht (cli). So wird sichergestellt, dass der Kernel keine Interrupts mit Hilfe der Funktion cli() deaktivieren kann. RTAI gibt die mit der Funktion sti() angeforderten Interrupts nach dem Ausführen der Echtzeit-Interrupt-Handler an den Linux-Kernel weiter.

In der folgenden Abbildung wird mit Hilfe eines Flussdiagramms dargestellt, wie ein eingehender Interrupt von RTAI verarbeitet wird. Zuerst prüft der RTAI Dispatcher, ob eine Echtzeit-Applikation einen Handler für diesen Interrupt registriert hat. Falls entsprechende Interrupt-Handler vorhanden sind, werden diese ausgeführt.

Interrupt-Handling

Danach prüft RTAI anhand der internen Datenstrukturen, ob der Linux-Kernel den Interrupt ebenfalls mit sti() aktiviert hat. Bei einem positiven Prüfergebnis wird der Linux Dispatcher gestartet und somit die Verarbeitung des Interrupts auf der Kernel-Ebene eingeleitet. Falls der Linux-Kernel den betreffenden Interrupt nicht aktiviert hat, verlässt RTAI sofort den Interrupt-Kontext und führt das unterbrochene Programm wieder aus.

Scheduler[Bearbeiten | Quelltext bearbeiten]

RTAI unterstützt drei verschiedene Scheduling-Varianten. Diese sind entweder für den Einsatz auf Uni- oder auf Multiprozessor-Systemen spezialisiert. Alle Scheduler können sowohl im sogenannten Oneshot- oder Periodic-Mode betrieben werden. Die verschiedenen Scheduler werden in den Modulen rtai_sched_up.ko, rtai_sched_smp.ko und rtai_sched_mup.ko implementiert. Das entsprechende Scheduler-Modul wird jeweils nach dem RTAI-Modul rtai_hal.ko mit insmod in den Kernel eingefügt.

Uni-Prozessor-Scheduler (UP)[Bearbeiten | Quelltext bearbeiten]

Dieser Scheduler ist für Plattformen mit einem Prozessor vorgesehen, welche den 8254 als Timer benutzen. Der Aufbau des Schedulers ist recht einfach. Er besteht im Wesentlichen aus mehreren Listen mit verschiedenen Prioritäten, welche er linear abarbeitet. Dabei erhält jeweils der Task mit der höchsten Priorität Zugriff auf die CPU. Der Linux-Kernel selbst ist ebenfalls ein Echtzeit-Task, allerdings mit der geringsten Priorität.

SMP-Scheduler (SMP)[Bearbeiten | Quelltext bearbeiten]

Der SMP-Scheduler (Symmetric Multiprocessing) ist für Multiprozessor-Systeme gedacht, die entweder 8254- oder APIC-basiert sind. Der APIC ist der sogenannte Advanced Programmable Interrupt Controller in Multiprozessor-Systemen. Dieser hat unter anderem die Aufgabe, die auftretenden Interrupts den einzelnen CPUs zuzuteilen. Tasks können an eine CPU gebunden werden oder symmetrisch auf einem Cluster von CPUs laufen. Der Scheduler kann auch auf Systemen eingesetzt werden, die nur einen Prozessor haben, aber deren Kernel mit SMP-Option kompiliert wurde.

Multi-Uni-Prozessor-Scheduler (MUP)[Bearbeiten | Quelltext bearbeiten]

Wie es der Name schon sagt, sieht dieser Scheduler ein Multiprozessor-System als eine Ansammlung von mehreren Einzelprozessoren. Dies hat den Vorteil, dass im Gegensatz zum SMP-Scheduler jeder Prozessor seine Timer unabhängig von den anderen programmieren kann. Also können die Timer-Modi Periodic- und Oneshot-Mode abhängig von der CPU verschieden sein.

Timer[Bearbeiten | Quelltext bearbeiten]

Die Ausführung von Echtzeit-Tasks in RTAI ist timergesteuert. RTAI bietet die Wahl zwischen den beiden Timer-Modi Periodic- und Oneshot-Mode. Periodisch bedeutet, dass der Timer in regelmäßigen Intervallen ein Interrupt auslöst, der ein Rescheduling veranlasst. Im Gegensatz dazu steht das Oneshot-Verfahren. Hierbei wird der Timer so programmiert, dass er nach einer festgelegten Zeitspanne genau einen Interrupt auslöst, der den Scheduler aufruft. Für die Generierung eines weiteren Interrupts muss der Timer neu programmiert werden, was einen größeren Aufwand bedeutet, als beim periodischen Verfahren. Jedoch sind so auch unterschiedlich lange Intervalle möglich, nach denen ein Rescheduling erfolgen kann.

Bei der Initialisierung des Programms muss ein Modus gewählt werden. Dies geschieht, indem eine der beiden folgenden Funktionen aufruft:

  • rt_set_periodic_mode() Timer läuft im Periodic-Mode.
  • rt_set_oneshot_mode() Timer läuft im Oneshot-Mode.

Intertask-Kommunikation[Bearbeiten | Quelltext bearbeiten]

Für die Kommunikation und Synchronisation zwischen Echtzeit-Tasks im Kernel-Space stellt RTAI die für ein Echtzeitbetriebssystem üblichen Mechanismen zur Verfügung. Diese werden in den Kernel-Modulen der Scheduler implementiert:

  • Mailboxen
  • Semaphore
  • Nachrichten und Remote-Procedure-Calls

Mailboxen[Bearbeiten | Quelltext bearbeiten]

Mit Hilfe von Mailboxen ist eine asynchrone Inter-Prozess-Kommunikation möglich. Ein Task kann Nachrichten asynchron an die Mailbox eines anderen Tasks senden. Wenn der Empfänger bereit ist die empfangenen Nachrichten zu bearbeiten kann er sie aus der Mailbox holen. In diesem Fall arbeitet die Mailbox wie eine FIFO (first in first out), deren Funktionalität vollständig vom jeweiligen Task entkoppelt ist und keine Synchronisationsmechanismen benötigt.

Hier die wichtigsten RTAI-Funktionen zum Arbeiten mit Mailboxen:

  • rt_mbx_init() Initialisiert eine Mailbox mit einer definierten Größe.
  • rt_mbx_delete() Löscht die von einer Mailbox genutzten Ressourcen.
  • rt_mbx_send() Sendet eine Nachricht mit definierter Größe an die Mailbox.
  • rt_mbx_receive() Empfängt eine Nachricht mit definierter Größe von einer Mailbox.

Semaphore[Bearbeiten | Quelltext bearbeiten]

Ein Semaphor ist eine Art Schlüssel, den ein Task zum Beispiel benötigt, um auf eine gemeinsame Ressource zuzugreifen. Wurde der Semaphor bereits von einem anderen Task geholt, wird der anfragende Task in den Wartezustand gesetzt, bis der aktuelle Besitzer den Semaphor wieder zurückgibt. Ein Semaphor beinhaltet eine geschützte Variable (binär oder counting), welche die noch freien Zugriffe auf eine Ressource angibt. In einer Queue werden die Tasks vermerkt, die auf den Semaphor warten. Wird der Semaphor zurückgegeben erhält ihn der erste Task in der Queue.

Folgende Funktionen stehen zum Arbeiten mit Semaphoren in RTAI zur Verfügung:

  • rt_sem_init() Initialisiert einen Semaphor mit gegebenem Wert.
  • rt_sem_delete() Löscht den gegebenen Semaphor.
  • rt_sem_signal() Gibt den Semaphor zurück.
  • rt_sem_wait() Wartet auf einen Semaphor.

Kommunikation mit Linux-Prozessen[Bearbeiten | Quelltext bearbeiten]

RTAI stellt mit FIFOs und Shared Memory auch zwei Mechanismen zur Verfügung, die es den Echtzeit-Tasks ermöglicht mit normalen Linux-Prozessen im User-Space zu kommunizieren.

FIFOs[Bearbeiten | Quelltext bearbeiten]

Ein FIFO ist ein Puffer-Speicher, über den Daten zwischen einem RTAI-Task und einem normalen Linux-Prozess im User-Space ausgetauscht werden können. Theoretisch ist ein FIFO bidirektional. In der Praxis wird jedoch meistens nur eine Richtung benutzt. Zum gegenseitigen Austausch von Daten verwendet man zwei FIFOs, einen zum Senden von Befehlen und einen weiteren zum Empfangen der entsprechenden Antworten.

RTAI FIFO

Linux-Prozesse können auf einen FIFO wie auf eine normale Datei zugreifen. Anstelle einer Datei öffnet man mit der Funktion open() einen speziellen Device-Node im /dev-Verzeichnis (rtf0 bis rtf63). Anschließend kann man mit den Funktionen read() und write() Daten lesen und schreiben. Im Kernel-Space stellt die RTAI-API folgende Funktionen zum Arbeiten mit FIFOs für die Echtzeit-Tasks zur Verfügung:

  • rtf_create() Erzeugt einen FIFO mit gegebener Größe und Nummer.
  • rtf_destroy() Löscht einen FIFO.
  • rtf_reset() Löscht den Inhalt eines FIFO.
  • rtf_put() Schreibt Daten in den FIFO.
  • rtf_get() Liest Daten aus dem FIFO.
  • rtf_create_handler() Registriert einen Handler, der beim Eintreffen von Daten ausgeführt wird.

Shared Memory[Bearbeiten | Quelltext bearbeiten]

Shared Memory ist wie es der Name schon sagt, ein Speicherbereich, den sich Linux-Prozess und RTAI-Task teilen. Shared Memory wird hauptsächlich dann eingesetzt, wenn mehrere Linux-Prozesse Zugriff auf die Daten eines RTAI-Task benötigen oder eine große Datenmenge in kurzer Zeit von einem RTAI-Task an einen Linux-Prozess übertragen werden müssen.

LXRT[Bearbeiten | Quelltext bearbeiten]

Um die Entwicklung von Echtzeit-Tasks zu erleichtern, wurde in RTAI das LXRT-Modul eingeführt. Dieses Modul erlaubt die Entwicklung von Echtzeit-Tasks im User-Space, mit der Möglichkeit, auf die API von RTAI zuzugreifen. Dies ist eine Besonderheit, die nur in RTAI existiert und die Entwicklung sehr vereinfachen kann, da sich Fehler in einem User-Space Prozess in der Regel nicht auf die Stabilität des Gesamtsystems auswirken. Fehler in Kernel-Modulen können oft zum Absturz des gesamten Systems führen. Zudem kann man im User-Space im Gegensatz zum Kernel-Space mit einem normalen Debugger (zum Beispiel GDB) arbeiten.

RTAI-Lab[Bearbeiten | Quelltext bearbeiten]

Das RTAI-Lab Projekt erweitert Simulink und Scicos um einen Blocksatz, mit dessen Hilfe sich Echtzeitanwendungen für RTAI grafisch zusammenklicken lassen. Er enthält Blöcke zur Behandlung der oben beschriebenen Techniken wie Intertask-Kommunikation, oder Kommunikation mit Linux-Prozessen. Außerdem werden analoge und digitale IO-Blöcke bereitgestellt, mit deren Hilfe die Echtzeitanwendung mit der Außenwelt interagieren kann. Dazu greift RTAI-Lab auf die Treiber des Comedi Projekts zurück, unterstützt werden also alle IO-Karten, die von Comedi unterstützt werden. Aus dem so zusammengestellten Model wird automatisch C-Code generiert, der direkt kompiliert und als Echtzeittask gestartet werden kann. Zur Benutzerinteraktion mit diesem Task wird eine grafische Benutzeroberfläche mitgeliefert, über die sich Variablen plotten, aber auch verändern lassen.

Andere Lösungsansätze für echtzeitfähiges Linux[Bearbeiten | Quelltext bearbeiten]

Literatur[Bearbeiten | Quelltext bearbeiten]

  • Yaghmour, Karim: The Real-Time Application Interface, 2001 (PDF)
  • Blattner, Jörg: Hart im nehmen? Linux in Echtzeit, Hochschule Zürich Winterthur 2005 (PDF (Memento vom 29. September 2007 im Internet Archive))
  • Abbott, Doug: Linux for Embedded and Real-time Applications, Burlington (USA) 2003, Elsevier Science, ISBN 0-7506-7546-2
  • Düding, Dirk: Ein Beitrag zum Einsatz von echtzeitfähigen Linux-Varianten in der Automatisierungstechnik, Dissertation, Dortmund 2003, Universität Dortmund
  • Keller, Matthias: Untersuchung von Ansätzen zur CAN-Kommunikation in Echtzeit unter Linux, Bachelor-Thesis, TU München, 2006 (PDF)
  • Bucher, Mannori, Netter: RTAI-Lab tutorial: Scilab, Comedi, and real-time control, 2008 (PDF)

Weblinks[Bearbeiten | Quelltext bearbeiten]