summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16/kernel31/2gmem.asm
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/wow16/kernel31/2gmem.asm')
-rw-r--r--private/mvdm/wow16/kernel31/2gmem.asm1321
1 files changed, 1321 insertions, 0 deletions
diff --git a/private/mvdm/wow16/kernel31/2gmem.asm b/private/mvdm/wow16/kernel31/2gmem.asm
new file mode 100644
index 000000000..4049a2ecf
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/2gmem.asm
@@ -0,0 +1,1321 @@
+ TITLE GMEM - Register interface to global memory allocator
+
+.xlist
+include kernel.inc
+include tdb.inc
+include protect.inc
+.list
+
+externFP SetSelectorLimit
+
+DataBegin
+
+externB fBooting
+;externW curTDB
+;externW pGlobalHeap
+externW SelTableStart
+externW SelTableLen
+
+ifdef WOW
+globalB fInAlloc, 0
+globalW UserSelArray, 0
+globalW SelectorFreeBlock, 0
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+
+externNP DPMIProc
+DPMICALL MACRO callno
+ mov ax, callno
+ call DPMIProc
+ ENDM
+
+;externW gdtdsc
+
+
+externNP gsplice
+externNP gjoin
+externNP gzero
+externNP gsearch
+externNP gmarkfree
+;externNP gcheckfree
+externNP gmovebusy
+externNP gcompact
+externNP glruadd
+externNP glrudel
+externNP glrutop
+externNP gnotify
+externNP henum
+externNP is_there_theoretically_enough_space
+externNP can_we_clear_this_space
+
+externNP get_physical_address
+externNP set_physical_address
+externNP alloc_sel
+externNP alloc_data_sel_above
+externNP pdref
+externNP set_sel_limit
+externNP mark_sel_PRESENT
+externNP mark_sel_NP
+externNP free_sel
+externNP FreeSelArray
+externNP GrowSelArray
+externNP get_arena_pointer
+externNP get_temp_sel
+externNP get_blotto
+;externNP get_sel
+externNP PreallocSel
+externNP AssociateSelector
+externNP GetAccessWord
+externNP SetAccessWord
+externFP set_discarded_sel_owner
+
+if ROM
+externNP IsROMObject
+endif
+
+if KDEBUG
+externNP CheckGAllocBreak
+endif
+
+;-----------------------------------------------------------------------;
+; galign ;
+; ;
+; Aligns the size request for a global item to a valid para boundary. ;
+; ;
+; Arguments: ;
+; BX = #paras ;
+; CF = 1 if #paras overflowed. ;
+; ;
+; Returns: ;
+; DX = #paras aligned, to next higher multiple of 2 ;
+; ;
+; Error Returns: ;
+; DX = FFFFh ;
+; ;
+; Registers Preserved: ;
+; all ;
+; Registers Destroyed: ;
+; none ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Mon Sep 22, 1986 03:14:56p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc galign,<PUBLIC,NEAR>
+cBegin nogen
+
+ jc align_error ; Overflow occur?
+ lea dx,[bx+GA_ALIGN] ; No, add alignment amount
+ and dl,GA_MASK ; ...modulo alignment boundary
+ cmp dx,bx ; Test for overflow
+ jnb align_exit ; Yes, continue
+align_error:
+ mov dx,0FFFFh ; Return impossible size
+align_exit:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; galloc ;
+; ;
+; Allocates global memory. ;
+; ;
+; Arguments: ;
+; AX = allocation flags ;
+; BX = #paragraphs ;
+; CX = owner field ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = handle to object or zero ;
+; BX = size of largest free block if AX = 0 ;
+; CX = AX ;
+; ;
+; Error Returns: ;
+; DX = 0 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; gsearch ;
+; ghalloc ;
+; glruadd ;
+; gmarkfree ;
+; History: ;
+; ;
+; Wed Jun 24, 1987 03:04:32a -by- David N. Weise [davidw] ;
+; Added support for Global Notify. ;
+; ;
+; Mon Sep 22, 1986 02:38:19p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+AccessWord dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+ dw DSC_CODE+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_CODE+DSC_PRESENT
+ dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+ dw DSC_DATA+DSC_PRESENT
+ dw (DSC_DISCARDABLE SHL 8) + DSC_DATA+DSC_PRESENT
+
+cProc galloc,<PUBLIC,NEAR>
+cBegin nogen
+
+if ROM and KDEBUG
+ if 1
+ %out Remove me someday
+ endif
+ or cx,cx ; had trouble with owner == 0
+ jnz @f ; too many times!
+ Debug_Out "ROMKRNL: galloc with owner = 0!"
+@@:
+endif
+
+if KDEBUG
+ test al,GA_DISCCODE ; If discardable code, allow alloc
+ jnz @F
+ call CheckGAllocBreak
+ jnc @F
+ jmp gaerr
+@@:
+endif
+
+ or bx,bx ; Allocating zero size?
+ jnz @F
+ jmp allocate_zero_size
+@@:
+
+ifdef WOW
+ push ds
+ SetKernelDS
+ mov fInAlloc, 1
+ mov SelectorFreeBlock, 0
+ mov UserSelArray, 0
+ UnSetKernelDS
+ pop ds
+endif
+ call gsearch ; Search for block big enough
+ jnz bleech
+ mov cx, ax
+
+ifdef WOW
+ push ds
+ SetKernelDS
+ mov fInAlloc, 0
+ mov SelectorFreeBlock, 0
+ mov UserSelArray, 0
+ UnSetKernelDS
+ pop ds
+endif
+
+ ret ; Done, if couldn't get enough
+bleech:
+ mov es,ax
+ push dx
+
+ifdef WOW
+
+ push ds
+ SetKernelDS
+ mov fInAlloc, 0
+ mov SelectorFreeBlock, 0
+ mov ax, UserSelArray
+ UnSetKernelDS
+ pop ds
+ or ax, ax
+ jnz got_Sel
+ mov ax, es
+
+old_path:
+
+endif
+ mov bx,dx
+ cCall get_physical_address,<ax>
+ add ax,10h ; Calculate address of object
+ adc dx,0
+ mov cx, ax ; in DX:CX
+
+ and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
+ or bl, bh
+ xor bh, bh
+ shl bx, 1
+ mov ax, cs:AccessWord[bx] ; Pick up access rights for selector
+ cCall alloc_sel,<dx,cx,es:[di].ga_size>
+
+got_sel:
+ pop dx
+ or ax, ax
+ jz short gaerr1
+ cCall AssociateSelector,<ax,es>
+ test dl,GA_MOVEABLE ; Is this a moveable object?
+ jnz moveable
+ test dh, GA_DISCARDABLE ; We have a fixed block
+ jnz not_moveable ; Not interested in discardable blocks
+ mov bx, ax
+%out THIS IS WRONG!!!
+ifdef WOW
+ ; the following dpmicall is basically a NOP. so just
+ ; avoid the call altogether.
+ ; - Nanduri Ramakrishna
+else
+ mov ax, 4 ; Lock the WIN386 pages
+ ;bugbugbugbug
+ DPMICALL ax ; int 31h
+ mov ax, bx
+endif
+ jmps not_moveable
+moveable:
+ mov es:[di].ga_count,0 ; Initialize lock count to 0
+ StoH al ; Mark as moveable block
+not_moveable:
+ mov es:[di].ga_handle,ax ; Set handle in arena
+ mov bx, ax ; AX and BX handle
+
+ call glruadd ; Yes, Add to LRU chain
+ mov cx, ax
+ ret
+
+allocate_zero_size:
+ test al,GA_MOVEABLE ; Yes, moveable?
+ jz gaerr ; No, return error (AX = 0)
+
+ mov bx, ax
+ and bx, ((GA_CODE_DATA+GA_DISCARDABLE) shl 8) + GA_DGROUP
+ or bl, bh ; Above bits are exclusive
+ xor bh, bh
+ shl bx, 1
+ mov ax, cs:AccessWord[bx] ; Pick up access rights for selector
+ and al, NOT DSC_PRESENT ; These are NOT present
+ xor dx, dx ; Base of zero for now
+ cCall alloc_sel,<dx,dx,cx>
+ or ax, ax
+ jz gaerr
+
+ cCall AssociateSelector,<ax,cx>
+ StoH al ; Handles are RING 2
+ mov bx,ax
+ga_exit:
+ mov cx, ax
+ ret
+
+gaerr1:
+ xor si,si
+ call gmarkfree
+gaerr:
+ KernelLogError DBF_WARNING,ERR_GALLOC,"GlobalAlloc failed"
+ xor dx,dx ; DX = 0 means NOT out of memory
+ xor ax,ax ; Return AX = 0 to indicate error
+ jmps ga_exit
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; grealloc ;
+; ;
+; Reallocates the given global memory object. ;
+; ;
+; Arguments: ;
+; AX = allocation flags ;
+; BX = #paragraphs for new size ;
+; CX = new owner field value ;
+; DX = existing handle ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = handle to object or zero ;
+; DX = size of largest free block if AX = 0 ;
+; CX = AX ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; SI ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Mon 05-Feb-1990 21:07:33 -by- David N. Weise [davidw] ;
+; Got rid of the spagetti code. ;
+; ;
+; Mon Sep 22, 1986 10:11:48a -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc grealloc,<PUBLIC,NEAR>,<si>
+
+ localW rflags
+ localW hMem
+ localW oldhMem
+ localW owner
+ localW rsize
+ localW canmove
+ localB locked
+ localB mflags
+ localW numsels
+cBegin
+ mov rflags,ax
+ mov hMem,dx
+ mov oldhMem,dx
+ mov owner,cx
+ mov rsize,bx
+ call pdref
+ mov dx,bx ; save owner if discarded
+ mov word ptr mflags,cx
+ mov bx,rsize
+ jnz handle_ok
+ jmp racreate ; Do nothing with 0, free or discarded handles
+handle_ok:
+ test byte ptr rflags,GA_MODIFY ; Want to modify table flags?
+ jnz ramodify ; Yes go do it
+ or bx,bx ; Are we reallocing to zero length?
+ jz radiscard
+ jmp ra_shrink_grow ; No, continue
+
+;-----------------------------------------------------------------------;
+; Here to discard object, when reallocating to zero size. This ;
+; feature is only enabled if the caller passes the moveable flag ;
+;-----------------------------------------------------------------------;
+
+radiscard:
+ or ch,ch ; Is handle locked?
+ jnz radiscard_fail
+ test byte ptr rflags,GA_MOVEABLE ; Did they want to discard?
+ jz radiscard_fail ; No, then return failure.
+ mov al,GN_DISCARD ; AL = discard message code
+ xor cx,cx ; CX = means realloc
+ mov bx,hMem ; BX = handle
+ push es
+ call gnotify ; See if okay to discard
+ pop es
+ jz radiscard_fail ; No, do nothing
+ call glrudel ; Yes, Delete handle from LRU chain
+
+ cCall mark_sel_NP,<si,es:[di].ga_owner>
+
+ xor si,si
+ call gmarkfree ; Free client data
+ mov ax,0 ; don't change flags
+ jz @F ; Return NULL if freed a fixed block
+ mov bx, si
+ mov ax,hMem ; Return original handle, except
+@@: jmp raexit ; GlobalLock will now return null.
+
+radiscard_fail:
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ xor dx,dx
+ xor ax,ax
+ jmp raexit
+
+;-----------------------------------------------------------------------;
+; There are 2 attributes that can change: ;
+; 1) Fixed -> moveable - added in 2.x, probably not used by many ;
+; 2) nondiscardable <-> discardable ;
+; 3) non-shared -> shared, i.e., the owner changes ;
+;-----------------------------------------------------------------------;
+
+ramodify:
+if ROM
+ cCall IsROMObject,<hMem> ; If someone is trying to modify a
+ jc ramod_done ; ROM object, just pretend it worked
+endif
+ mov ax,rflags ; Get new flags
+ mov dx,owner ; Get new owner field value
+ or si,si ; Moveable object?
+ jnz is_moveable ; yes, change discardability/owner
+ test al,GA_MOVEABLE ; Make fixed into moveable?
+ jz ra_mod_owner ; Fixed, can ONLY change owner
+
+ push ax
+ push cx
+ mov ax, es:[di].ga_handle ; Turn selector into handle
+ StoH al
+ mov bx, ax
+ mov es:[di].ga_handle, ax
+ mov es:[di].ga_count, 0 ; 0 lock count for new movable obj
+ pop cx
+ pop ax
+ mov si,bx
+
+; fall through to code that makes [non]discardable and may change owner
+
+is_moveable:
+ call glrudel ; Remove from lru chain, even though
+ push bx
+ mov bx, ax
+ cCall GetAccessWord,<si>
+ and ah, not DSC_DISCARDABLE ; Clear discard bit
+ test bh, GA_DISCARDABLE
+ jz ra_notdiscardable
+ or ah, DSC_DISCARDABLE
+ra_notdiscardable:
+ cCall SetAccessWord,<si,ax>
+ mov ax, bx
+ pop bx
+ test cl,HE_DISCARDED ; Is this a discarded handle?
+ jz ramod1 ; No, continue
+ test ah,GA_SHAREABLE ; Only change owner if making shared
+ jz ramod_done
+
+ push bx
+ push es
+ mov bx, si
+ mov es, dx
+ call set_discarded_sel_owner
+ pop es
+ pop bx
+ jmps ramod_done
+
+ramod1: call glruadd ; only adds to list IF object is disc
+
+ra_mod_owner:
+ test ah,GA_SHAREABLE ; Only change owner if making shared
+ jz ramod_done
+ mov es:[di].ga_owner,dx ; Set new owner value
+ramod_done:
+ mov ax,hMem ; Return the same handle
+ jmp raexit ; All done
+
+;-----------------------------------------------------------------------;
+; We are here to grow a 0 sized object up big. ;
+;-----------------------------------------------------------------------;
+
+racreate:
+ test cl,HE_DISCARDED ; Is this a discarded handle?
+ jz racre_fail ; No, return error
+ or bx,bx ; Are we reallocing to zero length?
+ mov ax,hMem
+ jz racre_done ; Yes, return handle as is.
+if KDEBUG
+ test cl,GA_DISCCODE ; if discardable code, allow realloc
+ jnz @F
+ call CheckGAllocBreak
+ jc racre_fail
+@@:
+endif
+ mov ax,GA_MOVEABLE ; Reallocating a moveable object
+ or ax,rflags ; ...plus any flags from the caller
+
+ and cl,GA_SEGTYPE
+ or al,cl
+ mov cx,dx ; get owner
+ push ds
+ SetKernelDS
+ife ROM
+ cmp fBooting, 1 ; Allocate high while booting
+ je @F
+endif
+ test al,GA_DISCCODE ; Discardable code segment?
+ jz ranotcode
+@@:
+ or al,GA_ALLOCHIGH ; Yes, allocate high
+ranotcode:
+ pop ds
+ UnSetKernelDS
+ mov [di].gi_cmpflags,al ; Save flags for gcompact
+ and [di].gi_cmpflags,CMP_FLAGS
+ push si ; save handle
+ call gsearch ; Find block big enough
+ pop si ; restore existing handle
+ jz racre_fail1
+
+ mov bx,ax ; save new block
+ cCall mark_sel_PRESENT,<ax,si> ; sets a new set of sels if necessary
+ or si,si
+ jz racre_worst_case
+ xchg ax,si ; Return original/new handle
+ ; Set back link to handle in new block
+ cCall AssociateSelector,<ax,si>
+ mov es,si
+ mov es:[di].ga_handle,ax
+ mov es:[di].ga_count,0
+ call glruadd ; Add to LRU chain
+ jmps racre_done
+
+racre_worst_case:
+ mov es,bx ; Free block if no handles available.
+ xor si,si
+ call gmarkfree
+
+racre_fail:
+ xor dx,dx
+racre_fail1:
+ push dx
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ pop dx
+ xor ax,ax ; Yes, return failure
+racre_done:
+ jmp raexit
+
+
+;-----------------------------------------------------------------------;
+; This is what most would have thought is the guts of GlobalRealloc. ;
+;-----------------------------------------------------------------------;
+
+ra_shrink_grow:
+
+if KDEBUG
+ test es:[di].ga_flags,GA_DISCCODE
+ jz ok
+ INT3_WARN ; GlobalRealloc of discardable code!
+ok:
+endif
+ cmp bx,es:[di].ga_size
+ jz rasame
+
+ add bx,1 ; add room for header, set carry bit
+ jc ra_s_g_fail
+ call galign ; assuming there is room.
+ dec dx ; Exclude header again
+ mov si,dx
+
+; Here if not trying to realloc this block to zero
+; ES:0 = arena header of current block
+; AX:0 = client address of current block
+; CH = lock count of current block
+; DX = new requested size of block
+; SI = new requested size of block
+
+ mov bx,es:[di].ga_next ; Get address of current next header
+ cmp si,es:[di].ga_size ; Are we growing or shrinking?
+ ja raextend ; We are growing
+
+ call rashrink
+rasame: mov ax,hMem ; Return the same handle
+ jmp raexit ; All done
+
+raextend:
+ test rflags,GA_DISCCODE ; Not allowed to grow a disccode seg
+ jnz ra_s_g_fail
+if KDEBUG
+ call CheckGAllocBreak
+ jc ra_s_g_fail
+endif
+ push ax
+ call GrowSelArray
+ mov numsels, cx ; Save how many to free just in case
+ mov cx, ax
+ pop ax
+ jcxz ra_s_g_fail ; Didn't get selectors
+ mov hMem, cx ; We have a new handle
+ call ragrow
+ jnc rasame
+ test mflags,GA_DISCARDABLE ; if discardable, just stop now
+ jz ramove ; since it might get discarded!
+ra_s_g_fail:
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ xor ax,ax ; Yes, return failure
+ xor dx,dx
+ jmp raexit
+
+
+; Here to try to move the current block
+; AX = client address of current block
+; ES:0 = arena header of current block
+; CH = lock count of current block
+; SI = new requested size of block
+
+ramove: mov canmove, 1
+ mov dx,rflags ; get the passed in flags
+ test dx,GA_MOVEABLE ; Did they say OK to move
+ jnz ramove1 ; Yes, try to move even iflocked or fixed
+ cmp locked, 0 ; Locked?
+ jnz racompact ; Continue if this handle not locked
+ ; yes, try to find space to grow in place
+ or dx,GA_MOVEABLE ; If moveable, make sure bit set.
+ test hMem,GA_FIXED ; Is this a moveable handle?
+ jz ramove2 ; Yes, okay to move
+racompact:
+ xor dx,dx ; No, get size of largest free block
+ call gcompact
+ jmps racantmove
+
+ramove1:
+ test hMem, GA_FIXED
+ jz ramove2
+ and dx, NOT GA_MOVEABLE
+ramove2:
+ mov ax,dx ; AX = allocation flags
+ mov bx,si ; BX = size of new block
+ call PreAllocSel ; for gmovebusy later
+ jz racantmove
+ mov cx,bx ; CX = owner (use size for now)
+ call gsearch ; Find block big enough
+ jz racantmove ; Cant find one, grow in place now?
+ mov cx,hMem
+
+ push ax
+ cCall get_arena_pointer,<cx>
+;;; mov es,ax
+;;; mov es,es:[di].ga_next ; get real arena header
+;;; mov si,es:[di].ga_prev
+ mov si, ax ; SI = source arena
+ pop es ; ES = destination arena
+
+ call gmovebusy ; Call common code to move busy block
+ ; (AX destroyed)
+ push bx
+ push cx
+ mov bx, es:[di].ga_size
+ xor cx,cx
+REPT 4
+ shl bx,1
+ rcl cx,1
+ENDM
+ cCall set_sel_limit, <es:[di].ga_handle>
+
+ pop cx
+ pop bx
+ mov ax,cx ; Return new handle
+raexit:
+ mov cx,ax
+ jcxz ra_done
+ test hMem,GA_FIXED ; Is this a moveable object?
+ jz ra_done ; no, don't lock
+ mov bx, ax
+ifdef WOW
+ ; the following dpmicall is basically a NOP. so just
+ ; avoid the call altogether.
+ ; - Nanduri Ramakrishna
+else
+ mov ax, 4 ; Lock the WIN386 pages
+ ; bugbugbugbug
+ DPMICALL ax ; int 31h
+ mov ax, bx
+endif
+ jmps ra_done
+
+racantmove:
+ mov dx, hMem
+ call pdref
+
+ mov bx,rsize
+ add bx,1 ; add room for header, set carry bit
+ call galign ; assuming there is room.
+ dec dx ; Exclude header again
+ mov si,dx
+
+ mov bx,es:[di].ga_next ; Get address of current next header
+ call ragrow
+ jc racmove3
+ jmp rasame
+
+racmove3:
+ xor dx,dx ; No, get size of largest free block
+ call gcompact
+ mov dx,ax ; DX = size of largest free block
+
+rafailmem:
+ cCall get_arena_pointer,<hMem>
+ mov es,ax
+ mov ax,es:[di].ga_size ; AX = size of current block
+ mov es,es:[di].ga_next ; Check following block
+ cmp es:[di].ga_owner,di ; Is it free?
+ jne rafailmem0 ; No, continue
+ add ax,es:[di].ga_size ; Yes, then include it as well
+ inc ax
+rafailmem0:
+ cmp ax,dx ; Choose the larger of the two
+ jbe rafailmem1
+ mov dx,ax
+rafailmem1:
+ push dx ; Save DX
+ KernelLogError DBF_WARNING,ERR_GREALLOC,"GlobalReAlloc failed"
+ pop dx ; RestoreDX
+ xor ax,ax
+ jmps raexit
+
+ra_done: ; 3 feb 1990, this
+ push ax ; is a last minute hack
+ push bx
+ push cx
+ push dx
+ mov bx,hMem
+ mov cx,oldhMem
+ife RING-1
+ inc bx
+ and bl,NOT 1
+ inc cx
+ and cl,NOT 1
+else
+ or bl, 1
+ or cl, 1
+endif
+ cmp bx,cx ; was a new selector allocated?
+ jz ra_really_done ;
+ or ax,ax ; figure out if we suceeded
+ jz ra_ra
+ cCall FreeSelArray,<cx> ; free the original selector
+ jmps ra_really_done
+
+ra_ra: cCall get_physical_address,<bx>
+ cCall set_physical_address,<oldhMem>
+ cCall get_arena_pointer,<hMem>
+ INT3_ANCIENT
+ cCall AssociateSelector,<cx,es>
+ push ax
+
+ mov cx, numsels
+ mov ax, hMem
+fsloop:
+ cCall free_sel,<ax>
+ add ax, 8
+ loop fsloop
+
+ pop es
+ mov ax,oldhMem
+ mov es:[ga_handle],ax
+ cCall AssociateSelector,<ax,es>
+
+ra_really_done:
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+
+cEnd
+
+;-----------------------------------------------------------------------;
+; rashrink ;
+; ;
+; Shrinks the given block ;
+; ;
+; Arguments: ;
+; Here to shrink a block ;
+; ES:0 = arena header of current block ;
+; DX = new requested size of block ;
+; SI = new requested size of block ;
+; ;
+; Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ALL but DS, DI ;
+; ;
+; Calls: ;
+; gsplice ;
+; gmarkfree ;
+; ;
+; History: ;
+; ;
+; Tue 06-Feb-1990 01:03:54 -by- David N. Weise [davidw] ;
+; I got no clue what the history of this thing is, all I know is ;
+; that I got to fix it fast to prevent selector leak. ;
+;-----------------------------------------------------------------------;
+
+ assumes ds,nothing
+ assumes es,nothing
+
+cProc rashrink,<PUBLIC,NEAR>
+cBegin nogen
+
+ mov bx,si
+ xor cx,cx
+ REPT 4
+ shl bx,1
+ rcl cx,1
+ ENDM
+ mov ax,es:[di].ga_handle
+ or ax,ax
+ jz ra_free
+
+; !! the following was added Tue 06-Feb-1990 01:47:12
+; it doesn't belong here really but it is the only way to
+; prevent selector leak.
+
+ push bx
+ push cx
+ push si
+
+ mov si,ax
+ cCall GetAccessWord,<si>
+ mov bl, ah
+ mov ax, si
+ and bl, 0Fh ; Current hlimit
+ inc bl ; number of selectors there now
+ mov cx,dx
+
+ add cx, 0FFFh
+ rcr cx, 1 ; 17 bitdom
+ shr cx, 11
+ sub bl, cl
+ jbe ignore_this_shi
+
+ xor bh,bh ; BX = number of selectors to free
+ shl cx,3
+ .errnz SIZE DscPtr - 8
+ add cx,si ; CX = selector to start to free
+ xchg bx,cx
+@@: cCall free_sel,<bx>
+ add bx,SIZE DscPtr
+ loop @B
+
+ignore_this_shi:
+ pop si
+ pop cx
+ pop bx
+
+; end of shi
+
+ Handle_To_Sel al
+ cCall set_sel_limit,<ax>
+ra_free:
+ inc dx ; Test for small shrinkage
+ inc dx
+ .errnz GA_ALIGN - 1
+
+ cmp dx,es:[di].ga_size ; Enough room from for free block?
+ ja rashrunk ; No, then no change to make
+
+; !! why isn't the PreAllocSel done before the set_sel_limit?
+; Because it belongs with the 'gsplice'.
+
+ call PreallocSel ; Must be able to get selector
+ jz rashrunk
+ ; Yes, ES:DI = cur block, SI=new block
+ inc si ; Include header in size of block
+ call gsplice ; splice new block into the arena
+ mov es,si ; ES:DI = new free block
+ xor si,si
+ call gmarkfree ; Mark it as free
+rashrunk:
+ ret
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; ragrow ;
+; ;
+; Tries to grow the given global memory object in place ;
+; ;
+; Arguments: ;
+; AX:0 = client address of current block ;
+; ES:0 = arena header of current block ;
+; BX:0 = arena header of next block ;
+; DX = SI = new requested size of block ;
+; ;
+; Returns: ;
+; CY = 0 Success ;
+; ;
+; CY = 1 Failed ;
+; ES preserved ;
+; DX contains free memory required ;
+; ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ALL but DS, DI ;
+; ;
+; Calls: ;
+; is_there_theoretically_enough_space ;
+; can_we_clear_this_space ;
+; gjoin ;
+; gzero ;
+; rashrink ;
+; ;
+; History: ;
+; ;
+; Mon 05-Sep-1988 20:10:15 -by- David N. Weise [davidw] ;
+; Made ragrow be more intelligent by trying to extend into moveable ;
+; blocks. ;
+;-----------------------------------------------------------------------;
+cProc ragrow,<PUBLIC,NEAR>
+cBegin nogen
+
+ push si
+ push es ; Save current block address
+ sub dx, es:[di].ga_size ; compute amount of free space wanted
+ mov es,bx ; ES = next block address
+ mov cx,[di].hi_count
+ push cx
+ push es
+ call is_there_theoretically_enough_space
+ pop es
+ pop cx
+ cmp ax,dx
+ jb ragx
+ call can_we_clear_this_space
+ jz ragx
+ pop cx ; clear the stack
+ pop si
+ push si
+ call gjoin ; and attach to end of current block
+ pop si ; (will free a selector)
+ test byte ptr rflags,GA_ZEROINIT ; Zero fill extension?
+ jz ranz ; No, continue
+
+ mov bx, dx ; number of paragraphs to fill
+ mov dx, si ; New size of block
+ sub dx, bx ; Old size of block
+ inc dx ; Paragraph offset of where to zero
+ cCall alloc_data_sel_above,<es,dx>
+ push bx
+ push ax ; set the limit really big
+ push es
+ cCall SetSelectorLimit,<ax,0Fh,0FFFFh>
+ pop es
+ pop ax
+ pop cx ; Number of paragraphs to zero
+ mov bx, ax ; Selector to fill
+ call gzero ; zero fill extension
+ cCall free_sel,<bx>
+ranz:
+ mov dx, si
+ mov bx,es:[di].ga_next ; Pick up new next block address
+ call rashrink ; Now shrink block to correct size
+ clc
+ ret
+ragx:
+ pop es ; Recover current block address
+ pop si
+ stc
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gfree ;
+; ;
+; Frees a global object. ;
+; ;
+; Arguments: ;
+; DX = global memory object handle ;
+; CX = owner field value to match or zero if dont care ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; CX = 0 ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; CX = -1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ? ;
+; Calls: ;
+; gdref ;
+; free_object ;
+; hfree ;
+; ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 11:48:38a -by- David N. Weise [davidw] ;
+; Added this nifty comment block and restructured. ;
+;-----------------------------------------------------------------------;
+
+cProc gfree,<PUBLIC,NEAR>
+cBegin nogen
+
+ push cx
+ call pdref
+
+ pop dx
+ jz object_discarded
+ call free_object
+ jmps gfree_exit
+object_discarded:
+
+ cCall AssociateSelector,<si,di>
+ cCall FreeSelArray,<si>
+ xor ax,ax ;!!! just for now force success
+
+gfree_exit:
+ mov cx,ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; free_object ;
+; ;
+; Arguments: ;
+; DX = owner field value to match or zero if dont care ;
+; DS:DI = address of global heap info ;
+; ES:DI = address of arena header ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; glrudel ;
+; gmarkfree ;
+; hfree ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 02:59:06p -by- David N. Weise [davidw] ;
+; Moved it from gfree. ;
+;-----------------------------------------------------------------------;
+
+cProc free_object,<PUBLIC,NEAR>
+cBegin nogen
+ or dx,dx
+ jz free_it
+ cmp es:[di].ga_owner,dx
+ je free_it
+ mov ax,-1
+ jmps free_object_exit
+free_it:
+ call glrudel ; delete object from LRU chain
+ xor si,si
+ call gmarkfree ; free the object
+ cCall AssociateSelector,<si,di>
+ cCall FreeSelArray,<si>
+ xor ax,ax ;!!! just for now force success
+free_object_exit:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; free_handle ;
+; ;
+; Frees the given handle. ;
+; ;
+; Arguments: ;
+; DS:SI = handle table entry address ;
+; ;
+; Returns: ;
+; AX = 0 ;
+; CX = AX ;
+; ;
+; Error Returns: ;
+; AX = -1 ;
+; ;
+; Registers Preserved: ;
+; BX ;
+; ;
+; Registers Destroyed: ;
+; ? ;
+; Calls: ;
+; hfree ;
+; History: ;
+; ;
+; Sat Sep 20, 1986 02:30:32p -by- David N. Weise [davidw] ;
+; Moved it from gfree. ;
+;-----------------------------------------------------------------------;
+
+;cProc free_handle,<PUBLIC,NEAR>
+;cBegin nogen
+; xor ax,ax
+; or si,si
+; jz free_handle_exit
+; push bx
+; mov bx,si
+; call hfree
+; pop bx
+;free_handle_exit:
+; ret
+;cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gfreeall ;
+; ;
+; Frees all global objects that belong to the given owner. It first ;
+; loops through the global heap freeing objects and then loops through ;
+; the handle table freeing handles of discarded objects. ;
+; ;
+; Arguments: ;
+; DX = owner field value to match ;
+; DS:DI = address of global heap info ;
+; ;
+; Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; CX,ES,SI ;
+; ;
+; Calls: ;
+; free_object ;
+; henum ;
+; hfree ;
+; ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 05:46:52p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gfreeall,<PUBLIC,NEAR>
+cBegin nogen
+
+ mov es,[di].hi_first ; ES:DI points to first arena entry
+ mov cx,[di].hi_count ; CX = #entries in the arena
+free_all_objects:
+ push cx
+ call free_object ; Free object if matches owner
+ pop cx
+ mov es,es:[di].ga_next ; Move to next block
+ loop free_all_objects
+
+; may go extra times, as CX does not track coalescing done by gfree,
+; but no big whoop
+
+
+ push ax
+ push bx
+ push di
+ SetKernelDS es
+ mov si, SelTableStart
+ mov cx, SelTableLen
+ shr cx, 1
+ mov di, si
+ smov es, ds
+ UnSetKernelDS es
+
+free_all_handles_loop:
+ mov ax, dx
+ repne scas word ptr es:[di] ; Isn't this easy?
+ jne short we_be_done
+ lea bx, [di-2]
+ sub bx, si
+ shl bx, 2
+ or bl, SEG_RING
+
+if KDEBUG
+ lsl ax, bx
+ cmp ax, dx
+ je @F
+ INT3_ANCIENT
+@@:
+endif
+
+ cCall GetAccessWord,<bx>
+ test al,DSC_PRESENT ; segment present?
+ jnz short free_all_handles_loop ; yes, not a handle
+ test ah,DSC_DISCARDABLE ; discardable?
+ jz short free_all_handles_loop ; no, nothing to free
+ cCall free_sel,<bx>
+ mov word ptr [di-2], 0 ; Remove owner from table
+ jcxz we_be_done
+ jmps free_all_handles_loop
+we_be_done:
+ pop di
+ pop bx
+ pop ax
+
+
+gfreeall_done:
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; glock ;
+; ;
+; Increment the lock count of an object in handle table entry ;
+; ;
+; Arguments: ;
+; BX = handle to global object ;
+; CH = handle table flags ;
+; CL = lock count for moveable objects ;
+; DX = segment address of object ;
+; DS:DI = address of master object ;
+; ES:DI = arena header ;
+; ;
+; Returns: ;
+; CX = updated lock count ;
+; DX = pointer to client area ;
+; ;
+; Error Returns: ;
+; ZF = 1 if count overflowed. ;
+; ;
+; Registers Preserved: ;
+; AX ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 05:38:57p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc glock,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ inc ch ; Increment lock count
+ jz overflow ; All done if overflow
+ mov es:[di].ga_count,ch ; Update lock count
+glockerror:
+overflow:
+ pop ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; gunlock ;
+; ;
+; Decrement the lock count of an object. ;
+; ;
+; Arguments: ;
+; BX = handle to global object ;
+; CH = handle table flags ;
+; CL = lock count for moveable objects ;
+; CX = handle table flags and lock count for moveable objects ;
+; DS:DI = address of master object ;
+; ES:DI = arena header ;
+; ;
+; Returns: ;
+; CX = updated lock count, no underflow ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; glrutop ;
+; History: ;
+; ;
+; Fri Sep 19, 1986 04:39:01p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc gunlock,<PUBLIC,NEAR>
+cBegin nogen
+ push ax
+ mov ax,bx
+ dec ch ; Decrement usage count
+ cmp ch,0FFh-1 ; ff -> fe, 0 -> ff
+ jae count_zero ; Return if pinned, or was already 0
+ dec es:[di].ga_count ; Non-zero update lock count
+ jnz count_positive ; All done if still non-zero
+ test cl,GA_DISCARDABLE ; Is this a discardable handle?
+ jz count_zero ; No, all done
+ call glrutop ; Yes, bring to top of LRU chain
+count_zero:
+ xor cx,cx
+count_positive:
+ pop ax
+ ret
+cEnd nogen
+
+sEnd CODE
+
+end