Echtzeit Betriebssysteme
-
VxWorks






Kleines Seminar im WS 2003/2004 eingereicht durch
Sven Schomaker
Gießen, 1. Februar 2004

1. Abstract

Die vorliegende Arbeit stellt Problematiken und allgemeine Lösungsansätze von Echtzeitbetriebssystemen vor und geht exemplarisch auf das weit verbreitete Echtzeitbetriebssystem VxWorks des kalifornischen Unternehmens WindRiver ein. Im ersten Teil der Arbeit wird eine Definition des Echtzeitbegriffs vorgenommen und eine allgemeine Einführung in den Bereich der Echtzeitverarbeitung gegeben. Daraufhin wird eine genauere Betrachtung der für die Echtzeitverarbeitung wesentlichen Problematiken sowie Verfahren zu deren Lösung vorgenommen. Der zweite Teil der Arbeit befasst sich im Wesentlichen mit einer Betrachtung des Echtzeitbetriebssystems VxWorks und veranschaulicht exemplarisch einige der im ersten Abschnitt vorgestellten Lösungsansätze. Die vorliegende Arbeit beabsichtigt einen allgemeinen Überblick über die Problematiken von Echtzeitbetriebssystemen zu geben und wird daher keine detailierte Einführung in spezielle programmiertechnische Details im Umgang mit VxWorks geben. Zu diesem Zweck sei auf die sehr detailierten und umfangreichen Programmier-Referenzen und Anleitungen von WindRiver verwiesen [10], [9], [11].

The present work discusses several problem areas of realtime operating systems (RTOS) and introduces some proven solutions on that particular problems areas. Afterwards it gives an introduction to the popular RTOS VxWorks developed and maintained by the californian WindRiver corporation. The first part gives an general introduction to the term of realtime and furthermore will discuss the previously mentioned problem areas one inescapable encounters when regarding RTOS. After conveying the reader to the common realtime issues, the second part of this work will point out, how those problems might be soluted in an realworld RTOS on the basis of VxWorks. Since this work is meant to introduce common concepts of realtime operating systems and not to give an detailed programming reference on VxWorks, there wont be any detailed descriptions of actual system calls or similar to describe programmers issues when dealing with VxWorks. For this purpose the author refers to the pretty detailed and comprehensive programmers manuals provided by WindRiver [10], [9], [11].

2. Einführung

Echtzeitsysteme spielen in der Industrie und Forschung eine große Rolle und werden in unserer heutigen technisierten Gesellschaft in einer großen Anzahl von Anwendungen zum Einsatz gebracht. Als ältestes Einsatzgebiet für Echtzeitsysteme kann zweifellos der Einsatz in der Industrie zur Prozesssteuerung angesehen werden. Die ersten Prozessrechner wurden etwa um 1959 entwickelt und damals wie heute zur Steuerung von Fertigungsprozessen in der Industrie verwendet. Sicherlich sind diese Systeme kaum noch mit den heutigen hoch integrierten Mikrocontrollern vergleichbar, doch wurde man bereits damals darauf aufmerksam, das die Steuerung von zeitkritischen Abläufen entsprechende zeitliche Determinismen in den Steuerungsprozessen benötigen. Seit der Entwicklung der ersten Prozessrechner hat sich das Einsatzgebiet für Echtzeitsysteme stark erweitert, da sich die technischen Fähigkeiten der modernen Industriegesellschaft bis heute stark weiter entwickelt haben. So wurde mit fast jedem der neu für die Technik eröffneten Gebieten, die Anforderung an einen zeitlichen Determinismus der mit dieser neuen Techniken einhergehenden automatisierten Datenverarbeitung neu erkannt. Heutzutage erstreckt sich das Einsatzgebiet von Echtzeitsystemen von der Prozessrechentechnik über die Avionik, Fahrzeug- und Weltraumtechnik, bis hinein in das heimische Wohnzimmer, wo in Multimedialen Systemen ebenfalls zeitkritische Systeme anwendung finden.

Die Gestalt der Komponenten eines Echtzeitsystems variert je nach Anwendungsgebiet beträchtlich. In vielen Bereichen wie z.B. der Automobilindustrie werden Hard- und Softwarekomponenten verwendet, die direkt auf die jeweilige Anwendung zugeschnitten sind. Hierbei war (und ist) es nicht selten der Fall, das die spezialisierte Software direkt auf der Hardware operiert, ohne dazu Dienste einer abstrahierenden Softwareschicht in Anspruch zu nehmen wie Sie ein Betriebssystem bereitstellt. In den Vergangenen Jahren wurden jedoch vermehrt Anstrengungen unternommen auch im Bereich der Embedded-Systems Betriebssysteme bereitzustellen, die die immer komplexere Hardware abstrahieren und die Steuerung von Hardware und Resourcenverwaltung unter Beachtung des erforderlichen zeitlichen Determinismus übernehmen. Ein solches Betriebssystem, dass die von ihm bereitgestellten Dienste innerhalb fest definierter zeitlicher Schranken bereitstellt, nennt man Echtzeitbetriebssystem. Die Beispiele für Echtzeitbetriebssystem sind vielfältig und deren Anzahl doch auch sehr beachtlich, als da wären pSOS, YARTOS, ARTS, LynxOS, RealtimeLinux, QNX, VxWorks und noch viele weitere.

Natürlich werden Echtzeitsysteme auch auf Basis konventioneller Hardware aufgebaut. In einigen Anwendungen, wie z.B. der Prozesssteuerung ist es Hilfreich auf Low-Cost Hardware aufbauend echtzeitfähige Systeme zu erzeugen. Für die Echtzeitfähigkeit eines Systems ist mitnichten spezielle Hardware von Nöten. Eine Anzahl an Echtzeitbetriebssystemen, die für die konventionelle x86 Hardware entwickelt werden, hauchen eben diesen Systemen Echtzeitfähigkeiten ein, auch wenn hierzu einige Dinge spezieller Betrachtung bedürfen.

3. Echtzeit

Im allgemeinen Sprachverständnis wird der Begriff der Echtzeit häufig mit Kenngrößen des menschlichen Erfahrungsbereiches beschrieben. So tritt häufig eine zeitliches Gefühl von Verarbeitungsgeschwindigkeit, die sich in einem durch den menschenlichen Erfahrungsbereich begrenzten Rahmen befindet, an die Stelle der eigentlichen Definition von Echtzeit und der damit verbundenen Begriffe. So ist Beispielsweise die Verarbeitung von 25 Frames pro Sekunde zur Erzeugung eines flüssigen visuellen Sinneseindrucks für den Menschen bei der Wiedergabe von Bewegtbildern ausreichend, jedoch ist die Verarbeitung von 25 Frames pro Sekunde bei der automatisierten visuellen Erkennung von Fehlerhaften teilen auf einer Produktionsstraße spätestens dann unzureichend, wenn pro Sekunde 60 Objekte die Kamera passieren.

Wie man leicht einsehen kann lässt sich der Begriff der Echtzeit nicht anhand menschlicher Sinneseindrücke festmachen. Der menschliche Erfahrungsbereich ist somit im Sinne der Echtzeitverarbeitung Sinnfällig. Der eigentliche Begriff der Echtzeit beschreibt mitnichten eine sich an den kognitiven Fähigkeiten von Menschen orientierende Verarbeitungsgeschwindigkeit, sondern muss im jeweiligen Anwendungskontext definiert werden. Weiterhin ist auch eine Einschränkung des Echtzeitbegriffes auf die Verarbeitungs- oder Reaktionsgeschwindigkeit von Systemen falsch, da Echtzeit einen weitaus breiteren Definitionsrahmen besitzt, auch wenn diese beiden Faktoren wichtige Kenngrößen für Echtzeitsysteme darstellen. Vielmehr muss ein Echtzeitsystem einen zeitlichen Determinismus aufweisen, der das Zeitverhalten eines Systems vorhersagbar macht und unter allen Bedingungen garantiert ist. Somit kann als Definition von Echtzeit gelten:

Ein System agiert genau dann in Echtzeit, wenn die Bearbeitung einer Aufgabe einen unter allen Bedingungen garantierten zeitlichen Determinismus aufweist, der zur korrekten Erfüllung der jeweiligen Aufgabe hinreichend ist.

Unter den angestellten Betrachtungen kann man sagen das die korrekte Bearbeitung einer Aufgabe in einem Echtzeitsystem nicht nur von der logischen Korrektheit, sondern auch von der zeitlichen Korrektheit der Erfüllung der Aufgabe abhängt und das Echtzeitsystem somit einen garantierten zeitlichen Determinismus aufweisen muss. Die Forderung nach zeitlicher Korrektheit der Erfüllung einer Aufgabe ist jedoch nicht Absolut, da sich die Auswirkungen bei einem Verfehlen der für eine bestimmte Aufgabe definierten zeitlichen Schranken in ihrer Ernsthaftigkeit für viele Anwendungen unterscheiden. So ist es sicherlich nicht als fataler Systemfehler anzusehen, wenn in einem Videostream bei der Bildwiedergabe am heimischen Computer Rahmen verworfen werden, wobei das Verwerfen von Rahmen in der bereits erwähnten Fertigungsstraße durchaus als kritisch zu betrachten ist. Um den jeweils unterschiedlichen stärken in denen Echtzeit gefordert wird Rechnung zu tragen, werden Aufgaben (nachfolgend als Tasks bezeichnet) je nach Echtzeitanforderung folgendermaßen klassifiziert:

Nachdem nun ein allgemeines Verständnis für die Echtzeit und Echtzeitsysteme vorhanden sein sollte, werde ich im nächsten Kapitel ein wenig auf die Basisdienste eingehen, die ein Echtzeitbetriebssystem i.d.R. bereitstellt. Die Betrachtung der Basisdienste erfolgt unter Einbeziehung des in Echtzeitsystemen erforderlichen zeitlichen Determinismus und weist an geeigneter Stelle auf die besonderheiten hin, die diese Forderung für die Konzipierung der Basisdienste eines Echtzeitbetriebssystems und der allgemeinen Programierung von Echtzeitsystemen bedeutet.

3. Basisdienste von Echtzeitbetriebssystemen

Wie bereits erwähnt führt die Forderung nach deterministischen Zeitverhalten in Echtzeitsystemen eine völlig neue Sichtweise bei der Planung von Software und Hardware eines Rechensystems ein. Um ein deterministisches Zeitverhalten bestimmter Anwendungen zu erreichen benötigt man zum einen sehr detailierte Kenntnisse über die hardwareseitigen Abläufe und die Ausführungseigenschaften von Code. Bei der Betrachtung des Quellcodes ist die Anzahl an Taktzyklen, die für die Abarbeitung einer Sequenz von Anweisungen benötigt werden in der Regel durchaus bekannt, jedoch spielen hier latente Verzögerungen die direkt auf die strukturellen Hardwareeigenschaften zurückzuführen sind eine große Rolle. Für gewöhnlich offerieren Echtzeitbetriebssysteme ebenso wie allgemeine Betriebssysteme eine Reihe von Diensten, die von der Anwendungssoftware zur Durchführung ihrer Aufgaben herangezogen werden kann. Diese Dienste müssen allerdings im Gegensatz zu allgemeinen Betriebssystemen garantierte Zusagen über deren Zeitverhalten machen und dies unabhängig von der aktuellen Auslastung des Systems. Eben diese verschärften Voraussetzungen begrenzen den Umfang der von Echtzeitbetriebssystemen für Gewöhnlich bereitgestellten Dienste mit garantiertem Zeitverhalten auf eine Untermenge der Dienste, die ein allgemeines Betriebssystem in der Regel bereitstellen wird. Die von einem Echtzeitbetriebssystem bereitgestellten Kerndienste lassen sich in der folgenden Abbildung veranschaulichen.


Übersicht über Basisdienste eines Echtzeitbetriebssystems

Wie aus der obigen Abbildung entnommen werden kann, zählen zu den Kerndiensten die von einem Echtzeitbetriebssystem bereitgestellt werden meist das Taskmanagement (Scheduling), die Task-Synchronisation und Kommunikation, die Bereitstellung von I/O-Schnittstellen zu Block- und Character Devices, sowie (rudimentäre) Mechanismen zur dynamischen Speicherzuteilung. Darüber hinaus bieten einige Echtzeitbetriebssysteme noch eine Anzahl an Erweiterungen wie dynamische Speicherverwaltung inklusive Paging und Swapping, Netzwerkschnittstellen und andere Dienste an. Im folgenden werde ich noch gesondert auf die einzelnen Basisdienste eingehen und einige Problematiken die mit diesen Diensten in zusammenhang stehen etwas näher erläutern.

3.1. Taskmanagement (Scheduling)

In den Vergangenen Jahren sind wie in der Einführung bereits erwähnt wurde große Anstrengungen unternommen worden Echtzeitbetriebssystem zu schaffen, die wie die General-Purpose-Betriebssysteme eine Vielzahl von Diensten den Anwendungen zur Verfügung stellen. Mit einer der wichtigsten Dienste der bereit gestellt wird ist wie bei den allgemeinen Betriebssystemen die Mechanismen zur parallelen Nutzung des Prozessors. Bei der Betrachtung von Echtzeitsystemen fällt auf, dass nahezu alle Systeme eine parallele Bearbeitung von Daten leisten müssen. Diese parallele Bearbeitung kann man sicherlich bis zu einem gewissen Grad durch die Bereitstellung weiterer designierter Mikroprozessoren erreichen, jedoch lässt sich das Konzept nicht beliebig ausdehnen. Hier wird in der Echtzeitdatenverarbeitung das schon aus den allgemeinen Betriebssystemen bekannte Multitasking angewendet, um die quasi parallele Bearbeitung von Tasks zu erreichen. Das wichtigste Konzept hierbei ist das Scheduling, das im folgenden näher betrachtet werden soll.

Die Forderung nach quasi paralleler Ausführung einer Anzahl an Tasks benötigt eine Strategie wie lauffähige Prozesse dem Prozessor zugeteilt werden. In allemeinen Betriebssystemen, die meist in interaktiven Dialogbetrieb eingesetzt werden, bestimmt die Wahl der Scheduling-Strategie eine Mischung aus den folgenden 5 Forderungen [2]:

  1. Fairness: Jeder Prozeß erhält einen gerechten Anteil der Prozessorzeit.
  2. Effizienz: Der Prozessor ist immer vollständig ausgelastet.
  3. Antwortzeit: Die Antwortzeit für den interaktiven Benutzer ist minimal.
  4. Verweilzeit: Die Wartezeit auf die Ausgabe von Stapelaufträgen wird minimiert.
  5. Durchsatz: Die Anzahl der in einem bestimmten Zeitintervall ausgeführten Aufträge wird maximiert.

Zu diesen Punkten gesellt sich im Rahmen der Echtzeitbetriebssysteme noch eine weitere, nämlich der nach dem deterministischen Zeitverhalten. Das deterministische Zeitverhalten spielt hierbei die wichtigste Rolle, wobei andere Forderungen in einem Echtzeitsystem nur untergeordnete Priorität haben oder gänzlich ausser acht gelassen werden.

Grundsätzlich teilt man die Schedulingstrategien ein in kooperatives Scheduling, verdrängendes Scheduling und nicht-verdrängendes Scheduling [1]. Durch die Forderung nach deterministischen Zeitverhalten kommt von den Scheduling-Strategien im Grunde nur die des verdrängenden (präemtiven) Scheduling für die Anwendung in Echtzeitbetriebssysteme in Frage, da alle anderen Strategien ein schwer bzw. nicht vorhersagbares Moment in das Zeitverhalten eines Systems einbringen.

Von den bekannten Verfahren zum Scheduling werden in Echtzeitbetriebssystemen auschließlich prioritätsbasierte Verfahren eingesetzt. Die prioritätsbasierten Verfahren unterscheiden sich i.d.R. darin, auf welche Art die Priorität eines Prozesses bestimmt wird. Allen gemein ist, dass aus der Menge der rechenbereiten Prozesse immer der mit der höchsten Priorität ausgewählt wird. Die Prioritätsbasierten Verfahren lassen sich nach dem Zeitpunt, zu dem die Prioritäten einzelner Prozesse vergeben werden, in statische und dynamische Verfahren einteilen. Eine Übersicht über die wichtigsten eingesetzten Verfahren bietet die folgende Grafik.


Übersicht einige prioritätsbasierten Schedulingverfahren

