⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fhinit.asm

📁 [随书类]Dos6.0源代码
💻 ASM
📖 第 1 页 / 共 5 页
字号:
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 + -