-
EINLEITUNG
-
Die
vorliegende Erfindung betrifft allgemein Softwaresysteme, die es
Anwendern gestatten mit Informationsverarbeitungsmitteln zu interagieren.
-
Genauer
betrifft die Erfindung ein Softwaresystem, daß ein Betriebssystem umfaßt, das
Stärken
in der Flexibilität
und der Ausführungsgeschwindigkeit
bietet, die selbst mit den zur Zeit leistungsfähigsten Betriebssystemen nicht
denkbar sind.
-
Die
Erfindung betrifft ein zu einem derartigen System gehörendes Verfahren.
-
Wie
zu sehen sein wird, ist die Erfindung vorteilhaft (aber nicht ausschließlich) auf
die Entwicklung von Anwendungen im Zusammenhang mit embedded Informationsverarbeitungssystemen
anwendbar.
-
Es
wird daran erinnert, daß das
Betriebssystem ein wesentliches Element jedes Softwaresystems ist, von
dem es den Teil bildet, der direkt mit den Hardware-Bestandteilen eines
Informationsverarbeitungssystems kommuniziert.
-
Es
sind bereits zahlreiche Betriebssysteme bekannt, die es Entwicklungsteams
gestatten, Anwendungen zu erzeugen und die es Endanwendern gestatten,
diese Anwendungen einzusetzen.
-
Die
bestehenden Betriebssysteme teilen sich grob in zwei bedeutende
Familien auf.
-
Monolithische
Architekturen
-
Die
erste Familie wird von den Betriebssystemen mit monolithischer Architektur
gebildet. Solche Systeme bilden eine einzelne Softwareeinheit, die
drei Hauptschichten umfaßt:
- – eine
Schicht, die als untere Schicht bezeichnet wird, entspricht dem
Systemkern. Der Kernel kann als eine passive und privilegierte Codeeinheit
definiert werden, die ununterbrochen in den Systemspeicher geladen ist
und von allen Anwendungsprozessen verwendet werden kann.
Seine
wesentliche Aufgabe ist es, die Verwendung der gemeinsam genutzten
Ressourcen des Systems (Speicher, Prozessor, Peripheriegeräte) zu regeln.
Um diese Aufgabe zu erfüllen,
stellt der Kernel bestimmte wichtige Funktionalitäten bereit,
wozu die folgenden gehören:
- – die
Verwaltung des Speichers (Verteilung der Speicherressourcen unter
den Anwendungen in Abhängigkeit
von deren Anforderungen ...),
- – Verwaltung
der Prozesse (Organisation, Verwaltung des Zugriffs auf den Prozessor,
Multitasking-Verwaltung, ...),
- – Verwaltung
der Treiber der Peripheriegeräte,
- – Verwaltung
der Dateien (Name, Adresse, ...),
- – Verwaltung
der Benutzer (Zugang, Profile, ...).
- – eine
Schicht, die als obere Schicht bezeichnet wird, die den Anwendungen
zugeordnet ist und mit der die Benutzer interagieren können, um
bestimmte Anweisungen und Anforderungen für den Kernel in das System
eingeben zu können,
- – eine
Zwischenstufe, die "Bibliotheks"-Stufe genannt wird
und die manchmal als eine Schicht aufgefaßt wird, in der die sich häufig wiederholenden
Funktionalitäten
derart zusammengefaßt
sind, daß deren schneller
Einsatz ermöglicht
wird.
-
Eine
solche monolithische Architektur ist schematisch in der dem vorliegenden
Text beigefügten 1 dargestellt, die die zentralisierte
und hierarchische Anordnung der Schichten K (Kernel), L (Bibliotheken)
und A (Anwendungen) zeigt.
-
Die
Festlegung von "Schichten" gestattet es, die
Kommunikation zwischen den Elementen des Betriebssystems hierarchisch
aufzubauen, wobei die weiter unten angeordneten Schichten als "privilegierte" Schichten festgelegt
sind, die von Schichten aus einer oberhalb angeordneten Stufe aufgerufen
werden können.
-
Die
Schichten sind somit Klassen von Softwareelementen, die dieselben
Privilegien teilen. Dabei kann ein Privileg als die Befähigung festgelegt
werden, bestimmte Ressourcen des EDV-Systems (Hardware-Ressourcen
oder Software-Ressourcen)
zu nutzen.
-
Wie
bereits gesagt, bildet ein gemäß einer
solchen monolithischen Architektur aufgebautes System eine einzelne
Softwareeinheit, die "en
bloc" kompilierbar
ist.
-
Ein
Vorteil dieses Aufbaus ist es, daß die Systeme im allgemeinen
stabil und schnell sind.
-
Solche
Betriebssysteme weisen jedoch erhebliche Einschränkungen hinsichtlich der Flexibilität der Veränderung
des Systems auf.
-
Tatsächlich führt eine
Veränderung
im Kernel systematisch zu dessen vollständiger Neukompilierung. Für jede Veränderung
ist somit ein vollständiger
Neuaufbau des Systems notwendig.
-
Diese
Starrheit des Systems wirkt sich nachteilig aus, da Veränderungen
des Systems schwerfällig und
komplex sind und die Wartung aufwendig ist. Außerdem kann das System durch
aufeinanderfolgende "Ergänzungen" instabil werden.
-
Abgesehen
davon kann sich diese Starrheit in embedded EDV-Systemen (das heißt Systeme,
bei denen wenigstens ein Teil zur Integration in ein mobiles Gerät, wie etwa
ein Fahrzeug, ein Mobiltelefon, etc., vorgesehen ist) als in hohem
Maße nachteilig
herausstellen, da sie dazu zwingt im voraus eine bestimmte Anzahl von
Eigenschaften des EDV-Systems (wie die Tatsache einer privilegierten
Ausführungsgeschwindigkeit
oder auch die Größe des Speichers
...) festzulegen.
-
Die
Vielfalt der embedded Anwendungen konfrontiert die Programmierer
jedoch häufig
mit unterschiedlichen Anforderungen an die zugehörigen Betriebssysteme und es
wäre vorteilhaft,
wenn die Haupteigenschaften des Systems frei festgelegt und verändert werden
könnten.
-
Somit
ist diese monolithische Architektur aufgrund der oben genannten
und im wesentlichen von der Starrheit der monolithischen Betriebssysteme
herrührenden
Nachteile im wesentlichen für
Anwendungen bestimmt, die keine bedeutende Veränderung der Software oder Hardware
benötigen,
und sie ist an embedded Systeme schlecht angepaßt.
-
Die Mikrokern-Architekturen
-
Mit
dem Ziel diese Einschränkungen
auszugleichen, wurde eine zweite Architekturfamilie für Betriebssysteme
entwickelt. Dies sind Systeme mit Mikrokernen, wie in 2 dargestellt.
-
Diese
Figur zeigt, daß die
Mikrokernsysteme genau wie die monolithischen Systeme aus konzentrischen
Schichten gebildet sind, die einen zentralen Kernel umgeben, der
das "Herz" des Betriebssystems
bildet.
-
Das
Kernelelement MK ist hier auf einen "Mikrokern" reduziert, der nur die für das Funktionieren
des Systems wesentlichen Funktionalitäten erfüllt, nämlich:
- – die Verwaltung
des Speichers,
- – die
Verwaltung der Prozesse, wenigstens soweit die als low-level bezeichneten
Prozesse betroffen sind – es
handelt sich um die Umschaltung der Tasks. Genauer verwalten bestimmte
Mikrokernsysteme die Prozesse hoher Stufen mit Hilfe eines Servers,
während
andere sie durch den Mikrokern selbst verwalten,
- – die
Verwaltung der Ports (Mailbox) und die Weiterleitung von Nachrichten,
- – die
Regelung der Zuteilung der Hardwareressourcen zwischen den verschiedenen
Treibern (ein Treiber ist als Steuerprogramm definiert, das heißt ein Programm,
das die Funktion einer Karte oder jedes anderen Peripheriegeräts steuert).
-
Die
anderen, herkömmlicher
Weise durch die Kernels der monolithischen Systeme erfüllten Funktionalitäten werden
durch Server S erfüllt.
Diese Server bilden eine Zwischenschicht zwischen der oberen Schicht der
Anwendungen A und der Schicht L der Bibliotheken, die direkt den
Mikrokern MK umgeben. Sie haben gegenüber den Anwendungen A Priorität.
-
Eine
solche Mikrokernarchitektur gestattet es, das Betriebssystem zu
verändern,
ohne daß eine
Neukompilierung des ganzen Systems notwendig ist; diese zweite Familie
von Betriebssystemen gestattet somit im Vergleich zu den monolithischen
Systemen eine gewisse Flexibilität.
-
Die
Architekturen dieser Familie sind jedoch weiterhin aus aufeinanderfolgenden
Schichten um einen zentralen Kernel aufgebaut und der gesamte interne
Datenaustausch des Betriebssystem geht notwendigerweise über den
Mikrokern.
-
Die
Weiterleitung der Nachrichten in den aufeinanderfolgenden Schichten
des Systems, die zahlreicher als in monolithischen Systemen sind,
führt jedoch
zu einer zusätzlichen
Verarbeitung und verlangsamt die allgemeine Funktion des Systems.
-
Daher
ist es für
alle neuen Entwicklungen des Systems notwendig, diesen Austausch
von Nachrichten zu optimieren, was die Arbeit der Programmierer
komplexer gestaltet.
-
Es
scheint daher, daß die
Mikrokernsysteme, wenn sie auch gegenüber den monolithischen Systemen eine
zusätzliche
Flexibilität
aufweisen, mit einer längeren
Verarbeitung verbunden sind und nur eine unvollkommene Lösung darstellen.
-
Zusätzliche Bemerkungen zu den
existierenden Architekturen
-
Außerdem sind
die derzeitigen Systeme (monolithisch und Mikrokern) alle auf ein
Kernelelement ausgerichtet, um das herum aufeinanderfolgende Schichten
hierarchisch aufgebaut sind, in Abhängigkeit von vorbestimmten
Zugriffsprivilegien.
-
Tatsächlich ist
in all diesen Systemen jedes Programm entsprechend einer unveränderlichen,
dem System eigenen Einteilung systematisch einer bestimmten Schicht
derart zugeordnet, daß dieses
Programm systematisch mit einer Privilegienstufe versehen wird,
ohne daß die
Programmierer hierüber
die Kontrolle haben, was einen ersten Nachteil darstellt, der den
existierenden Systemen gemeinsam ist.
-
Dabei
können
die Programme beispielsweise folgendes sein:
- – ein "Kernel-" oder "Steuerungs-" oder "System-" Code (der privilegierte
Code, der die Interaktion mit der Hardware verwaltet),
- – ein "Bibliothek-" Element mit passiven
Funktionalitäten
(mathematisch, Videodekomprimierung, etc.),
- – ein
Anwendungscode.
-
Diese
verschiedenen Codetypen entsprechen häufig unterschiedlichen Dateiformaten
und sie werden von verschiedenen Elementen des Betriebssystems in
verschiedener Weise verwaltet.
-
Es
ist daher nicht möglich
die Gesamtheit der im System installierten Programme mit einem einzigen Werkzeug
visuell darzustellen; desgleichen ist es im allgemeinen nicht möglich die "Kernel-" Teile, die einen abgeschirmten
und unteilbaren Block bilden, während
des Systembetriebs auszuwechseln.
-
Daraus
folgt, daß zum
Erzeugen und Debuggen dieser verschiedenen Codetypen verschiedene
Werkzeuge verwendet werden müssen,
was in jedem Fall die Entwicklungsprozesse verkompliziert; dies
stellt einen zweiten Nachteil dar, der den existierenden Systemen
gemeinsam ist.
-
Damit
ist es deutlich, daß der
Kerne! der existierenden Systeme ein absolutes Zentrum des Systems bildet.
Dieser Kernel hat durch seine Privilegienstufe eine spezielle Stellung;
er bildet den am wenigsten portierbaren Teil des Systems und kann
nicht in einfacher Weise verändert
werden.
-
Außerdem ist
es eine weitere gemeinsame Eigenschaft der existierenden Softwaresysteme,
daß ihre Konzeption
die folgenden Punkte umfaßt:
- – eine
Phase der funktionalen Analyse, die es gestattet, das System durch
die zu erfüllenden
Funktionalitäten
zu beschreiben, was eine sehr intuitive und unmittelbar verständliche
Beschreibungsform darstellt,
- – gefolgt
vom Schreiben und Kompilieren von Programmen, bei dem diese Verständlichkeit
und Lesbarkeit beeinträchtigt
wird, wobei die Programme eine abgeschirmte Einheit bilden, deren
Funktionsweise vorbestimmt ist.
-
Die
Programme dieser Systeme funktionieren auf Anfrage wie "Automaten" und der Kernel arbeitet
nur in Reaktion auf die von den Anwendungen gestellten Anforderungen.
-
Es
ist somit erkennbar, daß der
Kernel, wenngleich er auch die Ressourcen anpaßt und Optimierungsfunktionen
zur Verbesserung der allgemeinen Funktion des Systems verwenden
kann, immer in Reaktion auf die von den Anwendungen gestellten Anforderungen
und diesen nachgeschaltet arbeitet. Dies stellt eine weitere wesentliche
Einschränkung
der existierenden Systeme dar.
-
Wie
zu sehen sein wird, ist im Gegensatz dazu im Fall der Erfindung
die Funktionsweise aller Komponenten des Systems integriert und
die während
der Phase der funktionalen Analyse hergestellten funktionalen Verknüpfungen
werden in der Systemarchitektur erhalten.
-
Daher
wäre es
im Vergleich zu einem bekannten System, wie dem in der Sprache Java
(eingetragenes Warenzeichen) dargestellten, von dem eine Beschreibung
im Schriftstück "introduction to programming
using Java", Version
3.0, Sommer 2000, von D. J. Eck – Department of mathematics
and computer science, Hobart and William Smith College, Geneva,
New-York, US 24/05/2000, das am 7. März 2001 unter der Internetadresse
http://math.hws.edu/eck/cs124/downloads/Javanotes3.pdf> verfügbar war,
vorteilhaft ein zusätzliches
Maß an
Flexibilität
in der Festsetzung der Beziehungen zwischen den Entitäten anzubieten.
-
Unter "Entität" versteht man im
Fall der bekannten Sprachen (beispielsweise Java) die Objekte und Klassen,
die eingesetzt werden können.
-
Wenn
eine gegebene Entität
andere zu ihrem Funktionieren notwendige Entitäten tatsächlich aufrufen kann, muß der Programmierer
im Fall der Sprache Java notwendigerweise explizit spezifizieren,
welche Entitäten
es sind, die in den Arbeitsspeicher des Systems geladen werden müssen, um
die ordentliche Funktion der gegebenen aufrufenden Entität zu gestatten.
-
Es
ist daher erkennbar, daß dieser
bekannte Sprachtyp, wenn er auch tatsächlich eine mit einer Objektarchitektur
verbundene bestimmte Flexibilität
bietet, trotzdem schon bei der Konzeption die Auswahl spezieller
Entitäten
verlangt, was die Flexibilität
des Systems stark einschränkt.
-
Außerdem geben
solche bekannten Systeme keine Fehlermeldung bei Ladevorgängen zurück, so daß es möglich ist,
daß eine
fehlerhafte Entität
oder eine Entität,
die nicht in der Lage ist ihre Aufgabe zu erfüllen, in das System geladen
wird. Dabei wird die Unzulänglichkeit
der Entität
erst während
des allgemeinen Betriebs des Systems oder während Testvorgängen, die
dann speziell bereitgestellt werden müssen, festgestellt.
-
Das
Schriftstück "CORBA: A Platform
for Distributed Object Computing" von
YANG Z. et al. beschreibt eine Plattform zur Durchführung transparenter
Kommunikation zwischen Anwendungsobjekten.
-
Ziele der Erfindung
-
Das
Hauptziel der Erfindung ist es, ein Betriebssystem vorzuschlagen,
das Stärken
in der Flexibilität und
der Ausführungsgeschwindigkeit
bietet, die selbst mit den zur Zeit leistungsfähigsten Betriebssystemen nicht
denkbar sind.
-
Ein
weiteres Ziel der Erfindung ist es, ein Softwaresystem vorzuschlagen,
das es außerdem
gestattet, die oben im Zusammenhang mit der Gesamtheit der existierenden
Systeme besprochenen Nachteile zu überwinden.
-
Noch
ein weiteres Ziel der Erfindung ist es, eine Softwarelösung bereitzustellen,
die an die mit der Konzeption von embedded Systemen verbundenen
Randbedingungen angepaßt
ist.
-
Um
diese Ziele zu erreichen, schlägt
die Erfindung ein Entwicklungsverfahren für Informationsverarbeitungsprojekte,
die dafür
vorgesehen sind, durch ein EDV-System
eingesetzt zu werden, vor, wobei das Verfahren eine Phase der funktionalen
Analyse, in der die Funktionalitäten,
die bereitgestellt werden sollen, erfaßt werden, eine Phase der Erzeugung
von Komponenten des Projekts mit Hilfe von Informationsverarbeitungsmitteln,
um diese Funktionalitäten
zu erfüllen,
eine Phase der Deklaration (Anmeldung) der Komponenten, die in der
Erzeugungsphase erzeugt wurden, auf demselben System und eine Phase
des Ladens der Komponenten in einen Speicherbereich des Systems,
damit diese vom System eingesetzt werden können, umfaßt, dadurch gekennzeichnet,
daß:
- – bei
der Komponenten-Erzeugungsphase jede Funktionalität vollständig durch
die ihr zugeordnete Komponente erfüllt wird,
- – bei
der Komponenten-Anmeldungsphase jede erzeugte Komponente bei einer
Ladekomponente des Systems angemeldet wird, und
- – bei
der Komponenten-Ladephase Mittel vorgesehen sind, um für jede von
einer geladenen Komponente angeforderte Funktionalität automatisch
eine Komponente zu suchen, die diese Funktionalität anbietet.
-
Bevorzugte
jedoch nicht einschränkende
Ausführungsformen
des erfindungsgemäßen Verfahrens sind
die folgenden:
- – bei der Ausführung der
automatischen Suche wird eine Bedingung berücksichtigt,
- – die
Bedingung ist in Abhängigkeit
von Kriterien ausgedrückt,
die in Abhängigkeit
von individuell mit jeder Komponente verbundenen Eigenschaften ausgedrückt sind,
- – beim
Erzeugen einer Komponente werden folgende Phasen ausgeführt:
- – Erzeugen
einer Schnittstellen-Quelldatei der Komponente, um einen „Schnittstellen" Teil der Komponente zu
bilden,
- – Erzeugen
wenigstens einer Code-Quelldatei, die es gestattet, die Funktionalität der Komponente
umzusetzen, um einen „Implementierungs"-Teil der Komponente zu bilden,
- – jede
Code-Quelldatei, die erzeugt wurde, um einen „Implementierungs"-Teil der Komponente
zu bilden, kann in einer beliebigen Programmiersprache ausgeführt werden,
- – jede
Komponente kann die ihr zugeordnete Funktionalität erfüllen, indem sie Software- und/oder
Hardware-Mittel einsetzt,
- – die
Schnittstellendatei jeder Komponente umfaßt eine Beschreibung der durch
die Komponente erfüllten Funktionalität, unabhängig von
der Art, in der diese Funktionalität von der Komponente erfüllt wird,
- – die
Schnittstellendatei umfaßt
ebenfalls eine Beschreibung der Funktionalitäten, die die Komponente von anderen
Komponenten importieren muß,
um ihre eigene Funktionalität
zu erfüllen,
- – jede
Komponente kann dynamisch durch eine andere Komponente, die dieselbe
Funktionalität
exportiert, ersetzt werden,
- – die
Ersetzung führt
die folgenden Phasen aus:
- – Speichern
des aktuellen Zustands der zu ersetzenden Komponente,
- – Laden
und Initialisieren der neuen Komponente,
- – Übertragen
des aktuellen Zustands der zu ersetzenden Komponente auf die neue
Komponente,
- – Herstellen
eines Kommunikationskanals zwischen der die Funktionalität anfordernden
Komponente und der neuen Komponente,
- – Entfernen
der zu ersetzenden Komponente,
- – falls
das Laden oder Initialisieren der neuen Komponente nicht korrekt
ausgeführt
wurde, sind Mittel vorgesehen, um eine Fehlermeldung zurückzugeben,
- – beim
Erzeugen einer Komponente werden ebenfalls die folgenden Phasen
ausgeführt:
- – Erzeugen
eines Makefiles, in dem folgendes festgelegt ist:
- – die
Sprache(n), die für
die bei der Erzeugungsphase der Code-Quelldatei(en) erzeugte(n) Quelldatei(en) verwendet
wird (werden),
- – die
Code-Quelldatei(en), die dem „Implementierungs"-Teil der Komponente
entsprechen,
- – Erzeugen
eines Prototyps der Komponente,
- – Herstellen
der Verknüpfungen
zwischen dem „Schnittstellen"-Teil und dem „Implementierungs"-Teil der Komponente,
um einen ausführbaren
Prototyp der Komponente zu erzeugen,
- – Ausführen des
Makefiles, um die Komponente einzeln zu kompilieren und eine zugehörige Objektdatei für die Schnittstellen-Quelldatei
des „Schnittstellen"-Teils der Komponente
sowie für
die oder jede Code-Quelldatei des „Implementierungs"-Teils der Komponente
zu bilden.
- – Kapseln
der in der vorhergehenden Phase erzeugten Objektdateien in einem
einzelnen ausführbaren
Modul,
- – beim
Erzeugen des Prototyps einer Komponente wird ein Prototyp erzeugt,
der folgendes umfaßt:
- – eine
Objektschnittstelle, die sich aus der Kompilierung der Schnittstellen-Quelldatei der Komponente
ergibt,
- – eine
Prototyp-Objektdatei für
jede Code-Quelldatei des „Implementierungs"-Teils der Komponente,
- – bei
der Kompilierung der Schnittstellen-Quelldatei der Komponente wird
folgendes ausgeführt:
- – die
Analyse und Überprüfung der
Stimmigkeit der Schnittstellen-Quelldatei,
- – die Übersetzung
der Schnittstellen-Quelldatei in binäre Daten,
- – das
automatische Generieren wenigstens einer Datei, um die Funktionalitäten aufzurufen,
die von der Komponente importiert werden müssen,
- – nach
der Phase des Herstellens der Verknüpfungen zwischen dem „Schnittstellen"-Teil und dem „Implementierungs"-Teil der Komponente
zum Erzeugen eines ausführbaren
Prototyps der Komponente wird eine Phase mit einem automatischen
Integritätstest
ausgeführt,
während
der überprüft wird,
ob das Projekt stimmig und abgeschlossen ist,
- – beim
automatischen Integritätstest
für jede
im Projekt notwendige Funktionalität wird automatisch aus einer
Liste verfügbarer
Komponenten eine Komponente gesucht, die die Funktionalität erfüllt,
- – für den Fall,
daß mehrere
Komponenten gefunden werden, die die angeforderte Funktionalität erfüllen, kann
eine bestimmte Komponente unter diesen Komponenten ausgewählt werden,
- – für den Fall,
daß der
Integritätstest
ergibt, daß das
Projekt nicht korrekt abgeschlossen ist, wird eine Fehlermeldung
erzeugt, die die Unstimmigkeiten anzeigt, um bestimmte Komponenten
abändern
und/oder hinzufügen
zu können,
- – für jede in
das System geladene Komponente ist die Beschreibung der Funktionalitäten, die
die Komponente von anderen Komponenten importieren muß, um ihre
eigene Funktionalität
zu erfüllen,
für die
Mittel zur automatischen Suche von Komponenten ständig zugänglich,
- – beim
Kapseln der in der vorhergehenden Phase erzeugten Objektdateien
in einem einzelnen ausführbaren
Modul wird überprüft, daß alle von
den verschiedenen Schnittstellen-Teilen des Projekts bereitgestellten Funktionalitäten tatsächlich vollständig in
einer zugehörigen
Quelldatei beschrieben und kompiliert sind,
- – das
Verfahren umfaßt
die Speicherung eines Strukturdiagramms der in das System geladenen
Komponenten in einen Bereich des Arbeitsspeichers,
- – das
Strukturdiagramm ist dafür
vorgesehen, bei der Anforderung einer Funktionalität durch
eine anfordernde Komponente abgefragt zu werden, um zu ermitteln,
ob eine Komponente des Strukturdiagramms fähig ist, die angeforderte Funktionalität bereitzustellen,
- – es
sind die Mittel zur automatischen Suche von Komponenten, die dazu
fähig sind
das Strukturdiagramm abzufragen,
- – das
Strukturdiagramm wird im Betrieb des Systems in Abhängigkeit
von den in das System geladenen Komponenten in Echtzeit aktualisiert,
- – jede
Komponente kann einer Privilegienstufe zugeordnet werden, die die
Zugriffsmöglichkeiten
der Komponente auf andere Komponenten in Abhängigkeit von der jeweiligen
Privilegienstufe der anderen Komponenten steuert,
- – es
sind Mittel vorgesehen, um automatisch jede Komponente, deren Funktionalität, die von
ihr bereitgestellt wird, für
den Betrieb der Informationsverarbeitungsprojekte nicht mehr benötigt wird,
zu entfernen,
- – die
Mittel umfassen für
jede Komponente einen Referenzzähler,
- – der
Referenzzähler
zählt die
Anzahl der Komponenten, die eine Funktionalität der Komponente, zu der der
Zähler
gehört,
importieren und die Komponente wird entfernt, sobald ihr Referenzzähler bis
Null abgenommen hat,
- – es
sind Mittel vorgesehen, um automatisch die von der entfernten Komponente
verwendeten Ressourcen freizugeben.
-
Einführung der Figuren
-
Weitere
Ausführungsformen,
Ziele und Vorteile des erfindungsgemäßen Systems sind besser aus
der folgenden Beschreibung einer Ausführungsform der Erfindung erkennbar,
die mit Bezug auf die beigefügte Zeichnung
ausgeführt
ist, in der außer
den bereits beschriebenen 1 und 2:
-
die 3a bis 3c drei schematische Repräsentationen
eines erfindungsgemäßen Betriebssystems darstellen,
-
4 eine schematische Repräsentation
einer Komponente des erfindungsgemäßen Systems darstellt,
-
5 eine schematische Repräsentation
der Bearbeitungsphasen einer solchen Komponente darstellt,
-
6 einen Funktionsplan darstellt,
der das Erzeugen und den Einsatz einer Komponente eines erfindungsgemäßen Betriebssystems
veranschaulicht,
-
7 den Modus des Aufteilung
und des Ladens der Softwarekomponenten des erfindungsgemäßen Systems
darstellt,
-
8 die Verringerung des Speicherverbrauchs
beim dynamischen Laden und Freigeben der Komponenten eines erfindungsgemäßen Systems
darstellt,
-
9 einen Funktionsplan darstellt,
der das dynamische Ersetzen einer Komponente in einem erfindungsgemäßen System
veranschaulicht,
-
die 10a, 10b und 10c drei
Strukturdiagramme von Komponenten darstellen, die in ein erfindungsgemäßes System
geladen sind. 10a entspricht
einer minimalen Konfiguration, in der nur die für den anfänglichen Betrieb eines erfindungsgemäßen Systems
unbedingt notwendigen Komponenten geladen sind. 10b entspricht einer Basiskonfiguration,
die außerdem
eine Multithread-Verwaltung gestattet. 10c entspricht einer erweiterten Version
eines erfindungsgemäßen Systems.
-
Allgemeine Einführung in
das System
-
Es
wurde bereits gesagt, daß die
existierenden Systeme, die monolithischen wie die Mikrokernsysteme,
die Programme systematisch in Abhängigkeit von der Systemschicht,
der sie zugeordnet sind, unterscheiden.
-
Die
erfindungsgemäßen Systeme
unterscheiden die Programme nicht in dieser Weise. Im Fall der Erfindung
ist das Betriebssystem im Gegenteil vollständig aus nicht hierarchischen
Komponenten gebildet. Somit weist das erfindungsgemäße System
als eine originale Eigenschaft keine Struktur in Schichten auf.
-
Obwohl
der Programmierer eines Softwaresystems im Fall der Erfindung die
Möglichkeit
behält
jeder Komponente des Systems eine bestimmte Privilegienstufe zur
Kommunikation mit den anderen Komponenten zuzuordnen (diese Privilegienstufen
können
den üblichenrweise
in Systemen des Stands der Technik verwendeten Stufen entsprechen – "Kernel", "Bibliothek", "Anwendung", oder je nach Bedarf
erzeugt werden), ist der Programmierer frei eine solche Zuordnung
für jede
Komponente durchzuführen
oder nicht und für
die Komponente eine beliebige gewünschte Privilegienstufe zu
wählen.
-
Der
Begriff "Programmierer" kann dabei eine
einzelne Person oder eine Entwicklergruppe bezeichnen. Wie noch
erkennbar sein wird, ist ein wichtiges Anliegen des erfindungsgemäßen Systems,
es Entwicklergruppen zu gestatten so effizient wie möglich zu
arbeiten, wobei jeder Programmierer eine Funktionalität einer
Anwendung übernehmen
kann, indem er eine Komponente entwickelt. Die vom erfindungsgemäßen System
angebotene feine Verwaltung der Privilegien eröffnet zahlreiche Möglichkeiten,
wie beispielsweise:
- – die Erzeugung, die Entwicklung
und der vollständige
Test einer Komponente im "nicht
privilegierten" Modus
(Anwendung) und sein Einsatz auf dem Ziel im "privilegierten Modus (System) nachdem
die Entwicklung abgeschlossen und vollständig überprüft ist. Dieser Ansatz gestattet
dieselbe Flexibilität
der Einstellung wie eine Mikrokernsystem, indem er es gestattet
einen Treiber ("driver") in Form einer Anwendung
vorzusehen, um diesen anschließend
im "System"-Modus mit gleicher
Leistungsfähigkeit
wie in einem monolithischen Kernel zu nutzen.
- – die
Möglichkeit
unterschiedliche Privilegien innerhalb einer Komponentengruppe desselben
Typs (beispielsweise "codecs", Codierer-Decodierer
für Daten)
zuzuweisen: Einsatz einer einfachen Komponente (Beispiel: "Codec" GIF) in Form einer
Systemkomponente für
die Geschwindigkeit und einer komplexen Komponente (Beispiel "Codec" HTML oder Macromedia
Flash (eingetragenes Warenzeichen)) in Form einer Anwenderkomponente,
langsamer aber abgesichert und mit einer vollständigen Toleranz gegenüber Fehlern.
Die
Wahl je nach vorliegendem Fall, gestattet es dem Programmierer sein
System vollständig
in Abhängigkeit
von seinen Zielen aufzubauen.
-
Die 3a bis 3c stellen schematisch die Architektur
eines erfindungsgemäßen Systems
dar, das ausschließlich
auf der Basis von Komponenten realisiert ist und das kein "zentrales" Element wie einen
Kernel oder einen Mikrokern umfaßt.
-
Wie
erkennbar sein wird, hat jede dieser Komponenten eine eigene Existenz
im System; sie können unabhängig voneinander
erzeugt, kompiliert, in den Speicher und das System geladen und
entfernt werden, was folgendes gestattet:
- – dynamisches
Aktualisieren des Systems (neue Version, Fehlerkorrektur ...) ohne
jemals neu zu starten ("reboot"),
- – bei
der Konzeption des Softwaresystems kann man sich in der vom Softwaresystem
durchgeführten
Abstraktion von der Hardware von den wenig portierbaren "vorgefaßten Teilen" befreien, indem
die Möglichkeit angeboten
wird, die Verwaltungsform der Hardware in Abhängigkeit von den Bedürfnissen
des Endprodukts abzuändern.
-
Jede
Komponente des erfindungsgemäßen Systems
ist einer einzigen Funktionalität
gewidmet, im Gegensatz zu den herkömmlichen Betriebssystemen,
in denen der Kernel, wie auch die Mehrzahl der Programme, mehrere
Funktionalitäten
erfüllt.
-
Dabei
kann jede Komponente zur Erfüllung
der ihr zugeordneten Funktionalität die Ausführung einer oder mehrerer anderer
Funktionalitäten
durch eine oder mehrere andere Komponenten anfordern.
-
Somit
läßt das erfindungsgemäße System,
um funktionieren zu können,
jede gegebene Komponente, die in seinen Speicher geladen ist, mit
anderen Komponenten, die eine für
das Funktionieren der gegebenen Komponente notwendige Funktionalität erfüllen, kommunizieren.
-
So
umfassen die 3a bis 3c Pfeile, die die Kommunikationskanäle darstellen,
die vom System zwischen bestimmten Komponenten eingerichtet sind,
um ihnen zu gestatten sich Funktionalitäten weiterzugeben.
-
Diese
Figuren veranschaulichen ebenfalls den dynamischen Charakter der
Systemarchitektur, wobei eine Komponente 31 durch eine
Komponente 32 ersetzt werden kann, um dieselbe Funktionalität zu erfüllen, ohne
die Veränderung
irgendeiner anderen Komponente zu erfordern, wie dies in der 3C dargestellt ist. Diese
Eigenschaften werden nachfolgend genauer beschrieben.
-
Die Komponenten – Allgemeines
-
Allgemeine Definition
-
Es
ist erkennbar, daß die
Komponente ein grundlegendes Element des erfindungsgemäßen Systems ist,
daher ist es wichtig sie genau zu definieren.
-
Eine
Komponente im Sinn der Erfindung ist ein isoliertes, unabhängiges und
eigenständiges
Codeelement. Wie noch genauer beschrieben wird, besitzt jede Komponente
des erfindungsgemäßen Systems
die folgenden Eigenschaften:
- – sie erfüllt eine
einzelne Funktionalität,
der sie zugeordnet ist,
- – sie
erfüllt
diese Funktionalität
vollständig.
Eine gegebene Funktionalität
wird in einer einzigen Komponente ausgeführt. Dies gestattet es, daß im Verlauf
einer Anwendung oder jedes anderen Programms nur eine einzige Komponente
modifiziert oder ersetzt werden muß, wenn diese gegebene Funktionalität abgeändert werden
soll,
- – wie
bei der Objektphilosophie ist die Weise, in der eine gegebene Funktionalität von einer
Komponente erfüllt
wird, den anderen Komponenten, die diese Funktionalität verwenden,
nicht bekannt,
- – jede
Komponente wird unabhängig
kompiliert, um eine getrennte ausführbare Datei zu bilden, vergleichbar
mit einer Kapselung der Komponente ("Modul" der Komponente genannt). Bei der Kompilierung
findet keine Bearbeitung der Verknüpfungen zwischen den Komponenten
statt. Dies gestattet eine bisher unbekannte Flexibilität, insbesondere
für die
Komponenten, die die wesentlichen Funktionalitäten des Systems erfüllen, die
in herkömmlichen
Systemen dem "Kernel" zugeordnet sind,
- – jede
Komponente ist einem ausführbaren
Code zugeordnet, der in ihrem Modul mit Hilfe einer Schnittstelle
gekapselt ist, die ihrerseits individuell der Komponente zugeordnet
ist. Beim Entwurf einer Komponente beschreibt die entwerfende Person
mittels einer hierfür
vom Anmelder speziell entworfenen Beschreibungssprache in einer
Textdatei, die die Quellversion der Schnittstelle der Komponente
bildet, die von der Komponente bereitgestellte Funktionalität. Diese
Beschreibung ist die einzige Information, die dem System über die
Komponente zur Verfügung
gestellt wird. Eine solche Kapselung garantiert das Fehlen von "Seiteneffekten" und unkontrollierbaren
gegenseitigen Abhängigkeiten
zwischen Komponenten des Systems.
-
Eine
Komponente des erfindungsgemäßen Systems
ist daher ein vollständig
gekapseltes (im Modul) Softwareobjekt und vom Rest des Systems mittels
einer Schnittstelle isoliert, die, wie noch zu sehen sein wird, die
folgenden Eigenschaften besitzt:
- – Wiederverwendbarkeit
und Modularität
(dieselbe Komponente kann in verschiedenen Anwendungen eingesetzt
werden – oder
allgemeiner in verschiedenen Programmen),
- – Unabhängigkeit
gegenüber
der Umgebung (jede Komponente wird individuell erzeugt und kann
unabhängig
in das System geladen und aus ihm entfernt werden),
- – dynamische
Verbindungen (die Komponenten schalten sich auf Anfrage ein und
nicht in systematischer Weise),
- – Spezialisierung
in eine gegebene Funktionalität.
-
Eine
Komponente C ist aus zwei Hauptteilen gebildet, wie in 4 dargestellt ist:
- – ein
IMP-Teil, der die Umsetzung der der Komponente zugeordneten Funktionalität gestattet,
wobei dieser Teil üblicherweise
als "Implementierungsteil" der Komponente bezeichnet
wird. Dieser Teil entspricht dem Code, der zur Erfüllung der
Funktionalität
der Komponente ausgeführt
wird und/oder einer Hardware-Implementierung auf Hardwareelementen.
Unter "Code" werden ein oder
mehrere Programme verstanden, die in jeder bekannten Sprache geschrieben
sein können,
wobei das oder die Programme dazu bestimmt sind, die der Komponente
zugeordnete Funktionalität
zu erfüllen
und hierfür
eine oder mehrere Funktionen auszuführen,
- – und
ein INT-Teil "Schnittstelle" der Komponente,
der der beschreibende Teil ist, der den Dialog mit den anderen Komponenten
des Systems erlaubt.
-
Kapselung der Komponenten
-
Jede
Komponente ist in einem "Modul" gekapselt, einer
ausführbare
Datei, die die Objektdateien zusammenfaßt, die der Schnittstelle und
dem Code der Komponente entsprechen. Wie noch zu sehen sein wird, wird
diese Datei eigenständig
für jede
Komponente erzeugt, unabhängig
von den anderen, das erfindungsgemäße System bildenden Komponenten.
-
Zum
Erzeugen einer Komponente ist es notwendig, die außerhalb
der Komponente liegenden Funktionalitäten festzulegen, deren Ergebnisse
von ihr bei ihrer Ausführung
benötigt
werden; dies bedeutet eine Vorgehensweise einer herkömmlichen
funktionalen Analyse.
-
Das
erfindungsgemäße System
behält
jedoch, wie noch erkennbar wird, die aus dieser Phase der funktionalen
Analyse kommenden semantischen Informationen bis in den Rahmen der
Ausführung
der Komponente bei.
-
Dies
erleichtert sehr die Veränderung
des Systems und erhöht
seine Lesbarkeit.
-
Die
außerhalb
der Komponente liegenden Funktionalitäten werden mittels der vom
Anmelder entwickelten und oben bereits erwähnten Abhängigkeitensprache in der Quelldatei
der Komponentenschnittstelle beschrieben.
-
Genauer
gestattet jede zu einer Komponente C gehörende Schnittstellen-INT Quelldatei
die vollständige
Beschreibung einer Komponente. Sie beschreibt die Schnittstellenelemente,
die sie von anderen Komponenten importieren muß und diejenigen, die sie zu
anderen Komponenten exportiert.
-
Diese
Datei wird kompiliert (mit Hilfe einer Kompilierungsdatei MF, die
auch Makefile genannt wird) und mit der oder den Objektdateien verbunden,
die dem Code des Implementierungsteils IMP entsprechen (das heißt mit jeder
der einen oder mehreren Quelldateien des Implementierungsteils der
Komponente), um das Modul M der Komponente zu bilden, das die ausführbare Version
der Komponente darstellt, wie schematisch in der nachfolgenden 5 dargestellt ist. Die zum
Erzeugen der Schnittstellen-Quelldateien verwendete Abhängigkeitensprache
wird weiter unten im Text erklärt.
-
Ein
Modul M kann dann in ein Ziel 50 geladen (das Ziel wird
dabei als die EDV-Hardware definiert, auf der das erfindungsgemäße Softwaresystem
arbeitet) und dort sofort von den anderen auf diesem Ziel anwesenden
Komponenten erkannt werden, wie noch genauer ausgeführt wird.
-
Der Implementierungsteil
der Komponente
-
Der
Implementierungsteil IMP ist das operationelle Herz der Komponente.
Es ist der Teil, der die tatsächliche
Ausführung
der Funktionalität
der Komponente gestattet. Diese Funktionalität kann durch den Implementierungsteil
auf verschiedene Weisen realisiert werden, je nach den vom Code
implementierten Funktionen.
-
So
können
verschiedene Komponenten jede dieselbe Funktionalität realisieren,
jedoch unter Berücksichtigung
unterschiedlicher Kriterien, wobei die Kriterien bei der Konzeption
der die Komponente anfordernden Anwendung oder des Programms vorbestimmt
oder während
der Ausführung
der Anwendung dynamisch bestimmt werden können.
-
Diese
Kriterien werden in Form von Eigenschaften (beispielsweise void,
char etc.) beschrieben, die der Schnittstelle der Komponente zugeordnet
sind und die später
in diesem Text beschrieben werden.
-
Die
Kriterien werden in Abhängigkeit
einer dieser Eigenschaften ausgedrückt, die in der Schnittstelle der
Komponente, die die Funktionalität
exportiert, festgelegt ist, wobei die Schnittstelle der Komponente,
die die Funktionalität
importiert, einen Vergleichsoperator mit dieser Eigenschaft (<, >, = etc., wie nachfolgend
beschrieben wird) verbindet und ebenso einen Vergleichswert.
-
Damit
ist es möglich,
das System oder die Anwendung statisch oder dynamisch anzupassen,
in Abhängigkeit
von außerhalb
der Komponente liegenden Kriterien (Hardware beispielsweise) oder
dem aktuellen Zustand des Systems und der Anwendung während der
Ausführung.
-
Die
Schnittstellendatei jeder Komponente liefert somit eine Gesamtheit
an Metainformationen, die es gestattet, wie an einer speziellen
Komponente des Systems (der Verwaltung der Abhängigkeiten) zu sehen sein wird,
in Abhängigkeit
der oben erwähnten
Kriterien (die eine Version der Komponente, eine Lokalisierung dieser
Komponente, einen Datenwert des Systemzustands etc. betreffen können) in
passender Weise die Beziehungen zwischen den Komponenten zu verwalten.
-
Es
sei klar zum Ausdruck gebracht, daß, auch wenn jede Funktionalität einzig
und allein durch Code ("Software"-Implementierung
der Funktionalität)
realisiert werden kann, es ebenfalls möglich ist, daß wenigstens
ein Hardwareelement beteiligt ist, um die Funktionalität zu erfüllen ("Hardware"-Implementierung
der Funktionalität).
-
Der Schnittstellenteil
der Komponente
-
Der
Schnittstellenteil gestattet es, genau zu beschreiben welche Funktionalität durch
die Komponente bereitgestellt wird und welche Funktionalitäten ihr
während
ihrer Ausführung
bereitgestellt werden müssen.
-
Sie
legt in der vom Anmelder entwickelten Abhängigkeitensprache das Format
der Daten, die der Komponente als Eingabe bereitgestellt werden
müssen,
und das Format der Ausgabedaten der Komponente fest. Dieses Format
hängt einzig
und allein von der realisierten Funktionalität ab und nicht von der Weise,
in der die Funktionalität
durch den Implementierungsteil realisiert ist.
-
Dieser
Schnittstellenteil gestattet es, eine Beschreibung der durch die
Komponente realisierten Funktionalität zu bilden, die unabhängig von
der Art ist, in der diese Funktionalität durch den Implementierungsteil realisiert
wird. Tatsächlich
bleibt diese Funktionalität
vollkommen gleich, unabhängig
vom Ausführungsmodus der
Funktionalität
durch einen Code (oder ein programmiertes Hardwareelement). Sie
führt dieselben
Verarbeitungen durch, fordert dieselben Eingabeinformationen an
und stellt dieselben Ausgangsdaten bereit.
-
Der
Schnittstellenteil ermöglicht
daher großzügig Veränderungen
des Systems. Eine Softwareimplementierung einer Funktionalität (entsprechend
einer Komponente, deren Implementierungsteil aus Code besteht) kann
daher später
durch eine Hardwareimplementierung realisiert werden.
-
In
diesem Fall umfaßt
die entsprechende Komponente eine Schnittstellendatei, aber ihr
Implementierungsteil wird durch ein sehr einfaches Programm gebildet,
das die Verbindung mit dem Hardwareelement beschreibt.
-
Umgekehrt,
kann eine Hardwareimplementierung ohne jeden Einfluß auf die
anderen Komponenten durch eine Softwareimplementierung einer Funktionalität ersetzt
werden.
-
Eine
Schnittstelle wird in der Beschreibung des Komponentenmoduls durch
das Schlüsselwort "interface" festgelegt.
-
Die
folgende Tabelle beschreibt verschiedene Eigenschaften einer Funktionalität; diese
Eigenschaften können
Funktionalitäten
betreffen, die durch die Komponente angefordert werden (Richtung
= Import) oder die von der Komponente bereitgestellte Funktionalität (Richtung
= Export):
-
-
Eine
Schnittstelle kann in ihrer Textdatei mittels verschiedener Eigenschaften
festgelegt werden. Ein Beispiel wird nachfolgend angegeben:
-
-
Eigenschaften einer Schnittstelle
-
Die
Eigenschaften einer Schnittstelle gestatten es, die weiter oben
in diesem Text erwähnten
Kriterien festzulegen. Sie sind wie in der Sprache C (eingetragenes
Warenzeichen) typisiert. Die folgende Tabelle beschreibt die verschiedenen
Typen der Eigenschaften:
-
-
Die
folgenden Zusätze
können
den Eigenschaften zugeordnet werden:
-
-
Bei
der Beschreibung der Abhängigkeiten
in der Schnittstellendatei gestatten Operatoren die Eigenschaften
der Schnittstelle zu präzisieren.
Sie gestatten es damit, den Import einer anderen Schnittstelle nur dann
zuzulassen, wenn der Wert einer Eigenschaft dieser anderen Schnittstelle
einem genau festgelegten Kriterium entspricht.
-
Die
folgenden Operatoren können
den Eigenschaften der Schnittstelle zugeordnet werden:
-
-
-
Das
Schlüsselwort "undef" kann als Vergleichswert
für die
Eigenschaften oder die Funktionen verwendet werden. Im untenstehenden
Beispiel erfordert die betrachtete Komponente eine als Codec bezeichnete Schnittstelle,
die eine als mainType bezeichnete 32-Bit-Ganzzahl-Eigenschaft, deren
Wert genau 2 sein muß, umfaßt. Diese
Schnittstelle muß eine
Funktionalität
Func() realisieren, die als Parameter eine Zeichenkette übernimmt
und eine vorzeichenbehaftete 32-Bit-Ganzzahl zurückgibt.
-
-
Die
Bereitstellung und die Anforderung der Funktionalität geschehen
damit über
die Beschreibung von Programmierschnittstellen, die bereitgestellt
oder angefordert werden. Eine Komponente kann beispielsweise die
Programmierschnittstelle "scheduler" (Organisationseinheit,
die die Erzeugung/Zerstörung/Handhabung von
Prozessen und Threads und ihre Synchronisation gestattet) bereitstellen,
wobei sie die "Speicher"-Schnittstelle (Speicherverwaltung),
die "Timer"-Schnittstelle (Verwaltung
eines Zeitgebers, den die Organisationseinheit benötigt, um
einen Prozeß nach
einer gegebenen Zeit zu unterbrechen und zum nächsten zu wechseln), etc. anfordert.
-
Diese
Programmierschnittstellen können
sowohl
- – Eigenschaften
(Version, Speicherverwaltungstyp, Sequenzierungseigenschaften etc.),
als auch
- – Methoden
(Funktionen), die zur Ausführung
der Komponente aufgerufen werden, beinhalten.
-
Die
Eigenschaften sind sowohl bei der Bereitstellung als auch bei der
Anforderung einer gegebenen Schnittstelle verwendbar. Es kann daher
ausgedrückt
werden, daß die
einer Komponente zugeordnete Speicherschnittstelle in der Version
1.5.2 vorliegt (eine Eigenschaft, die bei der Bereitstellung der
Schnittstelle offenbart wird) oder auch, daß eine Speicherschnittstelle
angefordert wird, deren Version wenigstens 1.0.0 ist, jedoch nicht
die Version 1.0.4, da bekannt ist, daß sie einen nicht zu umgehenden "Bug" aufweist (eine Eigenschaft,
die bei der Anforderung der Schnittstelle offenbart wird).
-
Der
Inhalt der Schnittstelle (Eigenschaften und Methoden) bildet eine
Beschreibung, die vom Programmierer mittels einer vom Anmelder zu
diesem Zweck entwickelten Sprache geschrieben wird.
-
Die
Sprache wird vom Abhängigkeitencompiler
in eine binäre
Form kompiliert, die in der ausführbaren Komponente
enthalten ist, die das Modul bildet, ebenso wie der Komponentencode
und die zugeordneten Daten.
-
Diese
binäre
Form ist bei der Ausführung
leicht durch das System nutzbar, um die Komponenten untereinander
entsprechend der angeforderten Funktionalitäten zu verbinden.
-
Diese
Sprache wird ebenfalls verwendet, um genauer anzugeben, welchen
Codetyp die Komponente enthält
("System" oder nicht, "passiv" (Bibliothek) oder "aktiv" (Anwendung) etc.)
und welcher Codetyp auf eine gegebene Funktion zugreifen kann (dies
gestattet beispielsweise, die 'gefährlichen' Funktionen des Systems auf
die "System"-Aufrufer einzuschränken); dies
gestattet die Auswahl des am besten optimierten Kommunikationsmittels.
-
Die Komponenten – Erzeugung
und Laden in das System
-
Nun
mit Bezug auf 6, werden
die Erzeugungsphasen einer Komponente des erfindungsgemäßen Systems
und deren Einsatz in einem erfindungsgemäßen System beschrieben.
-
Die 6 ist ein Funktionsplan,
in dem die Spalten verschiedene, zum Erzeugen und zum Einsetzen von
Komponenten des erfindungsgemäßen Systems
verwendete Elemente darstellen. Von links nach rechts befinden sich
in der Tabelle:
- – zwei Spalten "COMP", die der Komponente
selber entsprechen, die ganz links gelegene Spalte "INT" entspricht dem Schnittstellenteil,
während
die folgende Spalte "IMP" dem Implementierungsteil
entspricht,
- – eine
Spalte "MF" für das Makefile,
das die Kompilierungsdatei der Komponente ist,
- – eine
Spalte "COMPIL DEP", die einem Konzeptionselement
der Komponenten, dem Abhängigkeitencompiler,
entspricht, ein Element, das vom Anmelder speziell zur Kompilierung
einer Komponente entwickelt wurde,
- – eine
Spalte "COMPIL CODE", die dem oder den
Compilern bekannten Typs der Datei(en), die den Code der Komponente
bilden, entspricht,
- – eine
Spalte "LINK", die dem Verknüpfungseditor
entspricht,
- – eine
Spalte "KBIM", die einem speziellen
Entwicklungswerkzeug des erfindungsgemäßen Systems entspricht, das
bei der Konzeption eines Projekts (ein Begriff, der nachfolgend
definiert wird) eingreift,
- – eine
Spalte "GD", die einer bestimmten,
als Verwaltung der Abhängigkeiten
(oder GD) bezeichnete, Komponente des erfindungsgemäßen Systems
zugeordnet ist, die, wie noch zu sehen sein wird, das Herz des erfindungsgemäßen Systems
bildet, sich jedoch vollständig
von den Kernels und Mikrokernen des Stands der Technik unterscheidet,
- – eine
Spalte "LOAD", die bestimmten
Komponenten, den Ladern, des erfindungsgemäßen Systems entspricht, die
es gestatten, die Komponenten des Systems in einen Arbeitsspeicherbereich
des Ziels zu laden,
- – die
rechte Spalte, die die verschiedenen beschriebenen Phasen angibt.
-
Erzeugen der Komponente
-
Es
wird hier die allgemeine Bedeutung des Begriffs "Projekt" definiert, der eine Gruppe von Komponenten
bezeichnet, die einem gemeinsamen Zweck im erfindungsgemäßen System
dienen. Ein Projekt kann somit einer Anwendung entsprechen aber
ebenso in einem weiteren Sinn jeder Art von Programm, das durch ein
EDV-System ausgeführt
werden kann und von einer Anwendung verschieden ist (beispielsweise
eine Peripherieverwaltung).
-
Vor
dem Erzeugen eines zum Einsatz im erfindungsgemäßen System bestimmten Projekts,
wird in 601 in herkömmlicher
Weise eine Phase der funktionalen Analyse (AF) ausgeführt.
-
Diese
Phase gestattet es, die verschiedenen notwendigen Komponenten, ihre
jeweiligen Funktionalitäten
und den jeder dieser Funktionalitäten zugeordneten Bedarf (Funktionalitäten, die
durch andere Komponenten bereitgestellt werden müssen) festzulegen. Wie wir
sehen werden, ist es möglich,
die bereits in das System geladenen Komponenten dazu zu verwenden,
dem Projekt bestimmte Funktionalitäten bereitzustellen.
-
Nachdem
diese vorangehende Analyse durchgeführt und der Bedarf bezüglich der
Komponenten bekannt ist, führt
der Programmierer für
jede Komponente nacheinander die Phasen 602 bis 606 aus:
-
- – in 602 das
Erzeugen einer Schnittstellen-Quelldatei der Komponente, wobei in
der vom Anmelder entwickelten Abhängigkeitensprache die Eigenschaften
der Komponente beschrieben werden. Wir werden später im Text auf die Eigenschaften
dieser Sprache und ihre prinzipiellen Möglichkeiten zurückkommen,
- – in 603 erzeugt
der Programmierer anschließend
den Code, das heißt
die Quelldatei(en), die es gestatten, die Funktionalität der Komponente
bereitzustellen, in einer oder mehreren Sprachen, die von einem
bekannten Typ sein können.
Während
dieser Phase wird (werden) die durch die Komponente exportierte(n) Funktion(en)
nur durch Prototypen festgelegt, wobei der entsprechende Code noch
nicht geschrieben ist.
Genauer ausgedrückt, entspricht eine Funktionalität einer
auszuführenden
Verarbeitung oder Operation (die Beschreibung einer Funktionalität erfolgt
in französisch/deutsch),
beispielsweise der Speicherverwaltung, beim Start laufender Prozesse,
um deren Zugriff auf den Prozessor des Ziels zu verwalten, die grafische
Darstellung etc. Das, was als Funktion bezeichnet wird ist ein Teil
des Softwarecodes, der ebenfalls eine Verarbeitung ausführt. Die
Funktion ist die Software-Umsetzung der Funktionalität (daher
ihr Name) in einer Programmiersprache.
In allen Programmiersprachen
ist eine Funktion in einer Weise umgesetzt, die sehr nahe an unserem
System liegt. Sie umfaßt:
- – einen
Prototyp, der die Eingabe- und Ausgabeparameter (ihren Namen und
ihren Typ) festlegt. Dieser Prototyp kann dem Schnittstellenteil
unserer Komponenten angegliedert werden (seine Rolle ist identisch),
- – einen
Codeteil. Dieser Teil führt
eine Verarbeitung auf Daten aus und gestattet es damit, das am Ausgang bereitzustellende
Ergebnis zu ermitteln.
Genauer ausgedrückt legt der Prototyp einer
Funktion den Namen der Funktion, ihre Eingabeparameter (ihre Namen
und ihre Typen) und den Typ der Information des von der Funktion
zurückgegebenen
Ergebnisses fest.
- – in 604 erzeugt
der Programmierer ein Makefile, in dem er insbesondere folgendes
spezifiziert:
- – die
Sprache(n), die für
die in der vorangegangenen Phase 603 erzeugte(n) Quelldatei(en)
verwendet wird (werden),
- – die
Quelldatei(en), die dem Implementierungsteil der Komponente entsprechen,
- – die
Kompilierungsoptionen,
- – in 605 erzeugt
der Programmierer mit dem Abhängigkeitencompiler
und dem oder den zu der oder den verwendeten Sprache(n) gehörenden Compiler(n)
einen Prototyp der Komponente, der folgendes umfaßt:
- – eine
Objektschnittstelle, die sich aus der Kompilierung der in 602 erzeugten
Schnittstellen-Quelldatei der Komponente durch den Abhängigkeitencompiler
ergibt. Für
diese Schnittstellenkompilierung analysiert der Abhängigkeitencompiler
den Text der Schnittstellen-Quelldatei, überprüft seine
Kohärenz
und übersetzt
ihn dann in Binärdaten,
die für
die GD verständlich
sind. Der Abhängigkeitencompiler
erzeugt automatisch Dateien, um die in der Schnittstelle genannten
und der Komponente bereitzustellenden Funktionalitäten aufzurufen.
Diese
Dateien sind vom Abhängigkeitencompiler
erzeugte Dateien vom "Include"-Typ. Für jede Implementierungssprache
des Codes wird eine "Include"-Datei erzeugt. Es
ist die Aufgabe dieser Dateien im EDV- System einen Namensbereich (das heißt einen
Kontext, dem Entsprechungen zugeordnet sind) festzulegen, der außerhalb
desjenigen der Komponente liegt und von diesem verschieden ist und
der es gestattet auf die Funktionalitäten zuzugreifen, die durch
die Komponente in ihrer Schnittstelle angefordert werden. Jede dieser "Include"-Dateien legt somit
Strukturen fest, die von der Schnittstelle der Komponente aufgerufen
werden können,
um die in der Schnittstelle auftretenden Anforderungen in Strukturen
und Namen zu übersetzen,
die von der Implementierungssprache verwendbar sind, der die "Include"-Datei zugeordnet ist.
- – eine
Objektdatei für
jede in 603 erzeugte Quelldatei; jede Objektdatei entspricht
in diesem Stadium einem Quelldateiprototyp dessen Funktionen nicht
vollständig
geschrieben sind,
- – in 606 bearbeitet
der Programmierer dann die Verknüpfungen
zwischen der Objektschnittstelle und der oder den Objektdatei(en)
des Implementierungsteils der Komponente, um einen ausführbaren
Prototyp der Komponente zu erzeugen.
-
KBIM
führt danach
in 607 einen Integritätstest
der Gesamtheit der so für
das betrachtete Projekt entwickelten Komponentenprototypen aus,
indem es überprüft, daß das erzeugte
Projekt kohärent
und abgeschlossen ist (das heißt
alle für
das Projekt notwendigen Funktionalitäten sind innerhalb des Projekts
vorhanden).
-
Für den Integritätstest verfügt KBIM über die
Liste und die Beschreibung der Schnittstellen aller Komponenten.
So kann KBIM unter diesen Komponenten diejenige Komponente suchen,
die eine für
das Projekt notwendige Funktionalität erfüllt. Wenn mehrere Komponenten
die angeforderte Funktionalität
erfüllen,
bietet KBIM dem Programmierer an unter diesen Komponenten auszuwählen. Die
automatisch von KBIM gefundene oder durch den Programmierer bezeichnete
Komponente wird dann den das Projekt bildenden Komponenten hinzugefügt. Diese
neue Komponente kann ebenfalls weitere Funktionalitäten benötigen, die
KBIM versucht aufzulösen.
KBIM gestattet es somit, den größten Teil
der für
ein Projekt notwendigen Funktionalitäten automatisch aufzulösen.
-
Wenn
das Projekt nicht korrekt abgeschlossen ist, verfaßt KBIM
eine Fehlermeldung, die dem Programmierer die Inkohärenzen anzeigt
und dieser wird wieder die Abfolge der Phasen 602 bis 606 durchführen, um
bestimmte Komponenten der Anwendung zu verändern und/oder Komponenten
hinzuzufügen;
wenn das Projekt kohärent
und abgeschlossen ist, vervollständigt
der Programmierer in 608 die Funktionsprototypen des Codes
des Implementierungsteils der Komponente, indem er in der oder den
Quelldateien dieses Implementierungsteils die vollständige Version
der Funktionen schreibt.
-
In 609 setzt
der Programmierer das Makefile ein, um jede Komponente getrennt
zu kompilieren, so daß für den Code
die Objektdateien erzeugt werden, die die Ausführung der Funktionalität der Komponente gestatten.
Während
dieser Phase ruft das Makefile zum Erstellen des Codes den Abhängigkeitencompiler
sowie den oder die Compiler der verwendeten Sprache(n) auf. Die
Phasen 608 und 609 werden für jede Komponente des in der
Entwicklung befindlichen Projekts wiederholt.
-
Der
Programmierer setzt danach in 610 den Verknüpfungseditor
ein, um für
jede Komponente ein ausführbares
Modul zu erzeugen, wobei das Modul zur Gesamtheit der in den Kompilierungsphasen 605 bis 609 erzeugten
Objektdateien gehört
(die Objektschnittstelle wurde in der Phase 605 erzeugt,
während
die dem Code zugeordnete(n) Objektdatei(en) in der Phase 609 erzeugt
wurde(n)).
-
Während dieser
Bearbeitung der Verknüpfungen,
die der Kapselung der Komponente im Modul entspricht, überprüft der Editor,
daß alle
durch die verschiedenen Schnittstellen des Projekts bereitgestellten Funktionalitäten tatsächlich vollständig in
einer zugeordneten Quelldatei beschrieben und kompiliert wurden.
-
Deklaration
der Komponente
-
Nachdem
für jede
Komponente des Projekts ein ausführbares
Modul in dieser Weise erzeugt wurde, muß der Programmierer die Existenz
dieser Komponenten deklarieren, damit diese vom System berücksichtigt werden.
Diese Deklaration wird in 611 ausgeführt, wobei der Programmierer
in dieser Phase jede Komponente bei einem "Lader" deklariert, wobei die Lader selbst
spezielle Komponenten des erfindungsgemäßen Systems sind.
-
In
dieser Phase 611 speichert der Lader bei dem eine Komponente
deklariert wird die Komponente in einer dem Lader eigenen Liste,
die die Gesamtheit der bei ihm deklarierten Komponenten zusammenfaßt.
-
Diese
Phase 611 ist ebenfalls eine Phase, die das in Entwicklung
befindliche Projekt insgesamt betrifft, alle für ein Projekt entwickelten
Komponenten sind bei wenigstens einem Lader deklariert – jeder
Lader entspricht einem Medium des EDV-Systems (Platte, Netz etc.), auf dem
die diesem Lader zugeordneten Komponenten gespeichert sind.
-
Laden der Komponente in
das System
-
Oben
wurden die Phasen der Erzeugung und Deklaration eines "Projekts", das mehrere Komponenten umfassen
kann, beschrieben. Nachfolgend wird der Einsatz dieser Komponenten
beschrieben, der im unteren Teil der 6 dargestellt
ist.
-
In 620 ruft
eine Komponente C1 eine für
sie notwendige Funktionalität
F1 auf. Für
diesen Aufruf gibt es zwei Möglichkeiten:
- – zum
einen kann die Funktionalität
F1 in der Schnittstelle der Komponente C1 mit der Eigenschaft "loadtime" festgelegt sein
(die Eigenschaft "loadtime" ist weiter oben
beschrieben). In diesem Fall wird die GD die Komponente, die diese
Funktionalität
F1 erfüllt,
vor dem Laden der Komponente C1 suchen und in das System laden.
- – Wenn
diese Komponente selbst eine "Loadtime"-Funktionalität benötigt, lädt die GD
auch die zum Erfüllen dieser
Funktionalität
notwendige Komponente, und dies ebenfalls vor dem Laden der Komponente
C1. Die GD lädt
somit rekursiv alle Komponenten, die zum Erfüllen der verschiedenen "Loadtime"-Funktionalitäten, die sie antrifft, notwendig
sind (weiter unten wird erklärt,
wie eine Komponente in das System geladen wird).
- – zum
anderen kann die Funktionalität
F1 mit der Eigenschaft "runtime" festgelegt sein
(die Eigenschaft "runtime" ist weiter oben
beschrieben).
Die Komponente C1 muß daher explizit eine andere
Funktionalität, "depmgr", aufrufen, die durch
die GD bereitgestellt wird, um die "Runtime"-Funktionalität F1 aufzurufen. Hierfür muß die Funktionalität "depmgr" unbedingt mit der
Eigenschaft "loadtime" in der Schnittstelle
von C1 deklariert werden, damit diese Schnittstelle bereits beim
Laden und der Initialisierung von C1 verwendet werden kann (siehe
weiter oben zur Behandlung der "Loadtime"-Funktionalitäten).
C1
kann dann die in 620 aufgerufene "Runtime"-Funktionalität F1 genau in dem Moment importieren,
in dem sie sie einsetzen muß.
Die Komponente, die diese Funktionalität F1 erfüllt, wird dann durch die GD geladen.
Wenn
diese Komponente bei ihrem Laden eine Funktionalität benötigt (eine
in ihrer Schnittstelle als "loadtime" deklarierte Funktionalität), wird
die Komponente, die diese "Loadtime"-Funktionalität erfüllt, ebenfalls geladen.
Die
GD lädt
somit rekursiv alle Komponenten, die notwendig sind, um die verschiedenen "Loadtime"-Funktionalitäten zu erfüllen, die
sie antrifft (weiter unten wird erklärt, wie eine Komponente in
das System geladen wird). Die anfänglich in 620 angeforderte
Funktionalität
F1 ist für
C1 daher erst dann verfügbar,
wenn alle während
der Auflösung
angetroffenen "Loadtime"-Funktionalitäten ebenfalls aufgelöst sind.
Wenn eine einzige durch C1 beim Laden angeforderte Funktionalität (eine
als "loadtime" deklarierte Funktionalität) nicht
aufgelöst
ist, wird C1 nicht geladen. C1 kann dann nämlich seine funktionale Aufgabe
nicht erfüllen, da
es eine andere für
sie notwendige Funktionalität
nicht verwenden kann.
-
Wenn
die Funktionalität,
die C1 importieren muß,
nicht von einer der Komponenten des Projekts, zu dem C1 gehört und unter
dem es bei einem der Lader des Systems deklariert ist, erfüllt wird,
bestimmt das System, wie wir noch zeigen werden, in einem anderen
Projekt eine Komponente, die es gestattet, diese Funktionalität für C1 bereitzustellen.
-
Hierfür prüft die GD,
die ununterbrochen in den Arbeitsspeicher des Systems geladen ist,
in ihrem "Verknüpfungsgraphen", ob die Schnittstellen-Objektdatei
einer der Komponenten des Verknüpfungsgraphen anzeigt,
daß diese
Komponente die von C1 angefragte Funktionalität bereitstellt.
-
Hierfür wertet
die GD die "binäre" Version der Schnittstellendatei
aus, die in der ausführbaren
Komponente gespeichert ist und bei der Ausführung durch die "Lader"-Komponenten zur
GD geladen/übertragen wird.
-
Die
GD sucht zuerst die Schnittstellen, die denselben Namen wie die
Angefragte (Importierte) aufweisen. Wenn sie solche findet, überprüft sie anschließend innerhalb
dieser, ob alle Eigenschaften der angefragten Funktionalität vorhanden
und die eventuell vorhandenen Randbedingungen und Bedingungen (Version größer als
0.6.2 etc.) erfüllt
sind.
-
Der
Verknüpfungsgraph
der GD ist eine Liste der in das System geladenen Komponenten, das
heißt Komponenten,
die nicht nur deklariert sind, wie oben bezüglich der Phase 611 beschrieben
ist, sondern deren Schnittstellen-Objektdatei in einen Arbeitsspeicherbereich
des Ziels importiert wurde und die mit anderen Komponenten des Verknüpfungsgraphen
in Verbindung steht, um bereitgestellte und/oder angefragte Funktionalitäten auszutauschen.
-
Der
Verknüpfungsgraph,
der in einem Arbeitsspeicherbereich des Ziels gespeichert ist, ist
somit ein momentanes Bild der geladenen Komponenten, wobei der Verknüpfungsgraph
sich dynamisch entwickeln kann. Der Verknüpfungsgraph ist nur einmal
vorhanden und der GD zugeordnet, wobei die GD Zugriff auf die Informationen
des Verknüpfungsgraphen
hat.
-
Wenn
die GD in der Phase 621 feststellt, daß die von C1 aufgerufene Funktionalität durch
eine der Komponenten des Verknüpfungsgraphen
bereitgestellt wird (die "aufgerufene
Komponente" C2 genannt
wird, während
C1 die "aufrufende
Komponente" ist),
stellt sie zwischen der Komponente C2 und der Komponente C1 einen
Kommunikationskanal her, indem sie in 627 die Eigenschaften
der Komponente C2 in die Komponente C1 importiert.
-
Genauer
erstellt die GD für
C1 eine "View" (Ansicht) genannte
Datenstruktur, die eine Ansicht der durchzuführenden Importe anbietet. Dieser "View" umfaßt den Wert
der Eigenschaften und die Zeiger auf die importierten Funktionen
(oder auf Code, der es indirekt gestattet, diese zu erreichen, wie
beispielsweise ein Systemaufruf, eine Threadmigration, etc.). Diese "Ansicht" geht direkt aus
den vom Abhängigkeitencompiler
in den "Include"-Dateien erzeugten
Elementen hervor.
-
Wenn
jetzt die GD in 621 feststellt, daß die von C1 aufgerufene Funktionalität durch
keine der Komponenten des Verknüpfungsgraphen
bereitgestellt wird, wird sie die Listen der Lader des Systems nacheinander
abfragen, um festzustellen, ob eine der bei diesen Ladern deklarierten
Komponenten die von C1 angefragte Funktionalität anbietet. Dieses Abfragen
der Lader ist in Phase 622 dargestellt.
-
Bei
diesem Abfragen verwendet die GD eine Funktionalität "Lader", die die notwendigen
Funktionen zum Auflisten der Komponenten besitzt, die jeder "Lader" sieht. Die Funktionalität "Lader" gestattet es der
GD, eine durch eine Komponente des Laders exportierte Funktionalität mit der
zu importierenden Funktionalität
zu vergleichen. Sie gestattet es der GD ebenfalls, eine einzelne
Komponente vom Medium, dem der Lader zugeordnet ist, in den Arbeitsspeicher
des Ziels zu laden und freizugeben.
-
Genauer
ist jeder der Lader des erfindungsgemäßen Systems einem bestimmten
Medium zugeordnet, das die Speicherung der Komponenten gestattet;
jeder Lader kann so einer Speicherplatte oder jedem anderen Aufzeichnungsträger, beispielsweise
vom CD-ROM-Typ, zugeordnet sein. Die Vielzahl der Lader ist insbesondere
mit Bezug auf 7 dargestellt.
-
Wenn
eine solche Komponente in der Liste eines der Lader des Systems
ausfindig gemacht ist (Phase 623), übermittelt der erste Lader,
dessen Liste eine solche Komponente enthält, in 625 die Objektschnittstelle der
identifizierten Komponente C2 an die Verwaltung der Abhängigkeiten
und die GD selbst übermittelt
in 626 an die Komponente C1 die "Ansicht" dieser Komponente C2. (Phase 627).
-
Die "Ansicht" von C2 wurde von
der GD in einem Speicherbereich des Systems gespeichert, der beim Laden
der Komponente C2 dynamisch durch die GD erzeugt wird und der zusammen
mit der Freigabe dieser Komponente zerstört wird. Dieser Bereich befindet
sich im selben Adreßraum
wie die Komponente, die darauf zugreifen kann.
-
Wenn
in der Phase 623 die Suche der GD zum Auffinden einer die
angefragte Funktionalität
bereitstellenden Komponente in der Liste eines der Lader kein Ergebnis
liefert, hält
das System in 624 an.
-
In
jedem Fall führt
das Laden einer Komponente C1 in den Arbeitsspeicher des Systems
wie oben erklärt
zur automatischen Suche einer Komponente C2, die die für das Funktionieren
der Komponente C1 notwendige Funktionalität F1 anbietet, durch die GD.
-
Falls
die Komponente C1 nicht eine sondern mehrere Funktionalitäten aufruft,
führt die
GD in gleicher Weise die automatische Suche nach den diese erforderlichen
Funktionalitäten
anbietenden Komponenten durch.
-
Es
ist erkennbar, daß das
erfindungsgemäße System
gegenüber
den bekannten Systemen ein zusätzliches
Maß an
Flexibilität
anbietet.
-
Tatsächlich muß der Programmierer
für bekannte,
mit Entitäten
aufgebaute Systeme für
jede gegebene aufrufende Entität
die Liste der anderen Entitäten
des Systems spezifizieren, die für
das Funktionieren der aufrufenden Entität notwendig sind und die für das gute
Funktionieren dieser aufrufenden Entität in das System geladen werden
müssen.
-
Somit
sind bei diesen bekannten Systemen die Bedürfnisse der Entitäten nicht
in allgemeiner Weise durch Funktionalitäten ausgedrückt, sondern durch spezifische
Entitäten
(dies ist beispielsweise für
die Sprache Java der Fall).
-
Im
Fall der Erfindung ist jede von mehreren verschiedenen Komponenten
imstande einer aufrufenden Komponente C1 zugeordnet zu werden, insofern
die verschiedenen Komponenten dieselbe Funktionalität anbieten.
-
Ein
zusätzlicher
Vorteil der Erfindung ergibt sich auch aus den Kriterien, die den
Komponenten zugeordnet werden können,
wobei diese Kriterien durch die GD bei ihrer automatischen Suche
nach Komponenten, die eine von einer ersten Komponente angefragte
Funktionalität
anbieten, berücksichtigt
werden.
-
Tatsächlich sucht
die GD bei dieser Komponentensuche nicht nur eine Komponente, die
eine angefragte Funktionalität
anbietet, sondern genauer eine Komponente, die diese Funktionalität in Verbindung
mit einer spezifischen Bedingung anbietet, die gemäß den weiter
oben im Text erwähnten
Kriterien ausgedrückt ist.
-
Im
Fall der existierenden Sprachen (beispielsweise vom Java-Sprachtyp-eingetragenes Warenzeichen)
muß der
Programmierer tatsächlich
unbedingt eine explizite Verknüpfung
zwischen einer aufrufenden Entität
und einer aufgerufenen Entität
herstellen.
-
Es
ist somit erkennbar, daß der
Einsatz dieses Typs von bekannten Systemen in keiner Weise dasselbe
Maß an
Flexibilität
wie die Erfindung anbietet, die sich viel besser zur Wartung und
Veränderung
eignet (beispielsweise zur Realisierung erweiterter Versionen, in
denen Komponenten, die eine angefragte Funktionalität anbieten,
durch andere Komponenten, die dieselbe Funktionalität auf eine
andere Weise erfüllen,
ersetzt werden können
oder auch das Hinzufügen
neuer Komponenten, die die Funktionalität erfüllen, um der GD neue Auswahlmöglichkeiten
anzubieten).
-
Somit
gestattet es die Erfindung, extrem veränderbare Systeme aufzubauen,
in denen nach Belieben lediglich eine oder mehrere gewünschte Komponenten
ersetzt werden können.
-
Jede
Ersatzkomponente bietet eine Funktionalität an, die bereits durch die
alte Komponente, die ersetzt wird, angeboten wurde.
-
Indessen
können
die spezifischen Mittel zum Erfüllen
dieser Funktionalität
sich beliebig verändern,
unabhängig
davon, ob es Software- und/oder Hardwaremittel sind.
-
Im
Rahmen von Anwendungen wie der Wartung eines Netzwerks von an verschiedenen
Standorten installierten Systemen oder auch die Wartung einer Gruppe
von mobilen Vorrichtungen (wie beispielsweise Mobiletelefone oder
elektronische Notizbücher),
die man zur Wartung nicht physisch an einen zentralen Standort zurückholen
will, ist diese Möglichkeit
insbesondere interessant.
-
Somit
können
die auf Vorrichtungen vom oben erwähnten Typ installierten Anwendungen
durch das einfache Herunterladen einer oder mehrerer neuer Komponenten
von einem zentralen Ort auf diese Vorrichtung gewartet werden, und
dies, ohne daß die
Vorrichtungen, die über
ein beliebiges Gebiet verstreut sein können, physisch bewegt werden
müssen.
-
Außerdem erfordert
das Ersetzen dieser Komponenten nicht die Neukompilierung des EDV-Systems, das
sie einsetzt.
-
Wenn
eine Komponente C2, die die von C1 angefragte Funktionalität anbietet,
identifiziert wurde (wobei möglicherweise
die Kriterien einer von der Schnittstelle von (1) geforderten Bedingung
genügen
und in 627 die Eigenschaften von C2 in C1 importiert wurden),
wird die Verwaltung der Abhängigkeiten
unterschiedlich vorgehen, je nachdem, ob die Komponente C2 bereits
zum Verknüpfungsgraphen
gehört
oder nicht (Phase 628).
-
Wenn
C2 bereits zum Verknüpfungsgraphen
gehört,
geht die GD direkt zur Phase 633, in der ein Kommunikationskanal
zwischen C1 und C2 erzeugt wird. Hierfür verwendet das System in Abhängigkeit
von in der Schnittstelle von C1 und/oder C2 festgelegten Eigenschaften
entweder einen der vier unten beschriebenen Kommunikationsmodi oder
einen speziell erzeugten spezifischen Modus:
-
Die direkten Aufrufe
-
Dies
ist das schnellste Verfahren. Die angeforderte Funktionalität oder Methode
wird direkt aufgerufen und ihr Ergebnis direkt zurückgegeben.
Es gibt keinen dazwischen liegenden Code. Die Verwaltung der Abhängigkeiten
wählt dieses
Mittel, wenn die beiden Komponenten sich auf derselben Maschine,
im selben Adreßraum
und auf derselben Privilegienstufe befinden.
-
Ein
Adreßraum
ist als ein logischer Speicherbereich definiert, in dem Code- oder Datenadressen
für alle
auf diesen Bereich zugreifenden Komponenten gültig sind. Ein Zeiger auf Code
oder Daten kann unverändert
von einer Komponente zu einer anderen übertragen werden und gestattet
es, ohne daß sein
Wert verändert
wird, auf dieselben Daten zuzugreifen.
-
In
der Erfindung bedeutet der Begriff "Adreßraum" ebenfalls gemeinsame Privilegien, wobei
ein Adreßraum
einen "Raum" oder eine Klasse
von Objekten mit derselben Privilegienstufe bezeichnet: auf die
von Zeigern erfaßten
Objekte eines selben Adreßraums
können
die verschiedenen Komponenten somit in derselben Weise zugreifen.
-
So
kann beispielsweise ein "Anwendungs"-Raum mit niedriger
Privilegienstufe und ein "Steuerungs"-Raum mit hoher Privilegienstufe
festgelegt werden.
-
Die
Kohärenz
der Zeiger zwischen dem "Anwendungs"-Raum jedes Prozesses
und dem "Steuerungs"-Raum (System) wird
respektiert (der Prozessor des EDV-Systems hat gleichzeitig auf
beide Räume
Zugriff), aber der "Anwendungs"-Code kann keine
Daten im "Steuerungs"-Raum referenzieren.
-
Die
Privilegien sind Zugriffsmöglichkeiten
zwischen Komponenten; in der Quellenschnittstelle können die
folgenden Privilegienstufen verwendet werden:
-
-
Um
einer Komponente eine dieser Privilegienstufen zuzuweisen, legt
der Programmierer den entsprechenden Parameter in der Definition
des Moduls der Komponente fest, der innerhalb eines Texts vom folgenden
Typ enthalten ist:
-
-
Somit
ist es in allgemeiner Weise möglich
jeder einzelnen Komponente eine gegebene Privilegienstufe zuzuordnen,
wobei die Privilegienstufe die Zugriffsmöglichkeiten dieser Komponente
auf andere Komponenten regelt, in Abhängigkeit von den jeweiligen
Privilegienstufen der anderen Komponenten.
-
Anders
ausgedrückt
ermöglicht
die Zuordnung einer Privilegienstufe zu einer Komponente es dieser Komponente,
die von den Schnittstellen bestimmter Komponenten angebotenen Funktionalitäten zu "sehen", in Abhängigkeit
von den Privilegienstufen, die diesen anderen Komponenten wirksam
zugeordnet sind.
-
Wie
wir weiter unten noch sehen werden, kann diese Zugriffshierarchie
zwischen den Komponenten, die durch die Privilegienstufen begründet ist,
die den verschiedenen Komponenten einzeln zugeordnet werden können, durch
Operatoren "kurzgeschlossen" werden, die bestimmten
spezifischen Komponenten einzeln zugeordnet sind.
-
Beispiele
für solche
Aufrufe sind die folgenden:
- – Steuerungskomponente
zu Steuerungskomponente,
- – Anwendungskomponente
(das heißt
mit niedriger Privilegienstufe) zu Anwendungskomponente im selben Adreßraum (wie
eine Anwendung, die eine Komponente verwendet, die eine Bibliothek
mit passiven und gemeinsam genutzten Funktionen verwaltet).
-
Dieses
Verfahren ist das einzig verwendete, wenn die Speicherkomponente
keinen Schutz bereitstellt, was die Wahl der Ingenieure, die das
System für
ihr Produkt entwerfen, sein kann, wobei ohne einen Schutzmechanismus
ein sehr schnelles System bereitgestellt wird.
-
Die
Speicherkomponente "liefert" keinen Schutz wenn
die Komponente nur einen einzigen Adreßraum vom Typ "System" anbietet. Dieser
Typ der Speicherverwaltung bietet keinerlei Schutz (alles arbeitet
im selben Raum und kann potentiell den oder die zu anderen Komponenten
gehörenden
Code oder Daten zerstören
oder verändern),
ist jedoch auf bestimmten Zielen, die keine "MMU" (Memory
Management Unit) besitzen, die einzige Möglichkeit.
-
Die Systemaufrufe
-
Der
Aufruf wird auf einen Systemaufruf umgeleitet. Dieser transferiert
die Parameter vom Anwendungsstack zum Steuerungsstack, ändert die
Privilegienstufe, führt
den Aufruf aus, kehrt zur niedrigen Privilegienstufe zurück und gibt
das Ergebnis direkt zurück.
-
Dieses
Verfahren wird ausgewählt,
wenn eine Anwendungskomponente (nicht privilegiert) eine Funktionalität einer
Steuerungskomponente aufruft, falls letztere die nicht privilegierten
Komponenten dazu berechtigt sie zu verwenden.
-
Diese
Berechtigung geschieht auf der Ebene der Beschreibungssprache der
Abhängigkeiten
durch das Schlüsselwort "promote". Allgemeiner können die
folgenden Schlüsselworte
einer Komponente zugeordnet werden (in der Syntax der vom Anmelder
entwickelten Sprache werden die Schlüsselworte einfach der Eigenschaft
oder Methode deren Funktionsweise sie verändern sollen als Präfix vorangestellt):
-
-
Somit
gestattet die oben erwähnte
und durch das Schlüsselwort "promote" aktivierte Berechtigung
das "Kurzschließen" der an anderer Stelle
eingerichteten Privilegienstufen, um einzeln den Zugriff einer Komponente
auf eine andere zu gestatten, auf die ihre Privilegienstufe ihr
keinen Zugriff geben würde.
-
Die Threadmigration
-
Das
erfindungsgemäße System
trennt die logische Verwaltung eines Ausführungsthreads (Kennung, Priorität, Systemstack
etc.) von seiner physischen Verwaltung (Prozessorkontext, Anwendungsstack,
Adreßraum
in dem der Thread sich befindet etc.).
-
Wenn
eine Komponente eine Funktion aufruft, die sich in einem anderen
Adreßraum
befindet, und dies in synchroner Weise macht (der Aufrufende ist
blockiert solange er auf das Ergebnis wartet), "migriert" der Aufrufende in den Aufgerufenen
und führt
die Verarbeitung aus.
-
Hierfür legt der
logische Teil des Threads seinen aktuellen physischen Teil auf den
Stack und bindet sich an einen neuen physischen Teil, der im Adreßraum des
Aufgerufenen erzeugt wurde.
-
Der
Code der gewünschten
Funktionalität
wird dann im Kontext des Aufgerufenen ausgeführt (das heißt im selben
Adreßraum
und demselben Containerprozeß),
aber im logischen Thread des Aufrufenden. Nachdem die Funktion fertig
ist, holt der aufrufende Thread seinen originalen physischen Teil
vom Stack und "migriert" wieder in den Aufrufenden.
-
Der
Migrationscode der Threads befaßt
sich auch damit, die Parameter in beide Richtungen zu übertragen,
wobei er die als Parameter bereitgestellten Speicherbereiche, die
Zeichenketten, etc. kopiert oder neu zuordnet.
-
Dieser
Mechanismus vermeidet das deutlich kostspieligere herkömmliche
Verfahren, das darin besteht eine Nachricht zu erzeugen, die Nachricht
an einen Thread in der aufgerufenen Komponente zu senden, den Thread
des Aufrufenden zu suspendieren, die Nachricht im Aufgerufenen auszuwerten,
die gewünschte Funktion
auszuführen,
wieder eine Nachricht für
das Ergebnis zu erzeugen, den Aufrufenden aufzuwecken, den Aufgerufenen
wieder zu suspendieren.
-
Er
vermeidet ebenfalls zahlreiche mit der synchronen Übertragung
der Nachrichten verbundene Probleme wie die Umkehrung der Prioritäten (hier
wird die aufgerufene Funktionalität mit der Priorität des Aufrufenden
ausgeführt)
die Abrechnung der Ressourcen (die Maschinenzeit wird dem Aufrufenden
angerechnet) sowie die Notwendigkeit einen "Pool" an
Threads in der aufgerufenen Komponente zu unterhalten, die schlafen,
wobei sie unnütz
Speicherressourcen verwenden, bis sie Aufrufe empfangen, um danach
in Aufrufspitzen nicht in ausreichender Zahl vorhanden zu sein (hier
migrieren die Aufrufenden in die Aufgerufenen, es ist immer genau
die notwendige Anzahl an Threads vorhanden).
-
Dieses
Verfahren optimiert wesentlich den gebräuchlichsten Fall von Aufrufen
außerhalb
des Adreßraums:
die synchronen Aufrufe auf derselben Maschine.
-
Die Nachrichtenübermittlung
-
Im
Gegensatz zu den Systemen auf der Basis von Mikrokernen beispielsweise,
in denen es systematisch eingesetzt wird, wird dieses Verfahren
nur für
die Aufrufe verwendet, die nicht unter die obenstehenden Kategorien
fallen, wie etwa
- – lokaler asynchroner Aufruf
(der Aufrufende ist während
des Wartens auf das Ergebnis nicht blockiert),
- – Fernaufruf
zu einer anderen Maschine.
-
Die Übermittlung
von Nachrichten beinhaltet das Kodieren der in einer Nachricht bereitgestellten
Parameter, das Routing der Nachricht zu einer Zielkomponente, das
Dekodieren, das Ausführen
der Funktion, dem Ablegen des Ergebnisses in einer Nachricht, das
Zurücksenden
zum Aufrufenden. Dieses Verfahren ist wie oben erwähnt wurde
insbesondere für
asynchrone Aufrufe (die Ergebnisnachricht wird nachträglich gesendet)
und Fernaufrufe, die ohnehin die Bildung von Netzwerkpaketen benötigen, geeignet.
-
Mit
Bezug auf die zu 6 bereits
gegebene Beschreibung, ist das Erzeugen eines Kommunikationskanals
mit dem Aufruf der Funktion zum Eintragen der aufrufenden Komponente
C1 im Implementierungsteil der aufgerufenen Komponente C2 verbunden.
-
Diese
als Register() bezeichnete Funktion stellt einen Teil der Funktionalität "Component" dar, die von allen
Komponenten des Systems zusätzlich
zu ihrer eigenen Funktionalität
bereitgestellt wird. Die Funktionalität "Component" umfaßt vier Funktionen:
- – Initialisierung,
- – Rücksetzen,
- – Eintragen,
- – Austragen.
-
Wenn
nun die GD in 628 feststellt, daß die Komponente C2 nicht zum
Verknüpfungsgraphen
gehört, ruft
sie in 629 den Lader dieser Komponente C2 auf, um C2 in
den Arbeitsspeicher des Ziels zu bringen, in 630 die Initialisierungsfunktionen
von C2 aufzurufen und in 631 den Verknüpfungsgraphen zu aktualisieren.
-
So
stellt 7 den Verknüpfungsgraphen
G dar, in den die GD eine Komponente oder eine Gruppe P2 von Komponenten
vom Speicherplatz 72 eines ersten Laders importieren kann,
um es einer bereits im Verknüpfungsgraphen
vorhandenen Komponente C1 (die zuvor vom Speicherbereich 71 von
einem anderen Lader mit dem Projekt P1 zu dem sie gehört importiert
wurde) zu ermöglichen,
mit einer aufgerufenen Komponente G2 in Verbindung zu sein, von
der GD in der Phase 623 der Suche in den Ladern ermittelt
hat, daß sie eine
für C1
notwendige Funktionalität
bereitstellt.
-
Es
sei daran erinnert, daß tatsächlich beim
durch KBIM in 607 durchgeführten Integritätstest (siehe 6) KBIM nicht streng überprüft, ob jede
von einer Komponente aufgerufene Funktionalität von einer Komponente eines
selben Projekts angeboten wird, sondern allgemeiner von einer in
das Softwaresystem geladenen Komponente.
-
Nochmals
mit Bezug auf 6, mündet die
Phase 631 in die bereits beschriebene Phase 633.
-
Da
das Laden einer von einer Komponente C1 aufgerufenen Komponente
C2 beschrieben wurde, ist es erkennbar, daß die Komponente C1 ihrerseits
von einer anderen Komponente aufgerufen wurde und daß es notwendig
ist, beim Systemstart den Aufruf der Funktionalitäten anzustoßen.
-
Hierfür fordert
die GD beim Start einer Anwendung eine Funktionalität "Interaktion" an und sucht eine Komponente,
die diese Funktionalität
bereitstellt. Die GD kann auch eine Komponente importieren, die
diese Funktionalität
anfordert. In jedem Fall ruft die Funktionalität "Interaktion" eine andere Komponente auf, die ihrerseits
wenigstens eine weitere Komponente aufruft.
-
Die Verwaltung der Abhängigkeiten
-
Wie
bereits gesagt wurde, ist die Verwaltung der Abhängigkeiten eine Komponente,
die ununterbrochen in das erfindungsgemäße System geladen ist. Sie
gestattet es, die Verknüpfungen
zwischen den verschiedenen die Anwendung bildenden Komponenten zu
erstellen; diese Verknüpfungen
werden ausgehend von den Schnittstellen der Komponente eingerichtet.
-
Gemäß einer
vorteilhaften Eigenschaft der Erfindung werden nur die für das Funktionieren
der Anwendung und des Systems nützlichen
Komponenten geladen, um somit die notwendigen Ressourcen zu optimieren.
Diese Optimierung kann nach einem der folgenden Modi durchgeführt werden:
-
Automatisches Laden der
Komponenten bei der Ausführung
-
Wenn
eine Komponente zur Ausführung
geladen wird, analysiert die Verwaltung der Abhängigkeiten ihre Abhängigkeiten,
so wie sie in ihrer Schnittstelle ausgedrückt sind, und sie versucht
automatisch alle dort ausgedrückten Abhängigkeiten
aufzulösen,
das heißt
der Komponente alle von ihr benötigten
Funktionalitäten bereitzustellen
und ebenso das System der Abhängigkeiten "abzuschließen", indem sie für jede in
dieser Weise eingesetzte Komponente ebenfalls versucht die von ihr
selbst benötigten
Funktionalitäten
bereitzustellen.
-
Die
GD lädt
dann automatisch die Komponenten, die die importierten Schnittstellen
mit der Eigenschaft "loadtime" auflösen, in
den Verknüpfungsgraphen,
löst ebenfalls
ihre Abhängigkeiten
auf und erzeugt in Abhängigkeit
von ihren jeweiligen Einsatzorten die Kommunikationskanäle zwischen
den verschiedenen Komponenten.
-
Ein
Kommunikationskanal kann dabei entsprechend jedem Kommunikationsmodus,
wie er weiter oben definiert ist, erzeugt werden; er wird durch
einen beliebigen Datenübertragungsweg
gebildet (spezifisch für
jeden Kommunikationsmodus), der dazu fähig ist den Aufruf einer Funktionalität mit den
zugehörigen
Parametern und das Einholen des oder der Rückgabewerte, die sich aus der
von der Funktionalität
ausgeführten Verarbeitung
ergeben, durchzuführen.
-
Sobald
die Kommunikationskanäle
erzeugt sind, können
die Komponenten direkt untereinander kommunizieren.
-
Dynamisches Laden und
Entfernen von Komponenten
-
Wenn
eine importierte Schnittstelle die Eigenschaft "runtime" hat, fordert die Komponente, die diese Schnittstelle
verwendet, das Laden der Komponente, die diese Schnittstelle implementiert,
nur an, wenn diese Komponente die der Schnittstelle zugeordnete
Funktionalität
benötigt.
Diese Eigenschaft "runtime" ist somit eine Alternative
zur bereits beschriebenen Eigenschaft "loadtime".
-
Diese
Verwaltung gestattet es, die Eigenschaften der Implementierung der
Schnittstelle, die geladen werden soll, genau zu bestimmten und
dies in Abhängigkeit
von dynamischen Parametern, die beim Laden der die Funktionalität anfragenden
Komponente nicht bekannt sind.
-
Beispielsweise
kann eine Komponente "Text" eine Codec-Schnittstelle
importieren, um die Dateien, die sie übermittelt bekommt, zu dekomprimieren,
wobei diese "Text"-Komponente mehrere
Dateitypen erhalten kann.
-
Beim
Erhalt einer Datei kann die "Text"-Komponente die zur
Dekomprimierung dieser Datei fähige
Codec-Schnittstelle suchen, beispielsweise in Abhängigkeit
von deren Erweiterung. Hierfür
verwendet sie die Funktionalität
Query() der Verwaltung der Abhängigkeiten,
wobei dieser die Suchparameter übergeben
werden.
-
Daraufhin
kann sie der Verwaltung der Abhängigkeiten
mittels der Funktionalität
Open() die Anweisung geben die Komponente zu laden. Sie kann dann
die Codec-Schnittstelle dieser Komponente verwenden, um die Datei
zu dekomprimieren.
-
Wenn
die Dekomprimierung abgeschlossen ist, kann die "Text"-Komponente
das Entfernen der verwendeten Codec-Komponente anfordern.
-
Es
ist somit möglich
eine Komponente dynamisch zu laden. Diese Möglichkeit gestattet es, Komponenten
erst dann zu laden, wenn sie zum Ausführen einer Verarbeitung notwendig
sind. Wenn ihre Verarbeitung abgeschlossen ist, kann die Komponente
anschließend
entfernt werden.
-
Entsprechend
einem anderen Beispiel kann eine Anwendung bei ihrem Laden ein Bild
anzeigen, muß jedoch
anschließend
keine Bilder von diesem Format mehr verarbeiten oder nur in Ausnahmefällen.
-
Diese
Anwendung kann daher die Komponente zur Verarbeitung des Bildformats
dynamisch laden, sie dazu veranlassen die Datei zu bearbeiten um
das Bild anzuzeigen, und anschließend diese Komponente entfernen.
Die Komponente wird erst in den Speicher geladen, wenn es unbedingt
notwendig ist, was es gestattet, die Speicherressourcen zu einem
gegebenen Zeitpunkt in Abhängigkeit
von den auszuführenden
Verarbeitungen zwischen den verschiedenen Komponenten aufzuteilen.
-
Dieses
Verfahren gestattet es damit, die notwendigen Speicherressourcen
erheblich zu verringern.
-
Die
Verwaltung der Abhängigkeiten
kann ebenfalls automatisch das Laden und Entfernen von Komponenten
verwalten, in Abhängigkeit
von deren Verwendungsstatistik und den Speicherressourcen. Diese
Verwaltung wird dann für
den Programmierer der Anwendung vollständig transparent.
-
Die
Schemazeichnung der 8 zeigt
die Bedeutung der dynamischen Komponentenverwaltung auf einem System,
daß über geringe
Speicherressourcen verfügt.
In diesem Beispiel zeigt die Anwendung zwei Bilder an, ein GIF und
ein JPEG. Die Bilder werden nacheinander verarbeitet, was es gestattet,
die Komponenten dynamisch zu laden und zu entfernen.
-
In
diesem Beispiel gestattet es die Tatsache, daß die Komponenten dynamisch
geladen und entfernt werden, die maximal notwendige Speicherressource
zu verringern.
-
Außerdem ist
dieses Laden und Entfernen in der Mehrzahl der Fälle in der Leistung nicht spürbar.
-
Tatsächlich haben
die Komponentenmodule eine reduzierte Größe (in der Größenordnung
von einigen hundert Byte bis einigen Kilobyte). Ihr Laden in den
Speicher ist daher ein Vorgang, der sehr schnell durchführbar ist.
Außerdem
führt die
Mehrzahl der Anwendungen sequentielle Verarbeitungen aus und die
Eingabeinformationen werden oft von einem menschlichen Benutzer
bereitgestellt und die Ausgabeinformationen werden dem Benutzer
bereitgestellt.
-
Auf
der menschlichen Skala sind die wenigen, zum Laden und Entfernen
einer Komponente notwendigen Mikrosekunden sogar nicht wahrnehmbar;
im Fall des in 8 dargestellten
Beispiels werden die Vorgänge
entsprechend der folgenden Abfolge durchgeführt:
- – Laden
eines Bildes (Laden des JPEG-Codes),
- – Anzeigen
dieses Bildes auf dem Bildschirm,
- – Benutzer,
- – Laden
eines weiteren Bildes (Entfernen des JPEG-Codes und Laden des GIF-Codes),
- – Anzeigen
dieses weiteren Bildes.
-
Die
Zeit zum Laden und Entfernen ist in Bezug auf die anderen Verarbeitungen
unbedeutend.
-
Optimierung der Ressourcen
durch die Verwaltung der Abhängigkeiten
-
Die
Verwaltung der Abhängigkeiten
verwaltet für
jede Komponente einen Referenzzähler.
Dieser Zähler
zählt die
Anzahl der "Importeure" der Komponente,
das heißt
von Komponenten, die eine Funktionalität der dem Zähler zugeordneten Komponente
importieren. Eine Komponente wird entfernt, sobald ihr Referenzzähler auf
0 abgenommen hat.
-
Wenn
eine Komponente nicht mehr verwendet wird, gibt die Verwaltung der
Abhängigkeiten
automatisch die für
diese Komponente verwendeten Ressourcen frei.
-
Es
ist zu bemerken, daß die
Erfindung es somit gestattet, in besonders effizienter Weise die
vom System eingesetzten Ressourcen zu optimieren, ohne das allgemeine
Funktionieren des Systems zu belasten.
-
Tatsächlich setzen
die bekannten Systeme im allgemeinen periodisch arbeitende Mittel
zum Überprüfen des
Zustands der Komponenten ein, wobei die Mittel von einem speziellen
Task, der periodisch die Kontrolle erlangt, eingesetzt werden, derart,
daß die
zu entfernenden Komponenten bestimmt werden.
-
Ein
solcher periodischer Überprüfungstask
ist schlecht an Echtzeitanforderungen angepaßt, da er es nicht gestattet,
den Veränderungen
des Zustands der Komponenten mit einer guten Reaktionsfähigkeit
zu folgen.
-
Außerdem erfordert
diese Funktionsweise aufgrund des Vorhandenseins des Überprüfungstasks
eine Multitaskingumgebung.
-
Eine
Ausführung
dieser Funktionsweise, die eine periodische Überprüfung einsetzt, befindet sich
in der Sprache Java, wobei der Überprüfungstask
ein Element vom Typ "Garbage
Collector" einsetzt.
-
Genauere Angaben zu den
von einem Hardwareelement realisierten Funktionalitäten
-
Es
wurde bereits gesagt, daß der
Implementierungsteil einer Komponente einem Code entsprechen kann
(der ein oder mehrere Programme umfaßt, um die Funktionalität der Komponente
zu erfüllen),
jedoch ebenso einer Hardwareimplementierung durch Hardwareelemente,
die elektronische Schaltungen umfassen.
-
So
kann eine Funktionalität
von einer Komponente C1 realisiert werden, die sie unter Verwendung
einer elektronischen Schaltung implementiert (beispielsweise eine
Videodekomprimierungsschaltung). Diese Funktionalität kann jedoch
ebenso von einer Komponente C'1
realisiert werden, die sie vollständig als Software implementiert.
Wenn für
eine Anwendung die elektronische Schaltung vorhanden ist und richtig
funktioniert, verwendet das System die Komponente C1. Wenn dagegen
die elektronische Schaltung nicht vorhanden ist oder wenn sie nicht
richtig funktioniert, verwendet das System die Komponente C'1 und dies in einer
für die anderen
Komponenten transparenten Weise. In jedem Fall wird die Funktionalität ausgeführt.
-
Ebenso
kann eine Funktionalität,
die heute durch einen Softwarecode realisiert wird, später in einer
für die
anderen Komponenten vollständig
transparenten Weise durch eine Komponente realisiert werden, die
sie unter Verwendung einer elektrischen Schaltung implementiert.
-
Die
Schemazeichnung in 9 stellt
das Ersetzen einer Komponente C1 durch eine andere Komponente C'1 dar, die dieselbe
Funktionalität
exportiert.
-
Während C1
gerade ausgeführt
wird, wie in 900 angedeutet, fordert eine Komponente C2,
die einen Kommunikationskanal mit C1 besitzt und mit dieser somit
im Verknüpfungsgraphen
verbunden ist, in 901 bei der GD das Ersetzen von C1 durch
C'1 an.
-
Die
GD veranlaßt
dann C1 dazu ihren augenblicklichen Zustand zu sichern (Phase 902),
was C1 in 903 ausführt.
Die GD lädt
und initialisiert anschließend
C'1 (904 und 905).
-
Wenn
das Laden oder das Initialisieren von C'1 nicht richtig ausgeführt wurden
(Phase 906), gibt die GD einen Fehler an den Anfrager C2
zurück.
-
Wenn
das Laden und das Initialisieren von C'1 richtig abgelaufen sind, überträgt die GD
in 908 den augenblicklichen Zustand von C1 nach C'1, damit C'1 sich in denselben
Zustand versetzt.
-
Hierfür wertet
C'1 den übermittelten
augenblicklichen Zustand (909) aus und akzeptiert oder
verwirft ihn (910).
-
Wenn
sie ihn verwirft, entfernt die GD C'1 (911) und setzt sie zurück (912).
Die GD gibt anschließend eine
Fehlermeldung an den Anfrager C2 zurück (913 und 914).
-
Wenn
dagegen C'1 den
augenblicklichen Zustand von C1 akzeptiert, aktualisiert die GD
ihren Graphen (916), indem sie C1 durch C'1 ersetzt. Anschließend baut
sie die Kommunikationskanäle
für C'1 wieder auf (917);
diese Kanäle
sind diejenigen, die für
C1 verwendet wurden. Anschließend
setzt die GD C1 zurück
und entfernt sie (918 und 919).
-
Wenn
die Ersetzung richtig ausgeführt
wurde, informiert die GD C2 davon (920, 921);
diese kann ihre Verarbeitung fortsetzen.
-
Oben
wurde das Prinzip des erfindungsgemäßen Systems und seine Umsetzung
beschrieben (unter anderem mit Bezug auf 6).
-
Es
sei klargestellt, daß es
ebenfalls möglich
ist, die Schnittstelle der Komponente C1 so zu parametrieren, daß wenn die
GD eine Komponente sucht, die eine von C1 importierte Funktionalität exportiert,
sie in einer der Phase 627 in 6 entsprechenden Phase ihre Suche in
der Gesamtheit der in das System geladenen Komponenten ausführt und
an C1 eine "Ansicht" jeder Komponente
des Verknüpfungsgraphen übermittelt, die
diese Funktionalität
exportiert.
-
In
Abhängigkeit
von parametrierten Auswahlkriterien kann C1 dann die Komponente
auswählen,
die ihr unter den von der GD bestimmten paßt.
-
Es
sei ebenfalls klargestellt, daß das
erfindungsgemäße System
in seiner aktuellen Version zum Funktionieren minimal vier Komponenten
benötigt,
wie in 10a dargestellt
ist (in der die Pfeile die zwischen Komponenten übermittelten Funktionalitäten anzeigen – dieser
Figurentyp ist somit eine Repräsentation
des Verknüpfungsgraphen).
-
Es
handelt sich um die folgenden Komponenten:
- – "Interaktion", die wie bereits
gesagt wurde zum Anstoßen
der Funktion des Systems notwendig ist,
- – "Shuttle", die von "Interaktion" aufgerufen wird
und die ihrerseits die beiden folgenden Komponenten aufruft:
- – die
GD,
- – und
schließlich "VMM", Speicher- oder
Speicherverwaltungskomponente genannt, die ebenfalls die GD aufruft.
-
10b zeigt eine ebenfalls
minimale Konfiguration des Systems, in der drei Komponenten "CPU", "TIMER" und "SCHED" hinzugefügt wurden,
um eine Multithreadverwaltung zu ermöglichen.
-
Schließlich stellt 10c eine erweiterte Konfiguration
eines erfindungsgemäßen Systems
dar, die eine kleine Anwendung bildet.
-
In
dieser Figur verwendet die Komponente "Interaktion" eine Kommunikationskomponente "COM" zum Datenaustausch
auf einem Netz und sie verwendet die Komponente "GUI" (grafische
Schnittstelle) zur Anzeige grafischer Darstellungen.
-
Die
Komponente "MAUS" gestattet die Verwaltung
der MAUS-Peripherie. Sie übermittelt
Informationen über
Zustandsveränderungen
dieses Peripheriegeräts
(Verschiebung, Klick auf die Tasten). Die Komponente "GUI" verwendet die Komponenten "WINDOW" und "BUTTON" zur Realisierung
der von der Komponente "INTERAKTION" angeforderten Anzeigevorgänge.
-
Die
Komponenten "WINDOW" und "BUTTON" verwenden die Codec-Komponenten GIF und
JPEG zur Anzeige von Bildern in ihren jeweiligen Anzeigebereichen.
-
Die
Komponenten GUI, COM, WINDOW, BUTTON, GIF und JPEG verwenden gleichermaßen Funktionalitäten der
Basiskomponenten des Systems. Allerdings sind die zu diesen Funktionalitäten gehörenden Verknüpfungen
nicht in der Schemazeichnung der 10c repräsentiert,
um diese Figur nicht zu überladen.
-
Die
Komponenten sind in Domänen
eingeteilt, die Gruppen sind, die nicht einer Privilegienstufe entsprechen,
sondern einem Verwendungstyp. Verschiedene Domänen sind die folgenden, mit
bestimmten zugeordneten Komponenten:
-
-
Es
ist zu bemerken, daß aufgrund
der Tatsache, daß alle
Komponenten des erfindungsgemäßen Systems
entsprechend demselben Format realisiert sind, das System alle Komponenten
in derselben Weise verwaltet und die oben erwähnten vorteilhaften Eigenschaften
beziehen sich in derselben Weise auf alle Komponenten, unabhängig von
ihrer Privilegienstufe.
-
Es
wird schließlich
deutlich, daß erfindungsgemäße System
folgendes gestattet:
- – dem Programmierer, eine synthetische
Ansicht aller Elemente des Betriebssystems, unabhängig von
deren Privilegienstufe,
- – die
Verwendung derselben Werkzeuge zum Erzeugen dieser verschiedenen
Elemente,
- – die
Realisierung von Zusammenschaltungen zwischen den verschiedenen
Teilen ohne Einschränkungen. Die
Leistungsfähigkeit
des Systems wird nicht durch die Anzahl seiner Komponenten, sondern
die Anzahl der möglichen
Zusammenschaltungen ausgedrückt,
wobei in den herkömmlichen
Systemen (monolithische genauso wie Mikrokern) die Kommunikationsmittel
zwischen den verschiedenen Teilen begrenzt und starr sind. Systematisch
muß über einen
willkürlichen
Engpaß gegangen
werden (die Systemaufrufe liegen für den Kernel in begrenzter
Anzahl vor, sowohl für
monolithische Kernels, wie auch für Mikrokerne, etc.). Die Verwaltung
der Abhängigkeiten
und das dynamische Erzeugen von Kommunikationsmitteln gestatten
es, sich von dieser Beschränkung
zu befreien,
- – das
Bereitstellen gleicher Eigenschaften für alle Codetypen. Im Fall der
Erfindung ist es tatsächlich
nicht mehr notwendig ein Verwaltungssystem für Kernelmodule, für die Bibliothek
oder selbst für "Plug-Ins" von Anwendungen
vorzusehen. All dies wird durch das System der Komponentenverwaltung
ersetzt,
- – das
zukünftige
Erzeugen ebenso vieler Komponenten wie Funktionalitäten, die
zu erfüllen
sind. Dies gestattet es dem erfindungsgemäßen System vollständig veränderbar
zu sein.
-
Außerdem bietet
die Erfindung, wie wir in der obenstehenden Beschreibung gesehen
habe, dem Entwickler eine hohe Lesbarkeit und eine Reaktionsfähigkeit,
indem bei zahlreichen Vorkommnissen Fehlermeldungen zurückgegeben
werden.
-
Tatsächlich wird
beim Laden einer Komponente automatisch eine Funktion (Init) für diese
Komponente ausgeführt.
Diese Funktion (Init) überprüft, ob die
Gesamtheit der Komponenten, die für das Funktionieren der geladenen
Komponenten notwendig sind, auch in das System geladen ist. Für den Fall,
daß diese Überprüfung nicht
zufriedenstellend ist (wenigstens eine angefragte Funktionalität wird nicht
erfüllt
oder eine Komponente, die eine erforderliche Funktionalität anbietet,
ist einem defekten Hardwareelement zugeordnet, etc.), wird eine Fehlermeldung
an den Aufrufenden zurückgegeben.
-
Falls
eine aufgerufene Komponente einem defekten Element (Hardware und/oder
Software) zugeordnet ist, wird diese außerdem automatisch aus dem
Arbeitsspeicher des Systems entfernt.
-
Außerdem wurde
mit Bezug auf 9 ersichtlich,
daß ebenso
beim Aufruf von Komponenten Fehlermeldungen zurückgegeben werden.
-
Falls
ein für
das Funktionieren einer aufrufenden Komponente notwendiges Hardware-
oder Softwareelement fehlt oder defekt ist, gestattet es eine Fehlermeldung
hierüber
informiert zu sein, ohne daß ein
vollständiger
Testvorgang des Systems notwendig ist.