Bei der Betrachtung von Schedulingverfahren im Bereich von Echtzeitbetriebssystemen, wird unterschieden zwischen periodischen und aperiodischen Tasks. Aperiodische Tasks mit einer harten Echtzeitanforderung werden häufig auch als sporadische Tasks bezeichnet. Ein periodischer Task wird periodisch zu vorhersagbaren Zeitpunkten in äquidistanten Intervallen aktiviert, wobei ein sporadischer Task i.d.R. beim Auftreten von externe Ereignisse aktiviert werden muss. In der Regel sind Echtzeitsysteme reaktive Systeme, d.h. beschränken sich nicht nur auf periodische Tasks sondern arbeiten ebenfalls in hohem Maße mit aperiodischen Tasks.

Im folgenden soll nur kurz auf die Eigenheiten der drei wichtigsten Schedulingverfahren eingegangen werden. Eine detaillierte Diskussion der einzelnen Verfahren findet sich u.a. in [3] und [1].

Wie man sicherlich erkannt hat, beschränken sich sämtliche oben aufgeführten Schedulingalgorithmen auf das Scheduling von periodischen Tasks. Dies liegt daran, dass das Scheduling von aperiodische Tasks sehr komplex ist und in einer gemischten Umgebung von periodischen und aperiodischen Tasks meist derart auf das Scheduling von Periodischen Tasks zurückgeführt wird, dass man einen hoch priorisierten periodischen Servertask einführt, der während seiner Ausführungszeit anstehende aperiodische Tasks auf Basis des ihm zustehenden Quantums die CPU benutzen lässt. Diese herangehensweise reduziert das Schedulingproblem aperiodischer Tasks auf das Polling anstehender aperiodischer Tasks und basieren meist auf dem Ratenmonotonen- oder EDF-Schedulingalgorithmus. Beispiele für diese Art von aperiodischen Schedulingalgorithmen sind u.a. der Priority Exchange, Deferrable Server, sowie der Sporadic Server Algorithmus [4].

Ein weiterer Aspekt, der sowohl mit dem Scheduling aber auch mit der Reaktion auf externe Ereignisse zusammenhängt, ist die Art, mit der Dienste des Systemkerns ausgeführt werden. Die meisten allgemeinen Betriebssysteme blockieren während der Ausführung von Systemdiensten im Kernelmode die Interrupts um eine Verdrängung während der Bearbeitung von Serviceanforderungen zu unterbinden. Diese vorgehensweise ist in allgemeinen Betriebssystemen auch gänzlich unproblematisch, ist jedoch in Echtzeitbetriebssystemen nicht anwenbar. Stellt nämlich ein Task zu einem gegebenen Zeitpunkt während seiner Ausführungszeit einen Servicerequest an das Betriebssystem, könnten bei einer nicht unterbrechbarkeit der Systemdienste keinerlei Schedulingaktivitäten oder Reaktionen auf externe Ereignisse vonstatten gehen. Dies wäre der Vorhersagbarkeit des System bzgl. des Zeitverhaltens nicht besonders zuträglich und in dem Fall das ein Task just zu diesem Zeitpunkt eine Prozessorzuteilung benötigt, um seine Deadline einzuhalten wäre eine Fehlersituation vorprogrammiert. Aus diesem Grunde werden die Systemdienste soweit wie möglich so konzipiert, dass eine Verdrängung im Kernelmode möglich ist.

Bei der Betrachtung des Zeitverhaltens eines Systems, spielt die Latenzzeit eines Schedulingalgorithmus eine große Rolle. Wie dem Leser sicherlich bekannt ist, muss bei einem Kontextwechsel der aktuelle Prozessorzustand in den Hauptspeicher gerettet werden, was eine gewisse Zeit benötigt. Zu dieser Latenzzeit summiert sich natürlich auch die Zeit, die der jeweilige Schedulingalgorithmus benötigt, um den nächsten zu aktivierenden Prozess aus der Menge der rechenbereiten Prozesse auszuwählen. Hierbei ist natürlich ausschlaggebend, dass ein Algorithmus eine definierte zeitliche Obergrenze für die Ermittlung des nächsten auszuführenden Prozesses, unabhängig von der Anzahl der wartenden Prozesse haben muss, um den zeitlichen Determinismus des Systems nicht zu gefährden.

3.2. Speicherverwaltung

Die Speicherverwaltung in Echtzeitsystemen unterscheidet sich meist stark von der in allgemeinen Betriebssystemen eingesetzten Speicherverwaltung. Die gängige konventionelle Hardware enthält eine ganze Reihe von Mechanismen um die Anforderungen der Software zu unterstützen und die Systemperformance zu optimieren. So unterstützen eigentlich alle modernen Architekturen hoch entwickelte Mechanismen wie Caching, virtuellen Speicher mit Paging und Swapping, sowie die Segmentierung des Hauptspeichers. Alle diese Mechanismen dienen in den heutigen Systemen dazu die Anzahl der nebenläufig ausführbaren Programme zu erhöhen, ohne durch den physikalisch vorhandenen Hauptspeicher limitiert zu sein oder die Zugriffsgeschwindigkeit auf den Hauptspeicher zu optimieren. Eben solche Mechanismen lassen jedoch ein sicheres Vorhersagen des Zeitverhaltens nicht zu, weshalb in Echtzeitbetriebssystemen Lösungen gefunden werden müssen um mit den Problematiken die konventionelle Hardware für die Vorhersagbarkeit des Zeitverhaltens mit sich bringt. Weitere Probleme tun sich auf, wenn man die in modernen Betriebssystemen angewendete dynamische Alloziierung von Hauptspeicher anschaut.

In Echtzeitbetriebssystemen wird die dynamische Allozierung von Hauptspeicher meist mit sehr einfachen Strategien wie begrenzten Memory-Pools oder First Fit Strategien wie in VxWorks gearbeitet und manche Echtzeitbetriebssysteme wie RTLinux verzichten sogar vollständig auf die dynamische Alloziierung des Hauptspeichers. Vor allem solche Strategien, die eine Externe Fragmentierung des Hauptspeichers verursachen sind in Echtzeitsystemen problematisch. [13]

Die Speicherhierarchie in Echtzeitbetriebssystemen ist in der Regel Flach und verzichtet auf Konzepte wie virtuellem Speicher mit Paging und Swapping sowie der Isolierung von einzelnen Prozessen innerhalb des Hauptspeichers. Vor allem das Konzept des auf Swapping und Paging basierenden virtuellen Speichers lässt sich in Echtzeitbetriebssystemen nicht verwenden, da die Ein- und Auslagerung von Speicherseiten in/aus dem Hauptspeicher eine nicht vorhersagbare Latenzzeit in die Bearbeitung von Tasks einbringt. In Echtzeitbetriebssystemen die trotzdem Paging und Swapping unterstützen werden Mechanismen bereitgestellt um Speicherseiten oder ganze Echtzeitprozesse im Hauptspeicher resident zu halten.

Weiterhin Problematisch sind auch die Konzepte des Caching und Direkten Hauptspeicherzugriffs, da auch diese Mechanismen eine unvorhersagbare Verzögerung bzw. nichtdeterministisches Zeitverhalten in ein Echtzeitsystem einbringen. Beim DMA können aufgrund des sogenannten Cycle Stealing und den Cache Koheränzen unvorhersagbare Verzögerungen auftreten. Beim Cycle Stealing kann der Prozessor nach gewährter Busanforderung durch den DMA Controller ggf. einen darauffolgenden Buszugriff nur Verzögert durchführen, wenn der DMA Controller noch den Bus belegt, was natürlich nicht vorhersagbar ist. Das Problem mit Caching ist, dass durch Cache Misses eine gewisses Maß an Unvorhersagbarkeit bzgl. des Zeitverhaltens einer Task in das System eingebracht wird. Das Problem wird deutlich, wenn man sich vor Augen führt, dass z.B. bei einem Kontextwechsel der Cacheinhalt in der Regel vollständig oder in Teilen ungültig wird und der Cache bei erneuter Einlagerung mit gültigen Daten schrittweise wieder aufgebaut werden muss und das Maß an tatsächlichen notwendigen Hauptspeicherzugriffen nicht im Voraus bestimmen kann. Um das Problem zu umgehen kann man entweder den Cache in einzelne Partitionen teilen, die einem Task exclusiv zugeteilt werden oder das Caching für bestimmte Speicherbereiche deaktivieren. [3]

3.3. Synchronisation & Kommunikation

Ein weiteres Kapitel bei der Betrachtung von Echtzeitbetriebssystemen und echtzeitfähiger Software nimmt die Synchronisation und Kommunikation nebenläufiger Prozesse ein. Synchronisation von Prozessen impliziert in der Regel eine Zeit in der ein Prozess auf die Beendigung einer Tätigkeit eines anderen Prozesses warten muss. Solche Wartezeiten sind natürlich nicht immer Problematisch sondern in vielen Fällen durchaus gewünscht, jedoch muss in einem Echtzeitsystem eben diesen Wartebedingungen eine besondere Aufmerksamkeit gewidmet werden damit die Synchronisation nicht zum Verpassen einer zeitlichen Schranke für die Bearbeitung einer bestimmten Aufgabe führt. Weiterhin muss man auch die Möglichkeiten von Blockierungen erwägen, wenn man bei der Echtzeitprogrammierung mit Prozesssynchronisation und Kommunikation arbeitet. Sicherlich unterscheiden sich echtzeitfähige Programme bzgl. der Blockierungen nicht von konventionellen Programmen, jedoch sind die Auswirkungen von Blockierungen in Echtzeitsystemen in der Regel bedeutend schwerwiegender. Die Mechanismen zur Realisierung von Prozesssynchronisation unterscheiden sich in der Regel nicht von den in allgemeinen Betriebssystemen angewendeten Mechanismen, wie Spinlocks und Semaphoren oder die Sperrung von Interrupts. Zusätzlich zu diesen Möglichkeiten bieten einige Echtzeitbetriebssysteme die Möglichkeit den Scheduler zu deaktivieren, damit zwar die Reaktion auf externe Ereigniss anders als bei der Sperrung von Interrupts noch möglich ist, jedoch eine Verdrängung des aktiven Prozesses unabhängig von dessen Priorität unterbunden wird.

Ein Problem das bei der Synchronisation von Prozessen mittels einfachen Semaphoren oder Spinlocks auftreten kann, ist das der Prioritäteninversion. Prioritäteninversion bezeichnet das Phänomen, das ein hoch priorisierter Task nicht zur Ausführung gelangt, wenn er auf die Freigabe einer von einem niedriger priorisierten Task akquirierte Resource wartet. Im Normalfall wäre nun die Wartezeit für den hoch priorisierten Task genau die Zeit, die der niedrig priorisierte Task zur Freigabe der Resource benötigt. Nun kann es aber sein das der niedrig priorisierte Task von einem Task mittlerer Priorität verdrängt wird, sodass die Wartezeit für den hoch priorisierten Task unbestimmt wird. Dieses Problem nennt man Prioritäteninversion. Die folgende Abbildung verdeutlicht das Problem anhand eines kleinen Diagramms.


Exemplarische Timeline für Prioritäteninversion

