You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1571 lines
66 KiB
1571 lines
66 KiB
TITLE GCOMPACT - Global memory compactor
|
|
|
|
.sall
|
|
.xlist
|
|
include kernel.inc
|
|
.list
|
|
|
|
WM_COMPACTING = 041h
|
|
|
|
.386p
|
|
|
|
include protect.inc
|
|
|
|
DataBegin
|
|
|
|
externB Kernel_Flags
|
|
externW WinFlags
|
|
externW Win386_Blocks
|
|
externW PagingFlags
|
|
externD gcompact_start
|
|
externD gcompact_timer
|
|
externD pPostMessage
|
|
externD NextCandidate
|
|
|
|
fSwitchStacks DB 0
|
|
fUpDown DB 0
|
|
|
|
DataEnd
|
|
|
|
externFP GlobalCompact
|
|
ifdef WOW
|
|
externFP VirtualFree
|
|
endif
|
|
|
|
sBegin CODE
|
|
assumes CS,CODE
|
|
assumes fs, nothing
|
|
|
|
externNP glrudel
|
|
externNP gmarkfree
|
|
externNP gcheckfree
|
|
externNP gdel_free
|
|
externNP gsplice
|
|
externNP gnotify
|
|
externNP genter
|
|
externNP gleave
|
|
externNP Enter_gmove_stack
|
|
externNP Leave_gmove_stack
|
|
|
|
if KDEBUG
|
|
externFP ValidateFreeSpaces
|
|
endif
|
|
|
|
externNP set_selector_address32
|
|
ifndef WOW_x86
|
|
externNP get_rover_232
|
|
endif
|
|
externNP AssociateSelector32
|
|
externNP alloc_arena_header
|
|
externNP free_arena_header
|
|
externNP mark_sel_NP
|
|
externNP PreAllocArena
|
|
externNP DPMIProc
|
|
externNP get_physical_address
|
|
|
|
if KDEBUG
|
|
externNP CheckGlobalHeap
|
|
endif
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gcompact ;
|
|
; ;
|
|
; Compacts the global heap. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DX = minimum #contiguous bytes needed ;
|
|
; DS:DI = address of global heap information ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = size of largest contiguous free block ;
|
|
; ES:DI = arena header of largest contiguous free block ;
|
|
; DX = minimum #contiguous bytes needed ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; SI ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; CX ;
|
|
; ;
|
|
; Calls: ;
|
|
; gcmpheap ;
|
|
; gcheckfree ;
|
|
; gdiscard ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Thu Sep 25, 1986 05:34:32p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc gcompact,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
CheckKernelDS fs
|
|
ReSetKernelDS fs
|
|
push esi
|
|
smov es,40h
|
|
mov ax,es:[6Ch] ; get the BIOS ticker count
|
|
sub gcompact_timer.lo,ax
|
|
or Kernel_Flags[1],kf1_MEMORYMOVED
|
|
|
|
mov si, [di].gi_cmpflags
|
|
push si
|
|
push si
|
|
test WinFlags[1], WF1_PAGING
|
|
jz short @F
|
|
; First time:
|
|
or [di].gi_cmpflags, GA_NOCOMPACT ; No movement
|
|
@@:
|
|
gcompactl:
|
|
if KDEBUG
|
|
call ValidateFreeSpaces
|
|
endif
|
|
push edx ; Save requested size
|
|
cmp [di].gi_reserve,edi ; Is there a reserve swap area?
|
|
je short gcompact1 ; No, then dont compact lower heap
|
|
mov esi,[di].phi_first ; Yes, compact lower heap
|
|
mov ebx,pga_next
|
|
call gcmpheap
|
|
gcompact1:
|
|
mov esi,[di].phi_last ; Compact upper heap
|
|
mov ebx,pga_prev
|
|
call gcmpheap
|
|
pop edx ; Get requested size
|
|
mov esi,eax ; ES points to largest free block
|
|
or eax,eax ; Did we find a free block?
|
|
jz short gcompact2 ; No, try discarding
|
|
call gcheckfree ; Yes, see if block big enough
|
|
jae short gcompactxx ; Yes, all done
|
|
gcompact2: ; Discarding allowed?
|
|
cmp [di].hi_freeze,di ; Heap frozen?
|
|
jne short gcompactxx ; Yes, return
|
|
test [di].gi_cmpflags,GA_NODISCARD
|
|
jnz short gcompactx ; No, return
|
|
test WinFlags[1], WF1_PAGING
|
|
jnz short @F
|
|
test [di].gi_cmpflags, GA_NOCOMPACT ; Ignore flag if paging
|
|
jnz short gcompactx
|
|
@@:
|
|
push esi
|
|
call gdiscard ; No, try discarding
|
|
pop ecx ; Saved ESI may be bogus if gdiscard
|
|
; discarded anything...
|
|
jnz short gcompactl ; Compact again if anything discarded
|
|
mov esi, ecx ; Nothing discarded so ES OK.
|
|
|
|
gcompactx:
|
|
test WinFlags[1], WF1_PAGING
|
|
jz short gcompactxx
|
|
pop si ; Original flags
|
|
mov [di].gi_cmpflags, si
|
|
or si, GA_NOCOMPACT+GA_NODISCARD
|
|
push si ; Abort next time
|
|
test [di].gi_cmpflags, GA_NOCOMPACT
|
|
jz short gcompactl
|
|
|
|
gcompactxx:
|
|
add sp,2 ; Toss working flags
|
|
push ax
|
|
push dx
|
|
push es
|
|
mov ax,40h
|
|
mov es,ax
|
|
mov ax,es:[6Ch]
|
|
mov si,ax
|
|
cmp pPostMessage.sel,0 ; is there a USER around yet?
|
|
jz short tock
|
|
add gcompact_timer.lo,ax
|
|
sub ax,gcompact_start.lo
|
|
cmp ax,546 ; 30 secs X 18.2 tics/second
|
|
jb short tock
|
|
cmp ax,1092 ; 60 secs
|
|
ja short tick
|
|
mov cx,gcompact_timer.lo ; poor resolution of timer!
|
|
jcxz short tick
|
|
xchg ax,cx
|
|
xor dx,dx
|
|
xchg ah,al ; shl 8 DX:AX
|
|
xchg dl,al
|
|
div cx
|
|
cmp ax,32 ; < 12.5% ?
|
|
jb short tick
|
|
mov ah,al
|
|
mov bx,-1 ; broadcast
|
|
mov cx,WM_COMPACTING
|
|
xor dx,dx
|
|
cCall pPostMessage,<bx, cx, ax, dx, dx>
|
|
tick: mov gcompact_start.lo,si
|
|
mov gcompact_timer.lo,0
|
|
tock: pop es
|
|
pop dx
|
|
pop ax
|
|
pop [di].gi_cmpflags
|
|
pop esi ; Restore SI
|
|
ret
|
|
UnSetKernelDS fs
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gcmpheap ;
|
|
; ;
|
|
; ;
|
|
; Arguments: ;
|
|
; EBX = pga_prev or pga_next ;
|
|
; EDX = minimum #contiguous bytes needed ;
|
|
; DS:DI = address of global heap information ;
|
|
; FS = Kernel DATA ;
|
|
; ;
|
|
; Returns: ;
|
|
; EAX = largest free block ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; AX,CX ;
|
|
; ;
|
|
; Calls: ;
|
|
; gslide ;
|
|
; gbestfit ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Thu Sep 25, 1986 05:38:16p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc gcmpheap,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
CheckKernelDS fs
|
|
ReSetKernelDS fs
|
|
mov NextCandidate, -1
|
|
xor eax,eax ; Nothing found yet
|
|
push eax ; Save largest free block so far
|
|
gchloop:
|
|
cmp ds:[esi].pga_owner,di
|
|
je short gchfreefnd
|
|
cmp ds:[esi].pga_owner, GA_NOT_THERE
|
|
jne short gchnext
|
|
mov NextCandidate, -1
|
|
gchnext:
|
|
mov esi, ds:[esi+ebx]
|
|
cmp esi, ds:[esi+ebx] ; Sentinel?
|
|
jne short gchloop ; no, continue
|
|
|
|
gchexit:
|
|
pop eax ; Return largest free block in AX
|
|
ret
|
|
|
|
gchfreefnd:
|
|
test [di].gi_cmpflags,GA_NOCOMPACT
|
|
jnz short gchmaxfree ; No, just compute max free.
|
|
cmp [di].hi_freeze,di ; Heap frozen?
|
|
jne short gchmaxfree ; Yes, just compute max free.
|
|
push esi
|
|
test [di].gi_cmpflags,COMPACT_ALLOC
|
|
jz short no_hack
|
|
call gcheckfree ; Allocating, this big enough?
|
|
jb short no_hack ; yes, STOP NOW!
|
|
cmp bl,pga_prev ; Compacting upper heap?
|
|
jnz short no_hack
|
|
test [di].gi_cmpflags,GA_DISCCODE
|
|
jz short no_hack
|
|
cmp edx,ds:[esi].pga_size
|
|
ja short no_hack
|
|
mov esi,ds:[esi].pga_next
|
|
test ds:[esi].pga_flags,GA_DISCCODE
|
|
jnz short hack
|
|
cmp ds:[esi].pga_owner,GA_SENTINAL
|
|
jz short hack
|
|
cmp ds:[esi].pga_owner,GA_NOT_THERE
|
|
jnz short no_hack
|
|
hack:
|
|
pop esi
|
|
pop eax
|
|
mov eax,esi
|
|
ret
|
|
|
|
no_hack:
|
|
pop esi
|
|
test byte ptr WinFlags[1], WF1_PAGING ; Paging?
|
|
jnz short best_it ; yes, don't slide
|
|
call PreAllocArena
|
|
jz short gchmaxfree
|
|
push edx
|
|
call gslide
|
|
pop edx
|
|
jnz short gchfreefnd
|
|
best_it:
|
|
push edx
|
|
call gfirstfit
|
|
pop edx
|
|
gchmaxfree:
|
|
cmp bl,pga_prev ; Compacting upper heap?
|
|
jne short gchnext ; No, dont compute largest free block
|
|
cmp ds:[esi].pga_owner,di ; Is current free?
|
|
jne gchnext ; No, ignore it then
|
|
pop eax ; Recover largest free block so far
|
|
push edx
|
|
cmp esi,eax ; Same as current?
|
|
je short gchmf2 ; Yes, no change then
|
|
push eax
|
|
cmp ds:[di].gi_reserve,edi ; Is there a code reserve area?
|
|
je short gchmf0 ; No, continue
|
|
test ds:[di].gi_cmpflags,GA_DISCCODE ; If allocating disc
|
|
jnz short gchmf0 ; code ignore the fence
|
|
mov ax, [di].gi_disfence_hi
|
|
shl eax, 16
|
|
mov ax, [di].gi_disfence_lo
|
|
mov edx, ds:[esi].pga_size ; Size of this block
|
|
add edx, ds:[esi].pga_address ; End of this block
|
|
sub eax, edx ; Fence above it?
|
|
jae short gchmf0 ; yes, use the whole block
|
|
neg eax ; Amount above the fence
|
|
cmp eax, ds:[di].gi_reserve ; Above reserve?
|
|
jae short gchmf0 ; yes, use all of it
|
|
sub edx, eax ; Subtract off that above fence
|
|
ja short gchmf00 ; Use as size of block
|
|
pop eax
|
|
jmps gchmf2
|
|
|
|
gchmf0:
|
|
mov edx, ds:[esi].pga_size ; Size of this block
|
|
gchmf00:
|
|
pop eax
|
|
or eax,eax ; First time?
|
|
jz short gchmf1 ; Yes, special case
|
|
cmp edx, ds:[eax].pga_size ; Is it bigger?
|
|
jb short gchmf2 ; No, do nothing
|
|
gchmf1:
|
|
mov eax,esi ; Yes, remember biggest free block
|
|
gchmf2:
|
|
pop edx
|
|
push eax ; Save largest free block so far
|
|
test PagingFlags, 2 ; Idle time compaction!
|
|
jnz gchexit
|
|
jmp gchnext ; Go process next block
|
|
UnSetKernelDS fs
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gslide ;
|
|
; ;
|
|
; Sees if next/previous block can slide into the passed free block. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; FS:ESI = free block ;
|
|
; DS:DI = address of global heap information ;
|
|
; CX = #arena entries left to examine ;
|
|
; EBX = pga_next or pga_prev ;
|
|
; ;
|
|
; Returns: ;
|
|
; ZF = 0 if block found and moved into passed free block ;
|
|
; FS:ESI points to new free block ;
|
|
; FS:EDX points to new free block ;
|
|
; ;
|
|
; ZF = 1 if no block found ;
|
|
; FS:ESI points to original free block ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; EAX,EDX ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Thu Sep 25, 1986 05:58:25p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc gslide,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push esi
|
|
mov esi,ds:[ebx+esi]
|
|
mov edx,esi ; Source of move in EDX
|
|
call gmoveable
|
|
pop esi
|
|
jz short gslide_no_move
|
|
call gmovebusy ; Handle exact fits etc!!
|
|
call gpagingcandidate
|
|
if KDEBUG
|
|
cmp edx, ds:[esi+ebx] ; Are we adjacent?
|
|
je short gslide_adjacent
|
|
int 3
|
|
int 3
|
|
gslide_adjacent:
|
|
endif
|
|
mov esi, edx
|
|
or esi, esi ; ZF = 0
|
|
gslide_no_move:
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gmove ;
|
|
; ;
|
|
; Moves a moveable block into the top part of a free block. The low ;
|
|
; order bit of the source and destination may be either set or reset. ;
|
|
; If set, then this routine does NOT move the arena header paragraph. ;
|
|
; If the bit is reset, then the arena header is moved. Only the low ;
|
|
; order bit of EDX is examined, and the low order bit of ESI is assumed ;
|
|
; to the same. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DS:DI = master object ;
|
|
; ES:0 = address of destination block ;
|
|
; FS:ESI = arena of destination block ;
|
|
; FS:EDX = arena of source block ;
|
|
; ECX = # bytes to move ;
|
|
; ;
|
|
; Returns: ;
|
|
; DS:DI = master object (it may have moved) ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,BX,CX,DX,DI,SI,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; none ;
|
|
; ;
|
|
; Calls: ;
|
|
; gnotify ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Thu Sep 25, 1986 03:31:51p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc gmove,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
CheckKernelDS fs
|
|
ReSetKernelDS fs
|
|
|
|
push es
|
|
pushad
|
|
|
|
mov eax, edx
|
|
push esi ; Save destination
|
|
mov edx, ecx ; # bytes passed in in ECX
|
|
mov bx, ds:[eax].pga_handle ; BX = handle of source
|
|
Handle_To_Sel bl
|
|
mov cx, bx ; CX = client data address of dest.
|
|
|
|
push eax
|
|
push edx ; Save #paragraphs
|
|
|
|
mov ax, GN_MOVE
|
|
push cx ; Save client data address
|
|
call gnotify ; Call global notify procedure
|
|
pop cx
|
|
|
|
pop edx ; EDX = #paragraphs to move
|
|
pop esi ; ESI = source arena
|
|
pop edi ; EDI = destination arena
|
|
|
|
; Save DS value AFTER call to gnotify, as the master object might be the
|
|
; block we are moving and thus changed by the global heap notify proc.
|
|
|
|
push gs
|
|
smov gs, ds
|
|
mov ax,ss ; Are we about to move the stack?
|
|
cmp ax,cx
|
|
mov cx,0 ; ...assume no
|
|
jne short stack_no_move
|
|
mov cx, ax ; Selector does not change!
|
|
call Enter_gmove_stack ; switch to temporary stack
|
|
stack_no_move:
|
|
mov fSwitchStacks,cl ; Remember if we switched
|
|
|
|
xor cx, cx ; Ready for result of compare
|
|
mov eax, gs:[edi].pga_address
|
|
cmp gs:[esi].pga_address, eax
|
|
adc ch, 0
|
|
mov fUpDown,ch
|
|
|
|
mov ecx, edx ; # bytes to move
|
|
shr ecx, 2 ; # dwords to move
|
|
jecxz all_done
|
|
cmp fUpDown, 0
|
|
jnz short move_it_up
|
|
|
|
; MOVE IT DOWN
|
|
|
|
cld
|
|
xor esi, esi
|
|
jmps move_it
|
|
|
|
move_it_up:
|
|
std
|
|
mov esi, ecx
|
|
dec esi
|
|
shl esi,2
|
|
|
|
move_it:
|
|
mov ds, bx ; DS:SI = first word in source block
|
|
mov edi, esi
|
|
ifdef WOW_x86
|
|
smov es,FLAT_SEL ; 23:EAX => pga_address or taget
|
|
add edi,eax
|
|
endif; WOW_x86
|
|
rep movs dword ptr [edi], dword ptr [esi]
|
|
; 386 BUG, ECX, ESI, EDI ARE NOW TRASHED
|
|
|
|
all_done:
|
|
smov ds, gs
|
|
cCall set_selector_address32,<bx,eax> ; Update source selector
|
|
|
|
cmp fSwitchStacks,cl ; Switch to new stack if any
|
|
je short move_exit
|
|
call Leave_gmove_stack
|
|
move_exit:
|
|
pop gs
|
|
|
|
popad
|
|
pop es
|
|
cld ; Protect people like MarkCl from themselves
|
|
ret
|
|
UnSetKernelDS fs
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gbestfit ;
|
|
; ;
|
|
; Searches for the largest moveable block that will fit in the passed ;
|
|
; free block. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DS:ESI = free block ;
|
|
; DS:DI = address of global heap information ;
|
|
; CX = #arena entries left to examine ;
|
|
; EBX = pga_next or pga_prev ;
|
|
; ;
|
|
; Returns: ;
|
|
; ZF = 1 if block found & moved into free block w/ no extra room. ;
|
|
; DS:ESI = busy block before/after new busy block. ;
|
|
; ;
|
|
; ZF = 0 if DS:ESI points to a free block, either the ;
|
|
; original one or what is left over after moving a block ;
|
|
; into it. ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; DX,SI ;
|
|
; ;
|
|
; Calls: ;
|
|
; gmoveable ;
|
|
; gmovebusy ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Thu Sep 25, 1986 05:52:12p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds,nothing
|
|
assumes es,nothing
|
|
|
|
cProc gfirstfit,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
CheckKernelDS fs
|
|
ReSetKernelDS fs
|
|
push ecx
|
|
mov edx, esi ; Save free block
|
|
|
|
gbfrestart:
|
|
call PreAllocArena ; Abort if no free arenas
|
|
jz short gbfabort
|
|
mov eax,ds:[edx].pga_size ; Compute max size to look for
|
|
jmps gbfnext
|
|
|
|
gbfloop:
|
|
cmp ds:[esi].pga_owner,di ; Is this block busy?
|
|
je short gbfnext ; No, continue
|
|
cmp ds:[esi].pga_size,eax ; Yes, is block bigger than max size?
|
|
ja short gbfnext ; Yes, continue
|
|
cmp ds:[esi].pga_owner,GA_NOT_THERE ; Is this even here?
|
|
je short gbfnext ; No, continue
|
|
call gmoveable ; Yes, is it moveable
|
|
jnz short gbffound
|
|
gbfnext: ; No, continue
|
|
mov esi, ds:[esi+ebx] ; Skip past this block
|
|
cmp esi, ds:[esi+ebx] ; Sentinel?
|
|
jne gbfloop
|
|
|
|
gbfabort:
|
|
mov esi, edx ; Return original free block in ESI
|
|
jmps gfirstfit1 ; Nothing found!
|
|
|
|
gbffound:
|
|
xchg edx, esi ; Source of move
|
|
call gmovebusy ; Yes, move it into free block
|
|
mov NextCandidate, -1
|
|
call gpagingcandidate
|
|
mov NextCandidate, -1
|
|
xchg esi, edx ; Put free block in esi
|
|
call gwin386discard
|
|
xchg esi, edx
|
|
|
|
cmp edx, ds:[esi+ebx] ; Blocks adjacent?
|
|
je short gfirstfit1 ; Yes, may have coalesced.
|
|
; Return busy block in ESI
|
|
|
|
mov esi, ds:[esi+ebx] ; Get block after busy block
|
|
cmp ds:[esi].pga_owner,di ; Is this block busy?
|
|
jne short gfirstfit1 ; Yes, fit was exact
|
|
xchg edx, esi ; EDX is new free block
|
|
jmps gbfrestart ; Start search from old busy block
|
|
|
|
gfirstfit1:
|
|
pop ecx
|
|
ret
|
|
UnSetKernelDS fs
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gmovebusy ;
|
|
; ;
|
|
; Subroutine to move a busy block to a free block of the same size, ;
|
|
; preserving the appropriate arena header fields, freeing the old ;
|
|
; busy block and updating the handle table entry to point to the ;
|
|
; new location of the block. ;
|
|
; ;
|
|
; [tonyg] ;
|
|
; The above has been inaccurate for a while - the destination is NOT ;
|
|
; necessarily free, NOR is it always the same size! ;
|
|
; ;
|
|
; It will now handle everything gslidecommon used to do! ;
|
|
; ;
|
|
; Arguments: ;
|
|
; BX = ga_prev or ga_next ;
|
|
; DS:EDX = old busy block location ;
|
|
; DS:ESI = new busy block location ;
|
|
; DS:DI = address of global heap information ;
|
|
; ;
|
|
; Returns: ;
|
|
; DS:ESI = points to new busy block arena header ;
|
|
; DS:EDX = points to free block where block used to be ;
|
|
; (may be coalesced) ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; EBX,ECX ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; EAX ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Mon Jun 22, 1987 11:39:56p -by- David N. Weise [davidw] ;
|
|
; Made it jump off to gslidecommon when appropriate. ;
|
|
; ;
|
|
; Mon Oct 27, 1986 10:17:16p -by- David N. Weise [davidw] ;
|
|
; Made the lru list be linked arenas, so we must keep the list correct ;
|
|
; here. ;
|
|
; ;
|
|
; Thu Sep 25, 1986 05:49:25p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc gmovebusy,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
if KDEBUG
|
|
cmp ds:[esi].pga_owner, GA_NOT_THERE
|
|
jne short @F
|
|
AAARRRGGGHHH:
|
|
int 3
|
|
int 3
|
|
@@:
|
|
cmp ds:[edx].pga_owner, GA_NOT_THERE
|
|
je AAARRRGGGHHH
|
|
endif
|
|
|
|
push ecx
|
|
mov ecx,ds:[edx].pga_size ; ECX = size of source
|
|
cmp ds:[esi].pga_owner,di ; Is destination busy?
|
|
jne gmbexactfit ; Yes, then don't create extra block
|
|
mov eax, ds:[esi].pga_freeprev
|
|
call gdel_free ; Take off free list now!
|
|
cmp ecx,ds:[esi].pga_size ; No, source and destination same size?
|
|
je short gmbexactfit ; Yes, then don't create extra block
|
|
jb short gmbsplice ; Destination is larger, split it
|
|
|
|
if KDEBUG
|
|
; MUST BE ADJACENT IF DESTINATION
|
|
cmp ds:[esi+ebx], edx ; SMALLER THAN SOURCE!!!
|
|
je short gmb_adjust
|
|
int 3
|
|
int 3
|
|
gmb_adjust:
|
|
endif
|
|
push ecx ; source length
|
|
push ds:[esi].pga_size ; destination length
|
|
cmp bl, pga_next
|
|
je short gmb_down
|
|
; Moving busy block up
|
|
mov eax, ds:[edx].pga_address ; Correct destination address
|
|
add eax, ds:[esi].pga_size
|
|
mov ds:[esi].pga_address, eax
|
|
call gmb_gmove
|
|
jmps gmb_adjusted
|
|
|
|
gmb_down: ; Moving busy block down
|
|
call gmb_gmove
|
|
mov ecx, ds:[esi].pga_address ; Correct new free block address
|
|
add ecx, ds:[edx].pga_size
|
|
mov ds:[edx].pga_address, ecx
|
|
|
|
gmb_adjusted:
|
|
pop ds:[edx].pga_size ; Swap sizes
|
|
pop ds:[esi].pga_size
|
|
jmps gmb_moved
|
|
|
|
gmbsplice:
|
|
push ecx
|
|
push edx
|
|
mov edx, ecx ; # bytes in block to make
|
|
cmp bl, pga_prev
|
|
je short gmb_backward
|
|
call gsplice ; Split the block
|
|
jmps gmb_spliced
|
|
|
|
gmb_backward:
|
|
neg edx
|
|
add edx, ds:[esi].pga_size ; Second block will be used
|
|
call gsplice
|
|
xchg esi, edx
|
|
|
|
gmb_spliced:
|
|
mov ds:[esi].pga_owner,1 ; Mark new block busy
|
|
push esi ; New free block
|
|
mov esi, edx ; Block to free
|
|
mov edx, eax
|
|
call gmarkfree
|
|
pop esi ; New free block
|
|
pop edx ; Source for copy
|
|
pop ecx
|
|
|
|
gmbexactfit:
|
|
call gmb_gmove
|
|
|
|
gmb_moved:
|
|
mov eax, esi
|
|
mov esi, edx
|
|
xor edx, edx
|
|
call gmarkfree ; Free old block
|
|
mov ecx,esi ; New free block
|
|
mov esi,eax ; New block
|
|
or dx,dx
|
|
jz short gmb1
|
|
mov ds:[esi].pga_handle,dx ; Set back link to handle in new block
|
|
cCall AssociateSelector32,<dx,esi> ; Associate with new arena
|
|
xor dx,dx ; Set Z flag
|
|
gmb1:
|
|
mov edx,ecx
|
|
gmbexit:
|
|
pop ecx
|
|
ret
|
|
cEnd nogen
|
|
|
|
;
|
|
; Common code for gmovebusy
|
|
;
|
|
cProc gmb_gmove,<PUBLIC,NEAR>
|
|
|
|
cBegin nogen
|
|
push ecx ; # bytes to move
|
|
push dword ptr ds:[edx].pga_count
|
|
push ds:[edx].pga_owner
|
|
push ds:[edx].pga_lruprev
|
|
push ds:[edx].pga_lrunext
|
|
|
|
pop ds:[esi].pga_lrunext ; Copy client words to new header
|
|
pop ds:[esi].pga_lruprev
|
|
pop ds:[esi].pga_owner
|
|
pop dword ptr ds:[esi].pga_count
|
|
cmp ds:[esi].pga_lruprev,edi
|
|
jz short no_link
|
|
cmp [di].gi_lruchain,edx
|
|
jnz short didnt_move_head
|
|
mov [di].gi_lruchain,esi
|
|
didnt_move_head:
|
|
mov ecx,ds:[edx].pga_lruprev
|
|
mov ds:[ecx].pga_lrunext,esi ; Update the lru list
|
|
mov ecx,ds:[edx].pga_lrunext
|
|
mov ds:[ecx].pga_lruprev,esi ; Update the lru list
|
|
no_link:
|
|
pop ecx
|
|
ifndef WOW_x86
|
|
call get_rover_232
|
|
endif
|
|
jmp gmove ; Move the client data
|
|
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gmoveable ;
|
|
; ;
|
|
; Tests if an ojbect is moveable. Non moveable blocks are: ;
|
|
; Fixed blocks, moveable blocks that are locked, moveable blocks ;
|
|
; going up, discardable code going down. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; FS:ESI = arena header of object ;
|
|
; DS:DI = address of global heap information ;
|
|
; BX = ga_next or ga_prev ;
|
|
; ;
|
|
; Returns: ;
|
|
; ZF = 0 if object moveable ;
|
|
; ZF = 1 if object not moveable ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; All ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; nothing ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Wed Oct 15, 1986 05:04:39p -by- David N. Weise [davidw] ;
|
|
; Moved he_count to ga_count. ;
|
|
; ;
|
|
; Thu Sep 25, 1986 05:42:17p -by- David N. Weise [davidw] ;
|
|
; Added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc gmoveable,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
test ds:[esi].pga_handle,GA_FIXED ; If no handle then fixed
|
|
jnz short gmfixed
|
|
|
|
cmp ds:[esi].pga_count,bh ; If locked then fixed
|
|
jne short gmfixed
|
|
|
|
test ds:[esi].pga_flags,GA_DISCCODE ; If discardable code
|
|
jz short gmnotcode
|
|
cmp bl,pga_next ; Discardable code can only
|
|
ret ; move up in memory
|
|
gmnotcode:
|
|
cmp [di].gi_reserve,edi ; If no reserved code area?
|
|
je short gmokay ; Then anything can move up
|
|
cmp bl,pga_prev ; Otherwise can only move down
|
|
ret ; in memory
|
|
gmfixed:
|
|
or bh,bh ; Return with ZF = 1 if
|
|
ret ; not moveable
|
|
gmokay:
|
|
or esi,esi
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; gdiscard ;
|
|
; ;
|
|
; Subroutine to walk LRU chain, discarding objects until the #paras ;
|
|
; discarded, plus the biggest free block is greater than the #paras ;
|
|
; we are looking for. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; EAX = size of largest free block so far ;
|
|
; EDX = minimum #bytes needed ;
|
|
; DS:DI = address of global heap information ;
|
|
; ;
|
|
; Returns: ;
|
|
; ZF = 0 if one or more objects discarded. ;
|
|
; ZF = 1 if no objects discarded. ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; AX,DX,DI ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; BX,CX,ES ;
|
|
; ;
|
|
; Calls: ;
|
|
; ;
|
|
; History: ;
|
|
; Mon Oct 27, 1986 09:34:45p -by- David N. Weise [davidw] ;
|
|
; The glru list was reworked to link the arenas, not using the handle ;
|
|
; table as a middle man. Because of this change glruprev was moved ;
|
|
; inline and the code shortened up again. ;
|
|
; ;
|
|
; Wed Oct 15, 1986 05:04:39p -by- David N. Weise [davidw] ;
|
|
; Moved he_count to ga_count. ;
|
|
; ;
|
|
; Thu Sep 25, 1986 05:45:31p -by- David N. Weise [davidw] ;
|
|
; Shortened it up a bit and added this nifty comment block. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc gdiscard,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push eax
|
|
push edx
|
|
|
|
mov [di].hi_ncompact,0 ; Clear compaction flag
|
|
sub edx,eax ; How much to discard before
|
|
mov [di].hi_distotal,edx ; compacting again.
|
|
|
|
xor ebx,ebx ; EBX = amount of DISCCODE below fence
|
|
test [di].gi_cmpflags,GA_DISCCODE
|
|
jnz short fence_not_in_effect0
|
|
|
|
mov cx,[di].gi_lrucount
|
|
jcxz fence_not_in_effect0 ; All done if LRU chain empty
|
|
|
|
mov ax, [di].gi_disfence_hi
|
|
shl eax, 16
|
|
mov ax, [di].gi_disfence_lo
|
|
push edx
|
|
mov edx, eax
|
|
add edx, ds:[edi].gi_reserve
|
|
mov esi,[di].gi_lruchain ; ESI -> most recently used (ga_lruprev
|
|
gdloop0: ; is the least recently used)
|
|
mov esi,ds:[esi].pga_lruprev ; Move to next block in LRU chain
|
|
test ds:[esi].pga_flags,GA_DISCCODE ; Discardable code?
|
|
jz short gdloop0a ; No, ignore
|
|
cmp edx, ds:[esi].pga_address
|
|
jbe short gdinclude
|
|
cmp eax, ds:[esi].pga_address ; Yes, is this code fenced off?
|
|
jbe short gdloop0a ; No, ignore
|
|
gdinclude:
|
|
add ebx,ds:[esi].pga_size ; Yes, accumulate size of discardable
|
|
gdloop0a: ; code below the fence
|
|
loop gdloop0
|
|
pop edx
|
|
|
|
fence_not_in_effect0:
|
|
mov esi,[di].gi_lruchain
|
|
cmp [di].gi_lrucount, 0
|
|
je short gdexit
|
|
push ds:[esi].pga_lruprev
|
|
push [di].gi_lrucount
|
|
gdloop:
|
|
pop cx
|
|
pop eax
|
|
jcxz gdexit ; No more see if we discarded anything
|
|
mov esi, eax ; ES on stack may be invalid if count 0
|
|
dec cx
|
|
push ds:[esi].pga_lruprev ; Save next handle from LRU chain
|
|
push cx
|
|
cmp ds:[esi].pga_count,0 ; Is this handle locked?
|
|
jne short gdloop ; Yes, ignore it then
|
|
test [di].gi_cmpflags,GA_DISCCODE
|
|
jnz short fence_not_in_effect
|
|
test ds:[esi].pga_flags,GA_DISCCODE
|
|
jz short fence_not_in_effect
|
|
or ebx,ebx ; Discardable code below fence?
|
|
jz short gdloop ; No, cant discard then
|
|
cmp ebx,ds:[esi].pga_size ; Yes, more than size of this block?
|
|
jb short gdloop ; No, cant discard then
|
|
sub ebx,ds:[esi].pga_size ; Yes, reduce size of code below fence
|
|
fence_not_in_effect:
|
|
push ebx
|
|
call DiscardCodeSegment
|
|
pop ebx
|
|
jnz short discarded_something
|
|
test [di].hi_ncompact,10h ; did a GlobalNotify proc free enough?
|
|
jz short gdloop
|
|
jmps enough_discarded
|
|
discarded_something:
|
|
test [di].hi_ncompact,10h ; did a GlobalNotify proc free enough?
|
|
jnz short enough_discarded
|
|
or [di].hi_ncompact,1 ; Remember we discarded something
|
|
sub [di].hi_distotal,eax ; Have we discarded enough yet?
|
|
ja short gdloop ; No, look at next handle
|
|
enough_discarded:
|
|
pop cx ; Flush enumeration counter
|
|
pop ecx ; and saved ESI
|
|
gdexit:
|
|
cmp [di].hi_ncompact,0 ; Return with Z flag set or clear
|
|
pop edx
|
|
pop eax
|
|
ret
|
|
cEnd nogen
|
|
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; DiscardCodeSegment ;
|
|
; ;
|
|
; Discards the given segment. Calls gnotify to fix stacks, entry ;
|
|
; points, thunks, and prologs. Then glrudel removes it from the lru ;
|
|
; list and gmarkfree finally gets rid of it. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; DS:DI => BurgerMaster ;
|
|
; ES = Address of segment to discard ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = size discarded ;
|
|
; ZF = 0 ok ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; DI,SI,DS,ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; BX,CX,DX ;
|
|
; ;
|
|
; Calls: ;
|
|
; gnotify ;
|
|
; glrudel ;
|
|
; gmarkfree ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
; Fri Jun 12, 1987 -by- Bob Matthews [bobm] ;
|
|
; Made FAR. ;
|
|
; ;
|
|
; Sun Apr 19, 1987 12:05:40p -by- David N. Weise [davidw] ;
|
|
; Moved it here from InitTask, so that FirstTime could use it. ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc DiscardCodeSegment,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push esi
|
|
mov bx,ds:[esi].pga_handle ; BX = handle
|
|
mov al,GN_DISCARD ; AX = GN_DISCARD
|
|
call gnotify
|
|
jz short cant_discard ; Skip this handle if not discardable
|
|
call glrudel ; Delete handle from LRU chain
|
|
push ds:[esi].pga_owner ; Save owner field
|
|
mov eax,ds:[esi].pga_size ; Save size
|
|
xor edx,edx
|
|
call gmarkfree ; Free the block associated with this handle
|
|
mov bx,dx
|
|
pop cx ; Owner
|
|
cCall mark_sel_NP,<bx,cx>
|
|
cant_discard:
|
|
pop esi
|
|
ret
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; ShrinkHeap ;
|
|
; ;
|
|
; Tries to return DPMI memory blocks to DPMI memory manager. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; ;
|
|
; Returns: ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; InnerShrinkHeap ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc ShrinkHeap,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
push ds
|
|
|
|
GENTER32
|
|
ReSetKernelDS FS
|
|
|
|
cCall InnerShrinkHeap
|
|
jnz short sh_maybe_more
|
|
|
|
and PagingFlags, NOT 8 ; Don't call back if # win386
|
|
; didn't change
|
|
sh_maybe_more:
|
|
|
|
GLEAVE32
|
|
UnSetKernelDS FS
|
|
pop ds
|
|
ret
|
|
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; InnerShrinkHeap ;
|
|
; ;
|
|
; Checks heap to see if there are any blocks to return to Win386 ;
|
|
; Compacts if there are Win386 blocks around AND there is more ;
|
|
; than 512k free. ;
|
|
; Returns any completely free Win386 block to Win386. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; FS = Kernel's DS ;
|
|
; EDI = 0 ;
|
|
; ;
|
|
; Returns: ;
|
|
; Z flag set if no blocks returned, Z clear if 1 or more returned.;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; All ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; ;
|
|
; Calls: ;
|
|
; UnlinkWin386Block ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc InnerShrinkHeap,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
CheckKernelDS FS
|
|
ReSetKernelDS FS
|
|
pushad
|
|
|
|
push Win386_Blocks
|
|
|
|
cmp Win386_Blocks, 0
|
|
je short sh_done
|
|
; First count up free blocks
|
|
mov esi, [edi].phi_first
|
|
scan_loop:
|
|
mov esi, [esi].pga_freenext
|
|
scan_next:
|
|
cmp esi, [esi].pga_next ; Sentinel?
|
|
je short sh_done ; yes, all done
|
|
|
|
mov ebx, [esi].pga_prev
|
|
cmp [ebx].pga_owner, GA_NOT_THERE
|
|
jne short scan_loop
|
|
mov ecx, [esi].pga_next
|
|
cmp [ecx].pga_owner, GA_NOT_THERE
|
|
jne short scan_loop
|
|
mov eax, [ecx].pga_next ; Block after NOT_THERE block
|
|
cmp eax, [eax].pga_next ; Sentinel?
|
|
je short sh_done ; yes, don't try to unlink
|
|
; Have block to return
|
|
push [esi].pga_freeprev ; Current block will be freed
|
|
|
|
cCall UnlinkWin386Block
|
|
|
|
pop esi ; Continue before block freed
|
|
jmps scan_loop
|
|
|
|
sh_done:
|
|
pop ax ; Starting value of Win386_Blocks
|
|
cmp ax, Win386_Blocks ; Set Z flag if heap didn't shrink
|
|
|
|
popad
|
|
UnSetKernelDS FS
|
|
ret
|
|
cEnd
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; UnlinkWin386Block ;
|
|
; ;
|
|
; Returns a block to Win386 and unlinks it from the heap. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; EBX Block previous to block to be unlinked ;
|
|
; ESI Block to be unlinked ;
|
|
; ECX Block after to block to be unlinked ;
|
|
; ;
|
|
; Returns: ;
|
|
; ESI Block previous to EBX ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; ECX, DX, EDI, DS, ES ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; EAX, EBX, EDX ;
|
|
; ;
|
|
; Calls: ;
|
|
; GlobalCompact ;
|
|
; UnlinkWin386Block ;
|
|
; ;
|
|
; History: ;
|
|
; ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc UnlinkWin386Block,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
|
|
CheckKernelDS FS
|
|
ReSetKernelDS FS
|
|
push dx
|
|
|
|
mov edx, [ecx].pga_next ; Block after all this
|
|
cmp edx, [edx].pga_next ; Last sentinel?
|
|
je RSHORT dont_do_it ; Never free last block
|
|
|
|
if KDEBUG
|
|
push edx
|
|
mov eax, [esi].pga_size
|
|
mov edx, eax
|
|
shr edx, 16
|
|
krDebugOut <DEB_TRACE OR DEB_krMemMan>, "UnlinkWin386Block: releasing #dx#AX bytes"
|
|
pop edx
|
|
endif
|
|
push esi
|
|
call gdel_free ; Remove from free list
|
|
ifdef WOW
|
|
push edx
|
|
push ebx
|
|
push ecx
|
|
mov eax,MEM_RELEASE
|
|
mov edi,[esi].pga_size
|
|
cCall VirtualFree,<[ebx].pga_lrunext,edi,eax>
|
|
pop ecx
|
|
pop ebx
|
|
pop edx
|
|
else
|
|
mov esi, [ebx].pga_lrunext ; Saved WIN386 handle
|
|
mov di, si
|
|
shr esi, 16 ; Put in SI:DI
|
|
DPMICALL 0502h ; Free Memory Block
|
|
endif; WOW
|
|
xor edi, edi
|
|
pop esi
|
|
|
|
dec Win386_Blocks
|
|
|
|
mov eax, [ebx].pga_prev ; Block before all this
|
|
mov [eax].pga_next, edx ; Unlink them.
|
|
mov [edx].pga_prev, eax
|
|
|
|
cCall free_arena_header,<ebx> ; Free the arena headers
|
|
cCall free_arena_header,<esi>
|
|
cCall free_arena_header,<ecx>
|
|
|
|
mov esi, eax ; For gfreeall
|
|
|
|
sub [edi].hi_count, 3
|
|
|
|
if KDEBUG
|
|
call CheckGlobalHeap
|
|
endif
|
|
|
|
dont_do_it:
|
|
pop dx
|
|
ret
|
|
UnSetKernelDS FS
|
|
|
|
cEnd nogen
|
|
|
|
cProc gpagingcandidate,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
CheckKernelDS FS
|
|
ReSetKernelDS FS
|
|
test byte ptr WinFlags[1], WF1_PAGING ; Paging?
|
|
jz short gpc_not_paging
|
|
pushad
|
|
mov ebx, ds:[esi].pga_address
|
|
mov esi, ds:[esi].pga_size
|
|
add esi, ebx ; End of region
|
|
shr ebx, 12
|
|
shr esi, 12
|
|
cmp ebx, NextCandidate
|
|
jb short gpc_use_this_page
|
|
mov ebx, NextCandidate ; Start the region here
|
|
gpc_use_this_page:
|
|
cmp esi, ebx
|
|
jne short call_win386
|
|
mov NextCandidate, ebx
|
|
jmps gpc_done
|
|
call_win386:
|
|
mov NextCandidate, -1
|
|
sub esi, ebx ; number of pages
|
|
mov di, si
|
|
shr esi, 16
|
|
mov cx, bx
|
|
shr ebx, 16
|
|
DPMICALL 0700h ; Page Candidate
|
|
gpc_done:
|
|
popad
|
|
gpc_not_paging:
|
|
ret
|
|
UnSetKernelDS FS
|
|
cEnd nogen
|
|
|
|
assumes ds, nothing
|
|
assumes es, nothing
|
|
|
|
cProc gwin386discard,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
CheckKernelDS FS
|
|
ReSetKernelDS FS
|
|
cmp ds:[esi].pga_size, 4096
|
|
jb short not_a_chance ; Quick exit
|
|
cmp ds:[esi].pga_size, 16*1024
|
|
jb short inform_later
|
|
|
|
pushad
|
|
mov ebx, ds:[esi].pga_address
|
|
mov esi, ds:[esi].pga_size
|
|
|
|
mov di, si
|
|
shr esi, 16 ; SI:DI is # bytes to discard
|
|
mov cx, bx
|
|
shr ebx, 16 ; BX:CX is first bytes to discard
|
|
DPMICALL 0703h
|
|
popad
|
|
jmps not_a_chance
|
|
|
|
inform_later:
|
|
or PagingFlags, 1
|
|
not_a_chance:
|
|
ret
|
|
UnSetKernelDS FS
|
|
cEnd nogen
|
|
|
|
|
|
cProc DiscardFreeBlocks,<PUBLIC,NEAR>
|
|
cBegin nogen
|
|
push es
|
|
push ds
|
|
GENTER32
|
|
ReSetKernelDS FS
|
|
and PagingFlags, NOT 1
|
|
|
|
mov esi, ds:[di].phi_first
|
|
mov esi, ds:[esi].pga_freenext
|
|
dfb_next:
|
|
cmp esi, ds:[esi].pga_next ; Sentinel?
|
|
je short dfb_done ; yes, all done
|
|
|
|
push esi
|
|
push edi
|
|
cmp ds:[esi].pga_size, 4096
|
|
jb short no_win386discard ; Quick exit
|
|
|
|
mov ebx, ds:[esi].pga_address
|
|
mov esi, ds:[esi].pga_size
|
|
add esi, ebx ; First byte past block
|
|
shr esi, 12 ; Page of this byte
|
|
add ebx, 0fffh
|
|
shr ebx, 12 ; First page we can discard
|
|
sub esi, ebx ; # pages we can discard
|
|
jbe short no_win386discard ; none to discard
|
|
|
|
mov di, si
|
|
shr esi, 16 ; SI:DI is # pages to discard
|
|
mov cx, bx
|
|
shr ebx, 16 ; BX:CX is first page to discard
|
|
DPMICALL 0701h ; Say goodbye, pages
|
|
|
|
no_win386discard:
|
|
pop edi
|
|
pop esi
|
|
|
|
mov esi, ds:[esi].pga_freenext
|
|
jmps dfb_next
|
|
|
|
dfb_done:
|
|
GLEAVE32
|
|
UnSetKernelDS FS
|
|
pop ds
|
|
pop es
|
|
ret
|
|
cEnd nogen
|
|
|
|
;---------------------------------------------------------------------------
|
|
;
|
|
; guc_findfree
|
|
;
|
|
; helper function for guncompact
|
|
;
|
|
; finds the next free block below the address
|
|
; in ECX into which the block pointed to by ESI will fit.
|
|
;
|
|
; Entry:
|
|
; ECX = maximum address (desired swap area)
|
|
; DS:DI = global heap info
|
|
; ESI = arena of block to move
|
|
;
|
|
; Exit:
|
|
; Carry clear if block found, set if not
|
|
; EDX = free block arena
|
|
;
|
|
; Uses:
|
|
; EAX, EDX
|
|
;
|
|
; Preserves:
|
|
; EBX, ECX, ESI, EDI
|
|
;
|
|
; History:
|
|
; Fri Jun 7, 1991 9:38 -by- Craig Critchley [craigc]
|
|
; Wrote it...
|
|
;
|
|
;--------------------------------------------------------------------------
|
|
|
|
cProc guc_findfree, <NEAR, PUBLIC>
|
|
cBegin nogen
|
|
|
|
mov edx, ds:[di].phi_last
|
|
mov edx, ds:[edx].pga_freeprev
|
|
|
|
gucff_check:
|
|
cmp edx, ds:[edx].pga_prev ; if at start, not found
|
|
jz short gucff_notfound
|
|
|
|
mov eax, ds:[edx].pga_address ; is it out of swap area
|
|
add eax, ds:[edx].pga_size
|
|
cmp eax, ecx
|
|
jae short gucff_nextblock
|
|
|
|
mov eax, ds:[esi].pga_size ; does it fit
|
|
cmp ds:[edx].pga_size, eax
|
|
jb short gucff_nextblock
|
|
|
|
clc ; return it in EDX
|
|
ret
|
|
|
|
gucff_nextblock:
|
|
mov edx, ds:[edx].pga_freeprev ; previous free block
|
|
jmp short gucff_check
|
|
|
|
gucff_notfound:
|
|
stc ; return error
|
|
ret
|
|
|
|
cEnd nogen
|
|
|
|
;-----------------------------------------------------------------------------
|
|
;
|
|
; guncompact -
|
|
;
|
|
; this function moves segments that are not free or discardable code
|
|
; out of the intended swap area. don't take the name too seriously.
|
|
;
|
|
; Entry:
|
|
; ECX = size of intended swap area
|
|
; DS:DI = global heap info
|
|
; FS = global heap
|
|
;
|
|
; Exit:
|
|
; Carry clear if space could be cleared, set if not
|
|
;
|
|
; Registers used:
|
|
; EAX, EBX, ECX, EDX, ESI
|
|
;
|
|
; Called by:
|
|
; greserve
|
|
;
|
|
; Calls:
|
|
; gmoveable
|
|
; gmovebusy
|
|
;
|
|
; History:
|
|
; Fri Jun 7, 1991 9:38 -by- Craig Critchley [craigc]
|
|
; Wrote it...
|
|
;
|
|
;-----------------------------------------------------------------------------
|
|
|
|
cProc guncompact, <NEAR, PUBLIC>
|
|
|
|
cBegin <nogen>
|
|
|
|
mov edx, [di].phi_last ; point to last block
|
|
mov ebx, pga_prev
|
|
|
|
sub ecx, ds:[edx].pga_address ; find desired code fence
|
|
neg ecx
|
|
|
|
guc_trymovingblock:
|
|
mov esi, ds:[edx+ebx] ; block under current one...
|
|
cmp ds:[esi].pga_owner, 0 ; don't move free blocks
|
|
jz short guc_skipblock
|
|
test ds:[esi].pga_flags, GA_DISCCODE ; don't move discardable code
|
|
jnz short guc_skipblock
|
|
cmp ds:[esi].pga_owner, GA_NOT_THERE ; ignore not-there's
|
|
jz short guc_skipblock
|
|
|
|
call gmoveable ; can this block be moved?
|
|
jz short guc_error ; if not, swap area toast
|
|
push edx
|
|
call guc_findfree ; find a block to move it into
|
|
pop eax
|
|
jc short guc_error ; error if didn't find one
|
|
push eax
|
|
xchg edx, esi
|
|
call gmovebusy ; move it
|
|
xchg edx, esi
|
|
pop edx
|
|
|
|
;;; can we just fall thru the block ought to be free now...
|
|
jmp short guc_trymovingblock ; move what's there now
|
|
|
|
guc_skipblock:
|
|
mov edx, esi ; this block now first cleared
|
|
cmp ds:[edx].pga_address, ecx ; big enough?
|
|
ja short guc_trymovingblock
|
|
|
|
guc_done:
|
|
clc ; success-o-mundo!!
|
|
ret
|
|
|
|
guc_error:
|
|
stc ; if not, we could not
|
|
ret ; clear swap area
|
|
|
|
cEnd <nogen>
|
|
|
|
sEnd CODE
|
|
|
|
end
|