Gemeinsame Bibliotheken (Shared Libraries) in MagiC ab V6.00
------------------------------------------------------------

Andreas Kromke
26.10.97
letzte nderung: 10.2.98
Tabulatorweite: 5


Anmerkung:	Shared Libraries wurden bereits mit Version 5.20
			eingefhrt. Aufgrund eines Designfehlers mute ich
			das Format der Bibliothek ab Version 6.00 ndern.
			Da unterschiedliche "magische" Kennungen verwendet
			werden, kann es aber nicht zu Abstrzen kommen,
			sondern die Bibliotheken fr 6.00 werden lediglich
			von der alten Version 5.20 nicht erkannt und
			umgekehrt. Aufgrund mehrerer Unzulnglichkeiten
			in der Version 5.20 sollten ohnehin nur
			Bibliotheken fr 6.00 erstellt werden.


1. Was sind Shared Libraries ?
==============================

Meist werden Bibliotheken mit hufig genutzten Prozeduren in einem 
eigenen Objektmodul zusammengefat und mit mehreren Programmen 
zusammengelinkt. Dabei erhlt jedes Programm eine Kopie der 
Bibliothek, die fest in die PRG-Datei integriert wird.
Shared Libraries dagegen existieren als eigene Dateien nur ein 
einziges Mal auf der Festplatte und werden von mehreren Programmen, 
auch gleichzeitig, verwendet.


2. Wozu Shared Libraries ?
==========================

Gegenber fest eingelinkten Bibliotheken ergeben sich eine Reihe von 
Vorteilen:

- Speicherplatzersparnis auf der Festplatte. Je mehr Programme 
  dieselben Bibliotheken verwenden, desto grer ist die Ersparnis.
- Speicherplatzersparnis im Hauptspeicher. Dies kommt erst dann zum 
  Tragen, wenn mehrere Programme gleichzeitig geladen sind, die 
  dieselbe Bibliothek verwenden.
- Systematische Wartung fr den Programmierer: Beim Update gengt es  
  mitunter, nur eine neue Bibliothek nachzureichen. Von diesem Update 
  profitieren dann alle Programme, die die Bibliothek verwenden.   
  Auerdem sind weniger Quelltexte zu warten. Wenn eine Bibliothek   
  verndert wurde, mssen nicht alle Programme, die sie verwenden, 
  neu bersetzt werden.

Natrlich gibt es auch Nachteile:

- Das Programmladen dauert etwas lnger. Jedoch nur, wenn die 
  Bibliothek noch nicht geladen ist.
- Es knnen sich Wechselwirkungen von Updates verschiedener Programme 
  ergeben. Beim Austausch einer Bibliothek knnen mehrere Programme 
  betroffen sein (positiv oder negativ).
- Bei der Installation eines Programms mssen Dateien in den XTENSION-
  bzw. den ersten in der Suchliste SLBPATH angegebenen Ordner (ab 
  MagiC 6) kopiert werden, es ist also nicht mehr ohne weiteres 
  nachvollziehbar, zu welchem Programm welche Shared Library gehrt.
  Abhilfe z.B.:

	- Nur Aliase in den XTENSION-Ordner bzw. den ersten durch die
	  Environment-Variable SLBPATH (s.u.) angegebenen Ordner legen.
	- SharedLibraries in einem Unterverzeichnis des Programms belassen
	  und lediglich die Environment-Variable SLBPATH in MAGX.INF
	  um dieses Verzeichnis erweitern (ab MagiC 6 mglich). Falls
	  noch keine Variable SLBPATH existiert, mu der XTENSION-Pfad dort
	  zunchst eingetragen werden.


3. Wie verwende ich eine Bibliothek ?
=====================================

Zunchst mal: Das ist ganz einfach. Als Beispiel steht das Programm 
SLC_DEMO ('C' steht fr Client).

Zunchst bentigt man zum Aufruf der beiden neuen DOS-Funktionen das 
Objektmodul SLB_BIND, dazu mu man die Datei SLB.H einbinden.

Fr jede benutzte Bibliothek deklariert man einen Deskriptor vom Typ 
SHARED_LIB und einen Funktionszeiger vom Typ SLB_EXEC.