Ein schönes Beispiel einer solchen Problematik in der wahren Welt fernab jeglicher theoretischer Annahmen lässt sich in der Pathfinder Mission der NASA im July 1997 finden, in der das Landefahrzeug eine Reihe von zunächst unerklärlicher Soft-Resets erfuhr, die auf das Phänomen der Prioritäteninversion zurückzuführen waren. Der Pathfinder arbeitete mit einer zentral genutzten Resource (ein Bus) die zur Kommunikation von verschiedenen Komponenten des Fahrzeugs genutzt wurde. Die Resource wurde auf Basis eines Mutex zwischen einem niedrig priorisierten Task zur Sammlung metheorologischer Daten und einem hochpriorisierten Busmanagement-Task zur exklusiven Nutzung reserviert. Das System enthielt jedoch auch noch eine Reihe weiterer Tasks, die mit mittlerer Priorität liefen. Die korrekte Arbeit des Busmanagement-Task wurde durch eine Art Watchdog Timer überwacht, der im Fehlerfall die gesamte Landeeinheit Soft-Resetten sollte. Nun kam es in einigen Fällen dazu das der niedrig priorisierte Task von den mittel priorisierten Tasks verdrängt wurde während er den Mutex noch belegt hatte. Nun wurde der hochpriorisierte Task blockiert und nach einer Weile registrierte der Watchdogtimer das der Busmanagement Task seit geraumer Zeit nicht mehr ausgeführt wurde und forcierte in der Annahme eines fatalen Fehlers ein Reset des Systems. Nach längerem Nachsinnen ließ sich der Fehler auf der Erde reproduzieren, sodass man durch einen Workaround die Mission doch noch ohne weitere Probleme durchführen konnte. Der Workaround basierte darauf, dass bei dem eingesetzten Echtzeitbetriebssystem VxWorks die Möglichkeit besteht, bei der Erzeugung eines Mutex oder Semaphor zu spezifizieren ob dieser Mutex mit Priority Inheritance arbeiten soll und der Lander im Nachhinein offensichtlich zur Nutzung dieses Features umprogrammiert werden konnte. [5], [6], [8]

Allgemein werden zur Umgehung der Prioritäteninversion zwei Ansätze verfolgt. Beim Priority Ceiling Verfahren wird jeder gemeinsam genutzten Resource eine Priorität zugeordnet, die der Priorität des höchst priorisierten jemals diese Resource verwendeten Prozess entspricht und temporär dem Benutzer zugewiesen wird, der diese Resource im Zugriff hat. Beim Priority Inheritance Verfahren weist man jedem Prozess, der eine Resource im Zugriff hat, auf die ein höher priorisierter Prozess wartet die Priorität des (höher priorisierten) wartenden Prozesses zu. Auf diese Weise vermeidet man das ein Prozess, der eine gemeinsam genutzte Resource im Zugriff hat, auf die ein höher priorisierter Task wartet, von einem Task mittlerer Priorität verdrängt wird. [7]

Für die Task-Kommunikation bieten die meisten Echtzeitbetriebssysteme Message Queues, Shared Memory oder Pipes an. Hierin unterscheiden sich die von Echtzeitbetriebssystemen bereitgestellten Mechanismen nicht wesentlich von den Mechanismen, die allgemeine Betriebssysteme bereitstellen. In einigen Fällen, wie z.B. in VxWorks, die auch einen vollständige Netzwerksupport bieten, wird zudem noch die Kommunikation über Sockets bereitgestellt.

3.4. Device I/O Supervision

>Die I/O Schnittstellen in Echtzeitbetriebssystemen stellen in der Regel Kommunikationsmöglichkeiten für eine Vielfalt an Geräten bereit. In der Regel umfassen Echtzeitbetriebssysteme unterstützung für Block- und Zeichenorientierte Geräte wie Festplatten, Standard Ein- und Ausgabe, periphere Interfaces über serielle und parallele Schnittstellen und mittlerweile auch relativ häufig ebenfalls für Netzwerkinterfaces.

Die Kommunikation mit I/O Geräten in Echtzeitbetriebssystemen bedarf wie die Prozesssynchronisation ebenfalls einer besonderen Aufmerksamkeit seitens des Echtzeitprogrammierers, da die typischen I/O Operationen, insbesondere auf blockorientierten Geräten wie Festplatten, zu schwer vorhersagbaren zeitlichen Verzögerungen führen können. Im allgemeinen sollten I/O Operationen nur unter sorgfältiger Erwägung des Zeitverhaltens der I/O Operationen erfolgen, wenn möglich ausserhalb von Tasks die Echtzeitanforderungen haben. In einigen Fällen stellen Echtzeitbetriebssysteme auch Schnittstellen für asynchrones I/O bereit. Asynchrones I/O unterscheidet sich von synchronem I/O dadurch, dass der Aufrufende Task bei asynchronem I/O nicht blockiert wird, bis die I/O Operation beendet ist. Dies macht natürlich nicht in allen Fällen Sinn, z.B. nicht beim Einlesen von Dateien oder dem Lesen von Daten eines Netzerkinterfaces.

4. VxWorks

Nachdem nun im ersten Teil der Arbeit ein Überblick über Besonderheiten die beim Design von Echtzeitbetriebssystemen und echtzeitfähigen Programmen beachtet werden müssen, werden ich nachfolgend exemplarisch auf das Echtzeitbetriebssystem VxWorks eingehen.

