home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
pascal
/
bp7os2
/
os2rtl
/
sys
/
wmem.asm
< prev
next >
Wrap
Assembly Source File
|
1993-08-16
|
18KB
|
392 lines
;//////////////////////////////////////////////////////
;/ /
;/ Run-time Library für Borland Pascal 7.0 unter OS/2 /
;/ Heap-Memory-Manager. /
;/ /
;/ 1993 Matthias Withopf / c't /
;/ Originalversion (c) 1988,92 Borland International /
;/ /
;//////////////////////////////////////////////////////
.286p
_NOMACROS_ = 1 ; keine Macros definieren
INCLUDE SE.ASM
INCLUDE OS2.ASM
; Header jedes Heap-Segments.
hsSignature EQU (WORD PTR 0)
hsReserved EQU (WORD PTR 2)
hsFreeList EQU (BYTE PTR 4)
hsMemFree EQU (WORD PTR 8)
hsNextHeap EQU (WORD PTR 10)
hsHeapOrg EQU (BYTE PTR 12)
; Header jedes Heap-Blocks.
hbNext EQU (WORD PTR 0)
hbSize EQU (WORD PTR 2)
DATA SEGMENT WORD PUBLIC
EXTRN HeapList:WORD,HeapLimit:WORD,HeapBlock:WORD
EXTRN HeapError:DWORD,HeapAllocFlags:WORD
AllocSize DW ? ; Lokale Variable
DATA ENDS
CODE SEGMENT BYTE PUBLIC
ASSUME CS:CODE,DS:DATA
EXTRN HaltError:NEAR
;
; Procedure New(Var p : Pointer);
; Procedure GetMem(Var p : Pointer;Size : Word);
;
PUBLIC NewPtr
NewPtr PROC PASCAL FAR
ARG A_Size : WORD
MOV AX,A_Size ; lese Größe des Speicherblocks
CALL NewMemory ; fordere Speicher an
JC @@Error ; falls nicht genügend Speicher -> Fehler
RET
@@Error: LEAVE ; verlasse den Stack-Frame
MOV AX,203 ; Fehler: 'Heap overflow error'
JMP HaltError
NewPtr ENDP
;
; Procedure Dispose(Var p : Pointer);
; Procedure FreeMem(Var p : Pointer;Size : Word);
;
PUBLIC DisposePtr
DisposePtr PROC PASCAL FAR
ARG A_Ptr : DWORD, \
A_Size : WORD
MOV AX,A_Size ; lese Größe des Speicherblocks
MOV CX,A_Ptr.offs ; lese Zeiger auf den
MOV BX,A_Ptr.segm ; freizugebenden Speicherblock
CALL DisMemory ; gebe Speicher frei
JC MemError ; falls nicht ok -> Fehler
RET
DisposePtr ENDP
;
; Procedure Mark(Var p : Pointer);
; Procedure Release(Var p : Pointer);
;
PUBLIC MarkPtr
PUBLIC ReleasePtr
MarkPtr:
MemError:
ReleasePtr:
MOV AX,204 ; Fehler: 'Invalid pointer operation'
JMP HaltError
;
; Function MemAvail : LongInt;
;
PUBLIC GetFreMem
GetFreMem PROC PASCAL FAR
LOCAL L_AvailMem : DWORD
LEA BX,L_AvailMem ; lese Zeiger
PUSH SS ; auf Speicher für
PUSH BX ; Größe des freien Speichers
CALL DosMemAvail ; erfrage freien Speicher
MOV AX,L_AvailMem.offs ; lese Größe des
MOV DX,L_AvailMem.segm ; freien Speichers in DX/AX
MOV CX,HeapList ; lese Segment der Heap-Liste
JCXZ @@End ; falls keine Blöcke alloziert -> Ende
@@Loop: MOV ES,CX ; setze Segment des Heap-Segements
ADD AX,ES:hsMemFree ; addiere freier Speicher
ADC DX,0 ; des Heap-Segments
MOV CX,ES:hsNextHeap ; lese Segment des nächsten Heap-Segments
CMP CX,HeapList ; ist zu Ende ?
JNE @@Loop ; nein -> zurück und weiter suchen
@@End: RET
GetFreMem ENDP
;
; Function MaxAvail : LongInt;
;
PUBLIC GetFreMax
GetFreMax PROC PASCAL FAR
LOCAL L_AvailMem : DWORD
LEA BX,L_AvailMem ; lese Zeiger
PUSH SS ; auf Speicher für
PUSH BX ; Größe des freien Speichers
CALL DosMemAvail ; erfrage freien Speicher
MOV AX,L_AvailMem.offs ; lese Größe des
MOV DX,L_AvailMem.segm ; freien Speichers in DX/AX
OR DX,DX ; mehr als 64K ?
JNE @@End ; ja -> Ende
MOV CX,HeapList ; lese Segment der Heap-Liste
JCXZ @@End ; falls keine Blöcke alloziert -> Ende
@@Loop: MOV ES,CX ; setze Segment des Heap-Segements
CMP AX,ES:hsMemFree ; falls in diesem Heap-Segment mehr
JAE @@LessMem ; Speicher frei ist als auf OS/2-Heap
MOV AX,ES:hsMemFree ; -> lese freie Speichermenge
@@LessMem: MOV CX,ES:hsNextHeap ; lese Segment des nächsten Heap-Segments
CMP CX,HeapList ; ist zu Ende ?
JNE @@Loop ; nein -> zurück und weiter suchen
@@End: RET
GetFreMax ENDP
;
; Alloziere einen Speicherblock, dessen Größe in AX
; übergeben wird.
; Falls am Ende das Carry-Flag gelöscht ist, enthält
; DX:AX den Zeiger auf den Speicherblock (oder Nil),
; anderenfalls ist ein Fehler aufgetreten.
;
PUBLIC NewMemory
NewMemory PROC NEAR
OR AX,AX ; soll Block der Größe 0 angefordert werden ?
JE @@ReturnNil ; ja -> gebe Nil zurück
MOV AllocSize,AX ; speichere Blockgröße
@@Retry: CMP AX,HeapLimit ; ist es ein 'Small Block' ?
JB @@AllocSmall ; ja -> weiter
CALL NewGlobal ; fordere einen globalen Block an
JNC @@End ; falls ok -> Ende
CMP HeapLimit,0 ; ist 'Sub-Allocation' deaktiviert ?
JE @@HeapError ; ja -> rufe HeapError-Funktion auf
MOV AX,AllocSize ; lese gewünschte Blockgröße
MOV BX,HeapBlock ; lese Größe eines globalen Blocks
SUB BX,hsHeapOrg
CMP AX,BX
JA @@HeapError
CALL NewHeapMem
JMP SHORT @@ChkHeapErr ; -> teste auf Fehler
; Fordere einen 'Small Block' an.
@@AllocSmall: CALL NewHeapMem
JNC @@End ; falls ok -> Ende
MOV AX,AllocSize ; lese gewünschte Blockgröße
CALL NewGlobal ; fordere einen globalen Block an
@@ChkHeapErr: JNC @@End ; falls ok -> Ende
@@HeapError: MOV AX,HeapError.offs ; ist eine
OR AX,HeapError.segm ; HeapError-Funktion definiert ?
JE @@NoErrFunc ; nein -> weiter
PUSH AllocSize ; rufe die HeapError-Funktion mit
CALL HeapError ; der gewünschten Blockgröße auf
@@NoErrFunc: CMP AX,1 ; lese Ergebnis der HeapError-Funktion
MOV AX,AllocSize ; lese gewünschte Größe des Blocks
JA @@Retry ; falls nochmals versuchen -> zurück
JB @@End ; falls Runtime error -> Ende mit gesetztem Carry
@@ReturnNil: XOR AX,AX ; lese Nil-Zeiger
CWD ; (0:0) in DX:AX
@@End: RET
NewMemory ENDP
;
; Alloziere einen Block (Größe in AX) auf dem OS/2-Heap.
; Falls das Carry gelöscht ist, wird in DX:AX ein
; Zeiger auf den Speicherblock zurückgegeben.
;
NewGlobal PROC PASCAL NEAR
LOCAL L_Sel : WORD
PUSH AX ; übergebe die gewünschte Größe
LEA BX,L_Sel ; übergebe Zeiger auf
PUSH SS ; Speicher für ein Word,
PUSH BX ; in dem der Selektor zurückgegeben wird
PUSH HeapAllocFlags ; übergebe Allozierungs-Flags
CALL DosAllocSeg ; fordere Speicher an
OR AX,AX ; Fehler aufgetreten ?
JNZ @@Error ; ja -> Fehler
MOV DX,L_Sel ; lese Zeiger auf neuen
XOR AX,AX ; Block in DX:AX, Carry gelöscht
RET
@@Error: STC ; setze Fehlerflag
RET
NewGlobal ENDP
;
; Allocate heap block
; In AX = Block size
; Out DX:AX = Block pointer
; CF = 1 if error
;
NewHeapMem PROC NEAR
ADD AX,3 ; runde gewünschte Blockgröße
AND AL,0FCH ; auf nächstes Vielfaches von 4 auf
MOV CX,HeapList
JCXZ @@2
@@1: MOV ES,CX
CALL NewBlock
JNC @@Ok ; falls ok -> gebe Zeiger zurück
MOV CX,ES:hsNextHeap
CMP CX,HeapList
JNE @@1
@@2: CALL NewSegment
JC @@Exit ; falls Fehler -> Ende
CALL NewBlock
@@Ok: MOV HeapList,ES
MOV AX,BX ; gebe den Zeiger auf den
MOV DX,ES ; Block in DX:AX zurück
@@Exit: RET
NewHeapMem ENDP
;
; Allocate heap segment
; Out ES = Heap segment
; CF = 1 if error
;
NewSegment PROC NEAR
PUSH AX ; rette Akku
MOV AX,HeapBlock ; lese Größe eines globalen Blocks
CALL NewGlobal ; fordere einen globalen Block an
JC @@Error ; falls Fehler -> Ende
MOV ES,DX ; lese Zeiger auf das neue
XOR DI,DI ; Heap-Segment in ES:DI
CLD ; setze Signatur
MOV AX,'PT' ; in
STOSW ; hsSignature
XOR AX,AX ; lösche
STOSW ; hsReserved
MOV AX,hsHeapOrg
STOSW ; hsFreeList.hbNext
XOR AX,AX
STOSW ; hsFreeList.hbSize
MOV AX,HeapBlock ; lese Größe eines globalen Blocks
SUB AX,hsHeapOrg
STOSW ; hsMemFree
PUSH AX
MOV AX,ES
MOV CX,HeapList
JCXZ @@1
PUSH DS
MOV DS,CX
XCHG AX,DS:hsNextHeap
POP DS
@@1: STOSW ; hsNextHeap
XOR AX,AX
STOSW ; hbNext
POP AX
STOSW ; hbSize
@@Error: POP AX
RET
NewSegment ENDP
;
; Allocate block from heap segment
; In AX = Block size
; ES = Heap segment
; Out BX = Block offset
; CF = 1 if error
;
NewBlock PROC NEAR
MOV BX,hsFreeList
@@1: MOV SI,BX
MOV BX,ES:[BX].hbNext
CMP BX,1
JB @@Exit
MOV DX,ES:[BX].hbSize
SUB DX,AX
JB @@1
MOV CX,ES:[BX].hbNext
JE @@2
MOV DI,BX
ADD DI,AX
MOV ES:[DI].hbNext,CX
MOV ES:[DI].hbSize,DX
MOV CX,DI
@@2: MOV ES:[SI].hbNext,CX
SUB ES:hsMemFree,AX
CLC
@@Exit: RET
NewBlock ENDP
;
; Dispose memory
; In AX = Block size
; BX:CX = Block pointer
; Out CF = 1 if error
;
PUBLIC DisMemory
DisMemory PROC NEAR
OR AX,AX ; soll Block der Größe 0 freigegeben werden ?
JE @@End ; ja -> Ende
JCXZ @@FreeGlobal ; falls globalen Block freigeben -> weiter
ADD AX,3 ; runde Blockgröße auf nächstes
AND AL,0FCH ; Vielfache von 4 auf
MOV ES,BX ; lese Zeiger auf freizugebenden
MOV BX,CX ; Block in ES:BX
CMP ES:hsSignature,'PT' ; hat der Block gültige Signatur 'TP' ?
JNE @@Error ; nein -> Fehler
TEST BL,3 ; ist Block auf DWORD-Grenze aligned ?
JNE @@Error ; nein -> Fehler
MOV SI,hsFreeList ; lese Offset der Frei-Liste
@@1: MOV DI,SI ; rette Offset
MOV SI,ES:[SI].hbNext ; lese Offset des nächsten Blocks
OR SI,SI ; Ende der Liste erreicht ?
JE @@2 ; ja -> weiter
CMP BX,SI ; ist freizugebender Block gefunden ?
JA @@1 ; nein -> zurück
JE @@Error
@@2: MOV ES:[BX].hbNext,SI
MOV ES:[BX].hbSize,AX
ADD AX,ES:hsMemFree
MOV ES:hsMemFree,AX
ADD AX,hsHeapOrg
CMP AX,HeapBlock ; vergleiche mit Größe für einen globalen Block
JE @@7
CALL @@3
MOV ES:[DI].hbNext,BX
MOV BX,DI
@@3: MOV SI,BX
ADD SI,ES:[BX].hbSize
CMP SI,ES:[BX].hbNext
JNE @@End
MOV AX,ES:[SI].hbNext
MOV ES:[BX].hbNext,AX
MOV AX,ES:[SI].hbSize
ADD ES:[BX].hbSize,AX
@@End: CLC ; lösche Fehlerflag
RET
@@Error: STC ; setze Fehlerflag
RET
@@FreeGlobal: MOV AX,DS ; soll Datensegment als Heap-Block
CMP AX,BX ; freigegeben werden ?
JE @@Error ; ja -> Fehler
PUSH BX ; übergebe Selektor des Blocks
CALL DosFreeSeg ; gebe globalen Block frei
CLC ; lösche Fehlerflag
RET
@@7: XOR AX,AX
MOV BX,ES
MOV DX,ES:hsNextHeap
CMP BX,DX
JE @@9
MOV AX,HeapList
@@8: MOV ES,AX
MOV AX,ES:hsNextHeap
CMP AX,BX
JNE @@8
MOV ES:hsNextHeap,DX
MOV AX,ES
@@9: MOV HeapList,AX
JMP @@FreeGlobal ; -> globalen Block freigeben
DisMemory ENDP
CODE ENDS
END