Topic : TOS - das Betriebssystem Author : Version : tos.hyp (5. März 2013) Subject : Programmieren/Atari Nodes : 3001 Index Size : 93602 HCP-Version : 5 Compiled on : Atari @charset : atarist @lang : @default : Titel @help : @options : +g -i -s +x +zz -t4 @width : 70 View Ref-File11.23.4 Wie schreibe ich eine Shared Libraries? TOS Auch dazu gibt es eine Beispielbibliothek SLB_DEMO, die alle notwendigen Elemente und Beschreibungen enthält. Am besten, man kopiert SLB_DEMO.C, LIBHEAD.S und SLB_DEMO.PRJ und modifiziert die Dateien entsprechend. Es muß dringend darauf geachtet werden, daß Bit 3 der Flags im Programmheader einer Bibliothek gesetzt ist, dazu kann man PH_BIT3.TTP verwenden. LIBHEAD ist der Header für eine Shared Library. Der Zeiger auf die Funktionsnamen kann entfallen, ansonsten zeigt er auf eine Tabelle von Zeigern mit den Namen der Bibliotheksfunktionen. Die Anzahl der Funktionen muß korrekt festgelegt werden, ebenso die Tabelle der Funktionen und der Bibliotheksname, welcher mit dem Dateinamen identisch ist. Beim Hinzufügen von Funktionen muß darauf geachtet werden, die Funktionsanzahl entsprechend anzupassen und ggf. die Versionsnummer zu erhöhen. Bei öffentlich zugänglichen Shared Libraries ist sicherzustellen, daß dokumentierte Funktionsaufrufe nie geändert werden! Entweder sind neue Parameter zu ergänzen (die aufgerufene Funktion kann die Anzahl der tatsächlich übergebenen Parameter abfragen), oder es ist eine neue Funktionsnummer zu verwenden. Für die Funktionszeiger sind auch Nullzeiger zulässig, sie geben beim Aufruf der Funktion ein EINVFN. Folgende Funktionen zur (De-) Initialisierung sind obligatorisch: slb_init()/slb_exit() Werden beim Laden bzw. Entfernen der Bibliothek aufgerufen, und zwar im Supervisor-Modus und im Kontext (Prozeß) der Bibliothek. Typischerweise lädt slb_init() eine Konfigurationsdatei, alloziert globalen Speicher für die Bibliothek und öffnet eine virtuelle VDI- Workstation. slb_exit() schreibt die Konfigurationsdatei zurück, gibt den Speicher wieder frei und schließt die VDI-Workstation. Falls slb_init() eine Datei öffnet, darf auf das Handle erst wieder bei slb_exit() zugegriffen werden, da alle anderen Aufrufe der Bibliothek im Kontext des Aufrufers ablaufen. Ab MagiC 6 erhält die Bibliothek in der Kommandozeilen-Struktur der Basepage eine normale 'C'-Zeichenkette übergeben, welche den vollständigen Pfad der SharedLibrary enthält. Falls die SharedLibrary Konfigurations- oder RSC-Dateien laden muß, kann der Pfad extrahiert und der Dateiname der Konfigurationsdatei entsprechend zusammengebastelt werden. Falls slb_init() z.B. aufgrund eines Busfehlers beendet wird, erhält der Aufrufer EXCPT als Ergebnis des Slbopen()-Aufrufs. Um die unplanmäßige Terminierung der Bibliothek abzufangen, installiert der Kernel vor Aufruf von slb_init()/exit() einen etv_term-Handler für die Bibliothek. slb_open()/slb_close() Werden beim Öffnen bzw. Schließen der Bibliothek aufgerufen. Wenn die Bibliothek nur einmal geöffnet wird, ist die Reihenfolge: slb_init() slb_open() slb_close() slb_exit() Im Gegensatz zu slb_init()/slb_exit() laufen slb_open()/slb_close() im Kontext des Aufrufers und im Usermodus mit dem Userstack des Aufrufers ab, auch dann, wenn der Slbopen()-Aufruf im Supervisor-Modus erfolgt ist. Die Bibliothek kann auch bei slb_open Speicher allozieren, dieser gehört jedoch dem Aufrufer und sollte bei slb_close() wieder freigegeben werden. Um die Zuordnung von alloziertem Speicher zum Aufrufer zu ermöglichen, wird der Bibliothek bei slb_open(), slb_close() und bei jedem Funktionsaufruf der aktuelle Prozeß- Deskriptor mit übergeben. Achtung: Die Übergabe des PD an slb_open() und slb_close() geht aufgrund eines Bugs in 5.20 erst ab MagiC 6. Der Kernel stellt sicher, daß die open/close Aufrufe korrekt geschachtelt sind, d.h. ein Prozeß kann eine Bibliothek nicht mehrmals öffnen. Funktionen Funktionen sind nicht obligatorisch, so kann eine Bibliothek auch Systemaufrufe über AES oder DOS einhängen, die nach Beendigung wieder entfernt werden, i.a. werden jedoch Funktionen zur Verfügung gestellt. Eine Funktion wird mit folgenden Parametern auf dem Stack aufgerufen: PD *pd Prozeß-Deskriptor des Aufrufers, korrespondiert mit dem zugehörigen slb_open()/close() LONG fn Funktionsnummer. Praktisch, wenn mehrere Funktionen zusammengelegt sind (identische Funktionszeiger in LIBHEAD) WORD nargs Anzahl der folgenden Argumente, in WORDs. Hat eine Funktion eine variable Anzahl von Parametern, kann die tatsächliche Anzahl ermittelt werden. Sehr praktisch bei Erweiterungen, ohne neue Funktionen einzubauen. Beispiel: Erwartet eine Funktion immer einen Zeiger, optional aber noch ein WORD, erhält sie entweder 2 oder 3 als <nargs>. ... die übrigen Parameter Die Funktionen werden im Kontext des Aufrufers und mit dessen Stack ausgeführt. Da dieser Aufruf i.a. im User-Modus erfolgt, wird das Multitasking auch bei längeren Aktionen nicht unterbrochen. Das Funktions-Ergebnis kann je nach Funktion LONG, WORD, void usw. sein. Eine Funktion darf die Register d0-d2 und a0-a1 ändern, alle anderen Register müssen ggf. gerettet werden. Insbesondere darf Register a2 nicht verändert werden, damit Routinen von PureC aus aufgerufen werden können.