VxWorks ist das zur Zeit am häufigsten in Produktivumgebungen eingesetzte Echtzeitbetriebssystem auf dem Markt und wird von dem Kalifornischen Unternehmen WindRiver seit 1981 als Produkt angeboten. Das System besteht aus dem Wind Echtzeitkernel und einer Anzahl an optionalen Erweiterungspaketen u.a. zur Unterstützung von erweiterten Speicherschutzmechanismen auf Basis der in den meisten Prozessoren Einsatz findenden MMU. Der Kernel bietet auch die nach IEEE 1003.1b Spezifizierten POSIX realtime extension API an, die eine leichte Portierbarkeit von Applikationen von/auf andere Betriebssysteme ermöglicht. Die Entwicklung auf VxWorks erfolgt in der Regel Crossplatform, d.h. man entwickelt ein Echtzeitsystem auf Basis von VxWorks nicht direkt auf der Zielmaschine sonder nutzt eine Art Emulator, der auf diversen Hostplattformen (z.B. Unix, Solaris, Windows) läuft. Zur Unterstützung des Entwicklungsprozesses stellt WindRiver eine integrierte Entwicklungsumgebung namens Tornado in der Version 2.0 bereit. VxWorks unterstützt eine ganze Reihe an Prozessorarchitekturen wie Intel x86, Intel XScale (hat glaub ich auch einen ARM Core?), ARM, Intel i960, MIPS, PowerPC, SH, Sparc, Motorola MC680x0, uvm. Bestes und wohl auch prominentestes Beispiel für den (wenn auch nicht ganz reibungslosen) Einsatz ist sowohl die Pathfinder Mission, die im July 1997 von der NASA zur Exploration des MARS mit einer Landefähre unternommen wurde [5], als auch der jüngste Einsatz von VxWorks in der NASA/JPL Mission des Mars Exploration Rover im Januar 2004 [15].

Im weiteren werde ich kurz auf architektonische Merkmale des Kernels eingehen und die Eigenschaften des Kernels im Hinblick auf Scheduling, Speicherverwaltung, Synchronisation & Kommunikation und Device I/O beleuchten.

4.1. Scheduling

Das Scheduling in VxWorks wird durch einen prioritätenbasierten präemtiven Schedulingalgorithmus vorgenommen. Die Prioritätenvergabe erfolgt statisch und bietet die Möglichkeiten 256 Prioritätsstufen an die Prozesse zu vergeben. Die Prioritäten laufen hierbei von 0 (höchste Priorität) bis 255 (niedrigste Priorität). Der Scheduler bietet die Möglichkeit für Tasks gleicher Priorität einen Round Robin Mode einzusetzen der eine gerechte Prozessorzuteilung an die konkurrierenden Prozesse einer Prioritätsstufe mit konfigurierbaren Zeitscheiben ermöglicht. Ohne die Aktivierung des Round Robin Scheduling findet keine Verdrängung eines Prozesses durch Prozesse gleicher Prioritätsstufe statt. Tasks laufen bei VxWorks gemeinsam mit dem Kernel immer auf der höchsten Privilegierungsstufe, und teilen sich mit diesem einen linearen Adressraum (s.u.). Trotz der statischen Prioritätenvergabe lassen sich die Prioritäten zur Laufzeit anpassen, was unter anderem vom System genutz wird Semaphoren mit dem Priority Inheritance Verfahren gegen Prioritäteninversion zu schützen(s.u). [10], [14]

4.2. Speicherverwaltung

VxWorks arbeitet mit einem gemeinsammen linearen Adressraum für Kernel und Tasks, sodass ein Task (da er ja auch im Kernelmode läuft) vollen Zugriff auf den gesamten Speicherbereich hat. Diese Tatsache gibt den Task zwar zum einen ein höchstes Maß an Perforance und Vorhersagbarkeit bzgl. ihres Zeitverhaltens, birgt aber auch die Gefahr bei den immer komplexer werdenden Systemen durch Programmierfehler die Stabilität des Gesamtsystems zu gefährden. Aus diesem Grund gibt es für VxWorks einen grundlegenden und einen erweiterten Support für MMUs, über den Speicherschutzmechanismen wie das Sperren von Speicherseiten für den Zugriff von anderen Tasks zu realisieren. Windriver bietet für den erweiterten MMU Support eine Extension für VxWorks namens VxVMI als eigenständiges Produkt an, d.h. dieses ist wohl bei Bedarf explizit zu erwerben. Mittels VxVMI lassen sich dann u.a. automatisch alle Codeseiten im Hauptspeicher mit Schreibschutz versehen, Pufferüberläufe oder das Überschreiben der Interruptvektorentabelle durch Fehlerhafte NULL-Pointer Derefferenzierungen entdecken bzw. unterbinden. Bedingt durch die Tatsache das kein Virtueller Speicher unterstützt wird, ist natürlich auch der Speicherbedarf von Anwendungen durch den physikalischen Speicherausbau begrenzt. [10], [12]

Um dem Problemen für die Vorhersagbarkeit des Zeitverhaltens von Operationen durch Caching entgegenzuwirken unterstützt VxWorks das partielle und vollständige Deaktivieren des Cachings. [10]

Die dynamische Allokation von Hauptspeicher geschieht nach (nicht einfach validierbaren) Aussagen in diversen Online Manuals durch einen einfache First-Fit Algorithmus, der eine externe Fragmentierung des Hauptspeichers verursacht. Aus diesem Grund gilt es als Best Practice die Anzahl der dynamischen Speicherallokationen minimal zu halten. [14]

4.3. Synchronisation & Kommunikation

