home *** CD-ROM | disk | FTP | other *** search
- UNIT bigheap;
- {
- BIGHEAP.PAS
-
- Neue Version von GetMem und FreeMem, um Speicherblöcke
- zuzuweisen, die größer als 65520 Byte sind.
-
- Diese Routinen können benutzt werden, um Heap-Speicherblöcke
- zu handhaben, die größer als die maximal erlaubten bei den
- vordefinierten GetMem und FreeMem sind. Sie sind besonders
- nützlich bei Grafik-Bildpuffern, die leicht 65520 Byte
- überschreiten können.
- }
-
- {===============================================================}
- INTERFACE
- {===============================================================}
-
-
- VAR HeapError : Pointer; { Prozedur für Heap-Fehler }
-
- { Neue Blockversion der Heap-Handhabungsprozeduren }
- PROCEDURE GetMem ( VAR p : Pointer; nachfrage : LongInt );
- PROCEDURE FreeMem( VAR p : Pointer; groesse : LongInt );
-
- {===============================================================}
- IMPLEMENTATION
- {===============================================================}
-
-
- TYPE
- { Verschiedene Records werden benutzt, um auf die Segment- und
- Offsetteile des Zeigers zuzugreifen
- }
- zeiger_rec = RECORD CASE Integer OF
- 1 : ( p : Pointer );
- 2 : ( w : RECORD
- offset,
- segment : Word
- END
- );
- END;
-
- { Elemente der freien Liste }
- frei_rec = RECORD
- anfang, { zeigt zum Anfang des freien Blocks }
- ende { zeigt zum Ende des freien Blocks }
- : Pointer;
- END;
-
- frei_list = ARRAY[0..8189] OF frei_rec;
- zfrei_list = ^frei_list;
-
- { Typ der neuen Heap-Fehlerfunktion }
- heap_fehlerfunktion = FUNCTION( s : LongInt ) : Integer;
-
- { Typ der alten Heap-Fehlerfunktion }
- alte_heap_fehlerfunktion = FUNCTION( s : Word ) : Integer;
-
- CONST
- groesster_block = 65520;
-
- {=============== anz_frei ====================================
- gibt die Blockanzahl in der freien Liste zurück
- }
- FUNCTION anz_frei : Integer;
- BEGIN
- anz_frei := (8192 - Ofs(FreePtr^) DIV 8) MOD 8192;
- END;
-
-
- {=============== veraend_form ======================================
- ergibt die veränderte Form eines Zeigers
- }
- FUNCTION veraend_form( p : Pointer ) : LongInt;
- VAR zwang : zeiger_rec; { Record für Zeigerumwandlung }
- BEGIN
- zwang.p := p;
- veraend_form := (LongInt(zwang.w.segment) SHL 4) + zwang.w.offset;
- END;
-
-
- {=============== normal_form =====================================
- ergibt die normale Form eines Zeigers
- }
- FUNCTION normal_form( p : Pointer ) : Pointer;
- VAR zwang : zeiger_rec; { Record für Zeigerumwandlung }
- BEGIN
- zwang.p := p;
- zwang.w.segment := zwang.w.segment SHL 12 + (zwang.w.offset SHR 4);
- zwang.w.offset := zwang.w.offset AND $f;
- normal_form := zwang.p;
- END;
-
-
- {=============== erh_normal ====================================
- erhöht einen "normalen" Zeiger
- }
- PROCEDURE erh_normal( VAR p : Pointer; erhoehen : LongInt);
- BEGIN
- p := normal_form( Pointer(veraend_form(p) + erhoehen) );
- END;
-
-
- {=============== diff_normal =================================
- ergibt die Differenz zwischen den zwei "normalen" Zeigern
- }
- FUNCTION diff_normal( p1, p2 : Pointer ) : LongInt;
- BEGIN
- diff_normal := veraend_form(p1) - veraend_form(p2);
- END;
-
-
- {=============== frei_blockgroesse ===============================
- ergibt die Größe eines freien Blocks
- }
- FUNCTION frei_blockgroesse( block : frei_rec ) : LongInt;
- BEGIN
- frei_blockgroesse := diff_normal( block.ende, block.anfang);
- END;
-
-
- {=============== block_entfernen ==================================
- entfernt einen Block von der freien Liste
- }
- PROCEDURE block_entfernen( VAR block : frei_rec );
- TYPE
- union = RECORD CASE Integer OF
- 1 : ( p : Pointer );
- 2 : ( fl_zgr : zfrei_list );
- 3 : ( w : RECORD offset, segment : Word END );
- END;
- VAR zwang : union; { Record für Zeigerumwandlung }
- BEGIN
- zwang.p := FreePtr;
- block := zwang.fl_zgr^[0];
- FreePtr := Ptr( zwang.w.segment, zwang.w.offset + SizeOf(frei_rec) );
- END;
-
-
- {=============== pool_groesse =====================================
- ergibt die Größe des freien Pools
- }
- FUNCTION pool_groesse : LongInt;
- VAR zwang : zeiger_rec; { Record für Zeigerumwandlung }
- BEGIN
- zwang.p := FreePtr;
- IF (zwang.w.offset = 0) THEN Inc( zwang.w.segment, $1000 );
- pool_groesse := diff_normal( zwang.p, HeapPtr );
- END;
-
-
- {=============== FAR-Heapfunktionen ============================}
-
- {$F+}
-
- {=============== heap_funktion =================================
- Neue Vorgabe-Funktion für HeapErr
- 0 bedeutet Abbruch mit Laufzeit-Fehler 203
- }
- FUNCTION heap_funktion( groesse : LongInt ) : Integer;
- BEGIN
- heap_funktion := 0;
- END;
-
- {=============== kleine_heap_funktion ===========================
- ersetzt alte HeapErr-Funkion
- ruft die neue Heapfehler-Funktion auf (oder die vom Benutzer
- bestimmte Ersetzungsfunktion)
- HINWEIS: benutzt einen Typzwang um die Funktion in der
- HeapError-Globalvariablen aufzurufen
- }
- FUNCTION kleine_heap_funktion( groesse : Word ) : Integer;
- BEGIN
- kleine_heap_funktion := heap_fehlerfunktion(HeapError)(groesse);
- END;
-
- {$F-}
- {=============== Ende der FAR-Heapfunktionen =====================}
-
-
-
- {=============== GetMem ========================================
- längere Version von GetMem
- }
- PROCEDURE GetMem( VAR p : Pointer; nachfrage : LongInt);
- LABEL
- Nochmals, Schneiden;
- VAR
- fl_zgr : zfrei_list;
- letzter_Block, anz : Integer;
- aktion : Integer;
- BEGIN
- { Normale Heaproutinen benutzen, falls Nachfrage klein ist }
- IF (nachfrage <= groesster_block) THEN
- BEGIN
- System.GetMem( p, Word(nachfrage) );
- Exit;
- END;
-
- { Auf Eingang in freie Liste prüfen, die groß genug für den
- Block ist
- }
- Nochmals:
- letzter_Block := anz_frei;
- IF (letzter_Block = 0) THEN { keine freien Blöcke }
- GOTO Schneiden;
-
- fl_zgr := FreePtr;
- FOR anz := 0 TO letzter_Block - 1 DO
- IF (frei_blockgroesse( fl_zgr^[anz] ) >= nachfrage) THEN
- BEGIN
-
- { Block gefunden, in zwei Blöcke teilen }
- p := fl_zgr^[anz].anfang;
-
- { Startzeiger einstellen }
- erh_normal( fl_zgr^[anz].anfang, nachfrage );
-
- { der Block fällt aus der freien Liste, falls
- nichts übrig ist
- }
- IF (frei_blockgroesse( fl_zgr^[anz] ) = 0) THEN
- block_entfernen( fl_zgr^[anz] );
- { fertig }
- Exit;
- END;
-
- { Hier sind keine Blöcke der freien Liste groß genug.
- Sie müssen aus dem Pool "herausgeschnitten" werden.
- }
- Schneiden:
- { Genug Speicher im Pool? }
- IF (pool_groesse < nachfrage + FreeMin) THEN
- BEGIN
- { Nicht genug Speicher, HeapError-Funktion aufrufen
- Typzwang benutzen, um indirekten Aufruf durch die
- globale HeapError Zeigervariable zu machen.
- }
- aktion := heap_fehlerfunktion(HeapError)( nachfrage );
- CASE aktion OF
- 1 : { NIL-Zeiger zu Programm zurückgeben }
- BEGIN
- p := NIL;
- Exit;
- END;
- 2 : { Zuweisung wiederholen }
- GOTO Nochmals;
- ELSE { Heapüberlauf-Laufzeitfehler erstellen }
- RunError( 203 );
- END;
- END;
-
- { Es ist nun genug Speicher vorhanden }
- p := HeapPtr;
- erh_normal( HeapPtr, nachfrage );
- END;
-
-
- {=============== FreeMem ======================================
- längere Version von FreeMem
- }
- PROCEDURE FreeMem( VAR p : Pointer; groesse : LongInt);
- LABEL
- Wiederholen;
-
- BEGIN
- Wiederholen:
- IF (groesse <= groesster_block) THEN
- BEGIN
- System.FreeMem( p, Word(groesse) );
- Exit;
- END;
- System.FreeMem( p, groesster_block );
- erh_normal( p, groesster_block );
- Dec( groesse, groesster_block );
- GOTO Wiederholen;
- END;
-
-
-
- {=============== unit INITIALISATION ==========================}
- BEGIN
- HeapError := @heap_funktion;
- System.HeapError := @kleine_heap_funktion;
-
- { FreeMin anpassen, um Platz für FreeList zu schaffen, wenn die
- großen Blöcke zurückzugewiesen werden. (für 3 Eingänge der
- freien Liste
- }
- Inc( System.FreeMin, 3 * SizeOf( frei_rec ) );
- END.
-