Jede Bibliothek wird mit Slbopen() geffnet (das ffnen und Schlieen 
sollte nur im User-Modus erfolgen), dabei werden folgende Parameter 
bergeben:

	char *name		Der Name der Bibliothek, in Groschrift, 
					inkl. Extension (".SLB"). Der 	
					Bibliotheksname ist gleichzeitig Dateiname.
	char *path		Wenn dieser Parameter nicht NULL ist, wird 
					hier zuerst nach der Bibliothek gesucht (der 
					Pfad mu in MagiC 5.20 mit '\' abgeschlossen 
					sein; dies ist in MagiC 6 nicht mehr ntig).
					Der Pfad sollte absolut sein, damit die
					Shared Library wei, wo sie liegt.
					Wenn der Parameter NULL ist oder die 
					Bibliothek im angegebenen Pfad nicht 
					gefunden wurde, wird im XTENSION-Ordner 
					gesucht.
					Ab MagiC 6 wird die Environment-Variable
					SLBPATH ausgewertet. Sie enthlt wie PATH eine
					Liste der Suchpfade, jeweils durch ';' getrennt.
					Ist die Variable definiert, wird nicht mehr
					extra im XTENSION-Ordner gesucht.
	LONG min_ver		Minimal notwendige Versionsnummer der 
					Bibliothek.
					Wenn ein Programm etwa die Version 3 
					bentigt, die Bibliothek aber erst Version 2 
					ist, wird ERANGE zurckgegeben. Die 		
					tatschliche Versionsnummer der Bibliothek 
					wird als Rckgabewert geliefert.
	SHARED_LIB *sl		Zeiger auf den Deskriptor. Wenn die 
					Bibliothek geffnet wurde, wird hier der 
					Deskriptor eingetragen.
	SLB_EXEC *fn		Zeiger auf den Funktionszeiger. Wenn die 
					Bibliothek geffnet wurde, wird hier der 
					Funktionszeiger eingetragen.

Rckgabewert kann sein:

	>= 0				Alles OK, Versionsnummer der Bibliothek.
	ERANGE			Versionsnummer zu niedrig
	EACCDN			Bibliothek schon von diesem Proze geffnet
	EFILNF			Bibliothek nicht gefunden
	ENSMEM			zuwenig Speicher
	...				andere Fehlercodes.

Die Bibliothek kann nun verwendet und schlielich mit Slbclose() 
wieder geschlossen werden. Dies ist nicht unbedingt notwendig, da 
alle geffneten Bibliotheken bei Programmende automatisch geschlossen 
werden, aber es ist guter Programmierstil. Auf keinen Fall darf eine 
Bibliothek mehrmals geschlossen werden, der Kernel kann solche Fehler 
nicht erkennen.

Einige Bibliotheken, wie z.B. EDITOBJC.SLB, installieren neue 
Systemaufrufe, in diesem Fall die AES-Aufrufe 210..217. Fr diese 
Bibliotheken wird der Funktionszeiger nicht bentigt. Ansonsten 
werden alle Funktionen der Bibliothek ber den Funktionszeiger 
aufgerufen. Die Bibliotheks-Aufruf-Funktion ist folgendermaen 
deklariert:

 typedef LONG (cdecl *SLB_EXEC)( SHARED_LIB *sl, LONG fn,
 				WORD nargs, ... );

Da leider PureC hier einen Fehler hat, mute ich die Funktion 
notgedrungen deklarieren als "typedef LONG (*SLB_EXEC)( void , ... );"
Damit sind leider alle Typberprfungen verbaut. Also Vorsicht!!!

Der Aufruf erwartet folgende Parameter:

     Den Deskriptor der Bibliothek
     Ein Langwort (!!!) fr die Funktionsnummer
     Ein WORD, das die Anzahl der Argumente in WORDs
      (d.h. alle "..."-Argumente) angibt
     weitere Argumente je nach Funktion

Am besten geschieht der Aufruf ber ein Makro, das in einer 
Headerdatei fr die Bibliothek definiert werden sollte, z.B.:

JPEG.H:

#define SLBJPEG_WANDELN (a,b) (*slbjpeg_exec)(slbjpeg, 7L, 4, a, b)

Hierbei werden <slbjpeg_exec> und <slbjpeg> bei Slbopen() ermittelt, 
7L ist die Funktionsnummer fr den Aufruf WANDELN, 4 bezeichnet die 
Lnge der folgenden Argumente (a und b sind zwei Zeiger => 2*4 Bytes 
=> 4 WORDs), a und b sind die Argumente der Funktion WANDELN.

Wenn die Funktion nicht vorhanden ist (die Bibliothek enthlt fr 
diese Funktion einen Nullzeiger, oder die Funktionsnummer ist hher 
als die Anzahl der tatschlich vorhandenen Funktionen), erhlt man 
EINVFN als Funktionsergebnis (tatschlich klappt das erst ab MagiC 6
korrekt).


4. Wie schreibe ich eine Bibliothek?
====================================

Auch dazu gibt es eine Beispielbibliothek SLB_DEMO, die alle 
notwendigen Elemente und Beschreibungen enthlt.
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 fr 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 Hinzufgen von Funktionen mu darauf geachtet werden, die 
Funktionsanzahl entsprechend anzupassen und ggf. die Versionsnummer 
zu erhhen.
Bei ffentlich zugnglichen Shared Libraries ist sicherzustellen, da
dokumentierte Funktionsaufrufe nie gendert werden! Entweder sind neue
Parameter zu ergnzen (die aufgerufene Funktion kann die Anzahl der
tatschlich bergebenen Parameter abfragen), oder es ist eine neue
Funktionsnummer zu verwenden.
Fr die Funktionszeiger sind auch Nullzeiger zulssig, 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 ldt slb_init() eine Konfigurationsdatei, alloziert 
globalen Speicher fr die Bibliothek und ffnet eine virtuelle VDI-
Workstation. slb_exit() schreibt die Konfigurationsdatei zurck, gibt 
den Speicher wieder frei und schliet 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 erhlt die Bibliothek in der Kommandozeilen-Struktur der 
Basepage eine normale 'C'-Zeichenkette bergeben, welche den 
vollstndigen Pfad der SharedLibrary enthlt. 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, erhlt 
der Aufrufer EXCPT als Ergebnis des Slbopen()-Aufrufs. Um die 
unplanmige Terminierung der Bibliothek abzufangen, installiert der 
Kernel vor Aufruf von slb_init()/exit() einen etv_term-Handler fr 
die Bibliothek.

slb_open()/slb_close()
----------------------

Werden beim ffnen bzw. Schlieen der Bibliothek aufgerufen. Wenn die 
Bibliothek nur einmal geffnet 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 Supervisormodus 
erfolgt ist.

Die Bibliothek kann auch bei slb_open Speicher allozieren, dieser 
gehrt jedoch dem Aufrufer und sollte bei slb_close() wieder 
freigegeben werden. Um die Zuordnung von alloziertem Speicher zum 
Aufrufer zu ermglichen, 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 einhngen, die nach Beendigung wieder 
entfernt werden, i.a. werden jedoch Funktionen zur Verfgung gestellt.

Eine Funktion wird mit folgenden Parametern auf dem Stack aufgerufen:

	PD *pd		Proze-Deskriptor des Aufrufers, korrespondiert 
				mit dem zugehrigen 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 tatschliche Anzahl 
				ermittelt werden. Sehr praktisch bei 	
				Erweiterungen, ohne neue Funktionen einzubauen.
				Beispiel: Erwartet eine Funktion immer einen 
				Zeiger, optional aber noch ein WORD, erhlt sie 
				entweder 2 oder 3 als <nargs>.
	...			die brigen Parameter

Die Funktionen werden im Kontext des Aufrufers und mit dessen Stack 
ausgefhrt. Da dieser Aufruf i.a. im User-Modus erfolgt, wird das 
Multitasking auch bei lngeren 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 mssen ggf. gerettet werden. Insbesondere darf Register a2
nicht verndert werden, damit Routinen von PureC aus aufgerufen werden
knnen.