In VxWorks werden zur Synchronisation von Prozessen vor allem Semaphoren eingesetzt, die bei ihrer Erzeugung für die Verwendung des Priority Inheritance Verfahrens zum Schutz vor Prioritäteninversionen konfiguriert werden können. Weiterhin stellt der Kernel Mechanismen zur Temporären Deaktivierung des Schedulers oder der Interrupts bereit, um die Verdrängung des aktiven Prozess zu unterbinden. Hierbei ist jedoch besondere Vorsicht geboten, da die Sperrung von Interrupts sämtliche Reaktion auf externe Erreignisse unterbindet. Die Sperrung des Schedulers ermöglicht zwar weiterhin die Reaktion auf Interrupts, verhindert aber auch das solche Prozesse den Prozessor zugeteilt bekommen, deren Deadline herannaht, was durchaus zu einem verpassen der selbigen Führen kann. Wie bereits in der allgemeinen Diskussion der Konzepte in Echtzeitbetriebssystemen angesprochen ist bei der Verwendung von Synchronisationmechanismen in Echtzeitsystemen eine besondere Vorsicht geboten, um die zeitlichen Beschränkungen, die einem solchen System auferliegen nicht zu gefährden. [10], [14]

Die Kommunikation zwischen Tasks wird i.d.R. durch Message Queues, Pipes, Shared Memory oder Sockets durchgeführt. Der Primäre Kommunikationsmechanismus sind Message Queues, die jedoch ohne eine durch VxVM bereitgestellte Erweiterung nicht für den Einsatz in SMP Systemen vorgesehen sind. Message Queues sind unidirektional und können eine variable Anzahl an ebenso variabel Langen Messages enthalten. Aufgrund der Tatsache dass Message Queues unidirektional sind, erfordert die Vollduplex Kommunikation zweier Tasks auch die Aquisition zweier Message Queues. Das Schreiben und Lesen in bzw. aus der Message Queue kann optional in nicht blockierend geschehen, sodass der Versuch in eine volle Queue zu schreiben bzw. aus einer leeren Queue zu lesen einen Fehlercode zurückgibt anstatt den Task zu blockieren. [10]

4.4. Device I/O

Das Device I/O System von VxWorks stellt eine Reihe von Funktionen zur Durchführung von I/O Aufgaben bereit. Zu den Mechanismen die VxWorks für die Arbeit mit Devices bereitstellt gehören Routinen für synchrones und asynchrones I/O. Der Unterschied zwischen synchronem und asynchronem I/O besteht darin, dass bei asynchronen I/O Operationen der Aufrufer nicht bis zur Beendigung der Operation seitens des Betriebssystems blockiert wird, und somit keine Verzögerungen in das System eingebracht werden. Wie leicht ersichtlich immer ist das Arbeiten mit asynchronem I/O natürlich nur in solchen Fällen Sinnvoll und Möglich, in denen ein Prozess nicht zwingend auf das Ergebnis einer I/O Operation warten muss, wie dies beim Einlesen von Dateien der Fall ist.

Zur Operation auf Blockdevices stellt VxWorks eine Reihe von Dateisystemtreibern bereit und unterstützt unter anderem die Dateisysteme RT11, FAT12/16, ISO9660, sowie ein Raw Filesystem, dass das Vorhandene Blockdevice als eine große Datei behandelt und keine Strukturierung in Verzeichnisse unterstütz. Weiterhin stellt VxWorks eine umfangreiche Netzwerkimplementierung bereit, die Unterstützung für SLIP, PPP, TCP/IP und darauf aufbauende Dienste gibt. Für den Umgang mit den verschiedene Hardware Devices stellt VxWorks mit den sogenannten Board Support Packages eine umfangreiche Bibliothek von Geräte-Treibern bereit.

5. Epilog

Wie bereits im Abstract erwähnt stellt die vorliegende Arbeit weder eine vollständige Diskussion der gesamten theoretischen Aspekte der Echtzeitprogrammierung und Konzeption von Echtzeitbetriebssystemen, noch eine detailierte Anleitung für die Programmierung von Systemen auf Basis von VxWorks dar, sondern soll eine kurze Einführung in die Thematik bieten. Wenn seitens des Lesers weiterführendes Interresse an diesem Thema besteht, steht es Ihm frei, sich Anhand der nachstehenden Bibliographie mit der Thematik der Echtzeitprogrammierung weiter zu befassen.

Weiterhin übernimmt der Author keinerlei Haftung für Schäden die durch Verwendung der in dieser Arbeit dargelegten Informationen entstehen oder für die letztgültige Richtigkeit der gemachten Aussagen über interne Aspekte von VxWorks. Sollten bezüglich des Inhalts konstruktive Korrekturen seitens des Lesers beizusteuern sein, bin ich für eine Benachrichtigung mit einer Auflistung der Beanstandeten Dokumentbestandteile immer Dankbar. Weiterhin gwährt der Author dem Leser hiermit das Recht der Verwendung des vorliegenden Dokuments für private sowie wissenschaftliche und nicht kommerzielle Zwecke, sofern eine gültige Quellenangabe erfolgt.

As previously mentioned the present work does neither claim to be a complete discussion of the entire and pretty comprehensive theoretical aspects of programming realtime systems or the design of realtime operating systems nor an detailed instructions to the vxworks based realtime system programming, but is intended to be a brief introduction to the topic of realtime systems. If there is supposed to be some interrest in further reading, one is free to get more comprehensive knowledge to the subject matter by consultating the bibliography given below.

The author does even take any reasponsibility for any harm that might result of the use of information provided by the present document or for the completeness or final correctness of the information provided in regard to internal details to VxWorks. Are there supposed to be any corrections to be made on the part of the reader, the author is grateful for any correction proposals. Furtheron the author permits any private, scientific and non-commercial use of the present document, as long as this document is mentioned in the list of references.

6. Bibliographie