📄 fhinit.asm
字号:
cEnd
;***
; B$FHAlloc - allocate a far heap entry (DOS 3 & 5)
;
;Purpose:
; Calls B$IFHAlloc to allocate an entry of the requested size.
; If the allocation attempt fails, an Out of Memory runtime error
; is issued.
;Entry:
; DX:AX = 32-bit size in bytes.
; BX = unallocated far heap descriptor for allocated entry.
;Exit:
; [BX].FHD_hData <> segment if allocated (0 if unallocated)
;Uses:
; None.
;Exceptions:
; Out of memory condition if allocation cannot be done.
;Note:
; For DOS 5 the cPara field is never altered by the
; Far Heap manager.
;******************************************************************************
cProc B$FHAlloc,<PUBLIC,NEAR>,<AX>
cBegin
cCall B$IFHAlloc ;call common allocation code
OR AX,AX ;did allocation succeed?
JNZ FHAllocSuccess ;brif no error
JMP B$ERR_OM_FH ;issue out of memory error if failed
FHAllocSuccess:
cEnd
;***
; B$IFHAlloc - allocate a far heap entry (return error code on fail)(DOS 3 & 5)
;
;Purpose:
; Allocates a far heap entry of the given size. The far heap is
; first scanned from its upper to lower boundary using a first-fit
; algorithm. If no space is found of sufficient size, a compaction
; is done and the resulting unallocated space is tested. If still
; no room, the near heap is shrunk and the space reclaimed to the
; far heap to provide the allocation.
;Entry:
; DX:AX = 32-bit size in bytes.
; BX = unallocated far heap descriptor for allocated entry.
;Exit:
; AX = zero if not enough memory is present for requested allocation.
; [BX].FHD_hData <> segment if allocated (0 if unallocated)
;Uses:
; None.
;Exceptions:
; None.
;Note:
; For DOS 5 the cPara field is never altered by the
; Far Heap manager.
;******************************************************************************
IFHAllocDone:
cProc B$IFHAlloc,<NEAR,PUBLIC>,<BX,CX,DX,SI,DI,ES>
cBegin
;This routine can cause movement of the near heap, thus potentially
;invalidating the entry pointer to this routine if it is in the near heap.
DbAssertRel BX,B,b$NH_first,<FH_TEXT>,<Attempted to Far alloc with owner in near heap>
; Convert size DX:AX from bytes to paragraphs.
CALL FHByteToPara ;change DX:AX bytes to paragraphs in DX:AX
OR DX,DX ;test if more than 1M bytes requested
JNZ FHAllocError ;if so, give error immediately
DbAssertRel AX,NZ,0,FH_TEXT,<Cannot B$FHAlloc a buffer of size 0>
; To allocate a far heap entry, a first-fit allocation is attempted.
; SI traverses down the far heap descriptor list. FHTryAlloc is used
; to determine if any unallocated space exists adjacent to the lower
; boundary of the far heap entry described by SI.
MOV SI,OFFSET DGROUP:b$FHDStart ;set pointer to first desc in list
FHAllocLoop:
CALL FHTryAlloc ;try to allocate AX para adjacent to desc at SI
JNC FHAllocDone ;if success, then jump to finish
MOV SI,[SI].FHD_pNext ;get pointer to next descriptor in the list
CMP SI,OFFSET DGROUP:b$FHDEnd ;test if final descriptor
JNZ FHAllocLoop ;if not last descriptor, then jump to try again
; If first-fit fails, next compact the far heap and test the resulting
; unallocated space.
CALL FHTryAllocCompact ; compact to combine the free areas,
; and try to allocate again
JNC FHAllocDone ;if success, then jump to finish
; If compaction fails, shrink the near heap enough to get the necessary
; room for the allocation.
MOV DX,AX ;save request amount in DX
CALL FHParaSize ;get size of unallocated entry in AX
SUB AX,DX ;compute negative of size needed yet...
NEG AX ;...now value is positive
CALL B$FHLowerBottom ;attempt to lower the FH bottom for more room
XCHG AX,DX ; [AX] = original allocation request
CALL FHTryAllocCompact ; compact to combine the free areas,
; and try to allocate again
JNC FHAllocDone ; if success, then jump to finish
; If there was not enough near heap space, then release user lib
; data images, recover released space and retry allocation.
PUSH AX ;save original allocation request
PUSH BX ; Save FHD
CALL B$ULDataRelease ;free UL data images (if present)
POP BX
POP AX ;[AX] = original allocation request
CALL FHTryAllocCompact ; compact to combine the free areas,
; and try to allocate again
JNC FHAllocDone ; it worked, don't keep trying!
; If there was STILL not enough space, then have the help engine close
; down to release the remaining memory that it has, and re-try.
PUSH AX ; save registers
PUSH BX
CALL CompressHelp ; have help engine shrink down to minimum
POP BX ; restore registers
POP AX
CALL FHTryAllocCompact ; compact to combine the free areas,
; and try to allocate again
NoHelpShrink:
JNC FHAllocDone ;if success, then return
FHAllocError:
XOR AX,AX ;return error code - no memory available
; Allocation succeeded - done.
FHAllocDone:
cEnd
;***
; FHByteToPara - convert size in bytes to paragraphs (DOS 3)
;
;Purpose:
; Shift the 32-bit value given right four times to compute
; paragraphs.
;Entry:
; DX:AX = 32-bit number of bytes
;Exit:
; DX:AX = 32-bit number of paragraphs
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc FHByteToPara,<NEAR>
cBegin
ADD AX,0FH ;round up DX:AX to the...
ADC DX,0 ;...nearest paragraph
SHR DX,1 ;shift DX:AX...
RCR AX,1 ;...once
SHR DX,1 ;and...
RCR AX,1 ;...twice
SHR DX,1 ;and...
RCR AX,1 ;...thrice
SHR DX,1 ;and...
RCR AX,1 ;...four times to get the paragraphs
cEnd
;***
; FHTryAlloc/FHTryAllocCompact - try to allocate after a specific entry (DOS 3)
;
;Purpose:
; Given a DGROUP offset to a far heap descriptor and its corresponding
; far heap entry, compute the size of the unallocated space adjacent
; to the lower boundary of the entry. Allocate the upper part of the
; space if large enough to satisfy the allocation request.
;
; FHTryAllocCompact added with revision [74] to compact far heap before
; trying to do the allocation.
;
;Entry:
; SI = DGROUP offset of allocated far heap descriptor to test
; for the adjacent unallocated entry.
; BX = DGROUP offset of unallocated far heap descriptor to be
; allocated.
; AX = Size of allocation request in paragraphs.
;Exit:
; CF clear = allocation successful - descriptor at BX filled
; and linked into the far heap descriptor list.
; CF set = allocation failed - descriptor at BX unchanged.
;Uses:
; BX, CX, DX, DI.
;Exceptions:
; None.
;******************************************************************************
cProc FHTryAllocCompact,<NEAR>
cBegin
cCall B$FHCompact ; compact the heap to combine new free
; areas
cEnd <nogen> ; fall into FHTryAlloc
cProc FHTryAlloc,<NEAR>,<AX>
cBegin
;DbAssertRel [BX].FHD_hData,z,0,FH_TEXT,<FHTryAlloc: entry already allocated>
; Determine the location and size of the unallocated region in the
; far heap by determining the lower boundary of the given allocated
; far heap entry and upper boundary of the next allocated far heap
; entry. The unallocated region is exclusively between these two
; values.
MOV DI,[SI].FHD_pNext ;get descriptor pointer of next heap entry
MOV DX,[SI].FHD_hData ;get start segment of given heap entry
MOV CX,[DI].FHD_hData ;get start segment of next heap entry
ADD CX,[DI].FHD_cPara ;add size to get seg past upper bound of next
SUB CX,DX ;compute negative size of unallocated region
NEG CX ;negate to get correct size
SUB DX,AX ;get allocated seg to be adjacent given entry
; Test if the unallocation region of size CX paragraphs is large
; enough to satisfy the allocation request of AX paragraphs. If
; not, then jump with carry set to exit.
CMP CX,AX ;test if region is large enough for allocation
JB FHTryFail ;jump with CARRY set for failure
; Allocation succeeded - new entry is AX paragraphs in length at
; DX:0. Note that the allocation is taken from the upper part of
; the unallocated region to try to minimize compaction. The new
; far heap descriptor segment and length is filled and is linked
; between the given and next descriptor in the list.
MOV [BX].FHD_hData,DX ;fill in segment value of new descriptor
MOV [BX].FHD_cPara,AX ;fill in paragraph size of new descriptor
MOV [BX].FHD_pNext,DI ;new descriptor is linked to next descriptor
MOV [SI].FHD_pNext,BX ;given descriptor is linked to new descriptor
; Clear the entry using B$FHMove with BX=DX. Return CARRY clear.
MOV BX,DX ;set equal so B$FHMove clears the entry
CALL B$FHMove ;clear the entry at DX:0 for AX paragraphs
CLC ;clear carry flag for success
FHTryFail:
cEnd
;***
;B$FHRealloc - Reallocate a far heap entry (DOS 3 & 5)
;
;Purpose:
; Dos 3 support added with revision [32].
; Added as part of revision [11].
; Reallocate a block of memory from DOS.
;Entry:
; DX:AX = 32-bit total size in bytes to reallocate.
; BX = DGROUP offset of FH descriptor.
;Exit:
; AX = 0 means reallocation failed.
;Uses:
; None.
;Exceptions:
; None.
;******************************************************************************
cProc B$FHRealloc,<PUBLIC,NEAR>,<SI,DI,ES>
localV FHDTmp,<SIZE FHD>
cBegin
MOV CX,AX ;save byte size of request in DI:CX
mov DI,dx
cCall FHByteToPara ;[DX:AX] = para size of request
DbAssertRel DX,Z,0,<FH_TEXT>,<Reallocation request too large after rounding in B$FHRealloc>
CMP AX,[BX].FHD_cPara ;are we growing this entry?
JBE RealcSaveSize ;brif not - save new size and exit
;This routine can cause movement of the near heap, thus potentially
;invalidating the entry pointer to this routine if it is in the near heap.
DbAssertRel BX,B,b$NH_first,<FH_TEXT>,<Attempted a Far realloc with owner in near heap>
; We need to grow the entry. Our reallocation strategy is:
;
; 1. Check the adjacent entry. If there is enough free space
; to satisfy the allocation, use it.
; 2. Try to allocate a new entry of the requested size. If
; successful, copy data to newly allocated heap entry, and
; change the owner of the entry to be the descriptor passed
; to us on entry to B$FHRealloc.
; 3. As a last resort, see if enough room exists for the additional
; amount requested. If so, then move all far heap entries
; from the requested entry to the last allocated entry, down
; by the additional amount. The requested entry can then
; reclaim the freed space to satisfy the allocation request.
; Check the adjacent entry for enough free space.
cCall FHPrevDesc ;[SI] = descriptor before [BX]
MOV DX,[SI].FHD_hData
SUB DX,[BX].FHD_hData ;[DX] = total paras available for allocation
CMP DX,AX ;is it enough to satisfy the request?
JB RealcNew ;brif not
RealcSaveSize:
; Enough free space exists between this entry and adjacent entry.
MOV [BX].FHD_cPara,AX ;update size
JMP SHORT RealcDone ;exit
RealcNew:
; Try to allocate a new entry of requested size.
XCHG AX,CX ;[AX]=low word of byte count, [CX]=para count
mov dx,di ; [DX:AX] = byte count of original request
PUSH BX ;save entry FHD
LEA BX,FHDTmp ;point to temp FHD
cCall B$IFHAlloc ;try to allocate a new entry
MOV SI,BX ;save new FHD
POP BX ;recover entry FHD
OR AX,AX ;was alloc successful?
JZ RealcPartial ;brif not, try to allocate incremental diff
; The allocation succeded. Copy the entry and change the owner.
MOV AX,[BX].FHD_cPara ;get size of original entry
PUSH BX ;save original FHD
MOV BX,[BX].FHD_hData ;get start of area to move
MOV DX,[SI].FHD_hData ;get destination
PUSH CX ;save para size of allocation
cCall B$FHMove ;move the data
POP CX ;recover para size of new allocation
POP BX ;recover entry FHD
cCall B$FHDealloc ;deallocate entry FHD
; Now make the entry FHD the owner of the newly allocated heap entry.
MOV AX,[SI].FHD_hData
MOV [BX].FHD_hData,AX ;update segment of allocation
MOV AX,[SI].FHD_pNext
MOV [BX].FHD_pNext,AX ;update ptr to next descriptor in chain
MOV [BX].FHD_cPara,CX ;update size of entry
PUSH BX ;save entry FHD
MOV BX,SI ;get FHD of newly allocated entry
cCall FHPrevDesc ;find the FHD which points to new FHD
POP BX ;recover entry FHD
MOV [SI].FHD_pNext,BX ;replace new FHD with entry FHD in chain
JMP SHORT RealcDone ;exit
RealcPartial:
; Check to see if enough room exists for current entry to expand
; Note: we are assuming that the attempted allocation above caused
; compaction of the far heap to high memory, leaving one free
; entry at the end of the far heap (lower memory).
SUB CX,[BX].FHD_cPara ;compute amount needed to grow entry
PUSH BX ;save entry FHD
MOV BX,OFFSET DGROUP:b$FHDEnd ;get ending heap descriptor
cCall FHPrevDesc ;find last allocated descriptor
MOV DI,SI ;[DI] = last allocated FHD
cCall FHParaSize ;[AX] = size of Free entry
POP BX ;recover entry FHD
CMP AX,CX ;does enough memory exist to satisfy allocation?
JNB RealcPartialOk ;brif so
XOR AX,AX ;return AX=0 meaning not enough memory
JMP SHORT RealcDone ;exit
RealcPartialOk:
; Enough memory exists. Move free space adjacent to current allocation
; and allocate it to the Entry FHD.
PUSH BX ;save entry FHD
PUSH CX ;save increment of allocation
MOV AX,[BX].FHD_hData ;get current start of allocation
ADD AX,[BX].FHD_cPara ;compute end of current allocation
MOV BX,[DI].FHD_hData ;get start of area to move
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -