summaryrefslogtreecommitdiffstats
path: root/private/mvdm/wow16/kernel31/linterf.asm
diff options
context:
space:
mode:
Diffstat (limited to 'private/mvdm/wow16/kernel31/linterf.asm')
-rw-r--r--private/mvdm/wow16/kernel31/linterf.asm1572
1 files changed, 1572 insertions, 0 deletions
diff --git a/private/mvdm/wow16/kernel31/linterf.asm b/private/mvdm/wow16/kernel31/linterf.asm
new file mode 100644
index 000000000..50a06fdc3
--- /dev/null
+++ b/private/mvdm/wow16/kernel31/linterf.asm
@@ -0,0 +1,1572 @@
+ TITLE LINTERF - Local memory allocator, interface procedures
+
+.xlist
+include tdb.inc
+include kernel.inc
+.list
+
+.errnz la_prev ; This code assumes la_prev = 0
+
+if KDEBUG
+CheckHeap MACRO n
+local a
+ extrn CheckLocalHeap:NEAR
+ cCall CheckLocalHeap
+ or ax,ax
+ jz a
+ or ax,ERR_LMEM
+ kerror <>,<&n: Invalid local heap>
+a:
+ endm
+else
+CheckHeap MACRO n
+ endm
+endif
+
+externW pLocalHeap
+
+externFP <GlobalHandle,GlobalReAlloc,GlobalSize,GlobalCompact,GlobalFlags>
+externFP <GlobalLock,GlobalUnlock>
+externFP <GlobalMasterHandle,GetCurrentTask>
+externFP FarValidatePointer
+externFP DibRealloc
+
+DataBegin
+
+externW curTDB
+;externW MyCSDS
+
+if KDEBUG
+externW DebugOptions
+endif
+
+DataEnd
+
+sBegin CODE
+assumes CS,CODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+externNP <halloc,lhfree,lhdref,hthread> ; LHANDLE.ASM
+externNP <ljoin,lrepsetup,lzero> ; LALLOC.ASM
+externNP <lalloc,lfree,lfreeadd,lfreedelete> ; LALLOC.ASM
+externNP <lcompact,lshrink> ; LCOMPACT.ASM
+
+if KDEBUG
+externNP <CheckLAllocBreak>
+endif ;KDEBUG
+
+;-----------------------------------------------------------------------;
+; lenter ;
+; ;
+; Enters a critical region for the local heap. ;
+; ;
+; Arguments: ;
+; DS = automatic data segment containing local heap ;
+; ;
+; Returns: ;
+; DS:DI = address of LocalInfo for local heap ;
+; (li_lock field has been incremented) ;
+; ;
+; Error Returns: ;
+; CX == 1 if heap is busy ;
+; ;
+; Registers Preserved: ;
+; AX,BX,DX,SI,ES ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Oct 13, 2086 09:27:27p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lenter,<PUBLIC,NEAR>
+cBegin nogen
+ mov di,pLocalHeap
+ mov cx,1
+ xchg [di].li_lock,cx
+ jcxz enter1
+
+; Should really do a WaitEvent
+
+if KDEBUG
+ xor bx,bx
+ kerror ERR_LMEMCRIT,<lenter: local heap is busy>,bx,cx
+endif
+
+enter1: ret
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; lleave ;
+; ;
+; Leaves a critical region for the local heap. ;
+; ;
+; Arguments: ;
+; DS = automatic data segment containing local heap ;
+; ;
+; Returns: ;
+; DS:DI = address of LocalInfo for local heap ;
+; (li_lock field has been cleared) ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; AX,BX,DX,SI,ES ;
+; ;
+; Registers Destroyed: ;
+; CX ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Sun Oct 13, 2086 09:30:01p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lleave,<PUBLIC,NEAR>
+cBegin nogen
+ mov di,pLocalHeap
+ xor cx,cx
+ xchg ds:[di].li_lock,cx
+ jcxz leave1
+ ret
+leave1:
+
+; Should really do a PostEvent
+if KDEBUG
+ kerror ERR_LMEMCRIT,<lleave: local heap was not busy>
+endif
+
+cEnd nogen
+
+;-----------------------------------------------------------------------;
+; lhexpand ;
+; ;
+; Expands a local handle table. ;
+; ;
+; Arguments: ;
+; CX = #handle entries to allocate ;
+; DS:DI = local info structure ;
+; ;
+; Returns: ;
+; AX = address of handle table block of requested size ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; lalloc ;
+; hthread ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 01:48:21p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lhexpand,<PUBLIC,NEAR>
+cBegin nogen
+ xor ax,ax ; Allocate fixed local block
+ mov bx,cx
+ inc bx ; plus 1 for word at beginning & end
+ shl bx,1
+ shl bx,1
+ errnz <4-SIZE LocalHandleEntry>
+ push cx
+ call lalloc
+ pop cx
+ or ax,ax
+ jz lhfail
+ mov bx,ax
+ xchg [di].hi_htable,bx
+ push di ; Save DI
+ mov di,ax
+ mov ds:[di],cx
+ inc di
+ inc di
+ call hthread
+ mov ds:[di],bx ; Store pointer to next block
+ pop di ; Restore DI
+lhfail: mov cx,ax
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; lalign ;
+; ;
+; Aligns the size request for a local item to a multiple of 4 bytes. ;
+; ;
+; Arguments: ;
+; CF = 0 ;
+; BX = #bytes ;
+; CF = 1 get max amount ;
+; ;
+; Returns: ;
+; DX = #bytes aligned to next higher multiple of 4 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; nothing ;
+; ;
+; History: ;
+; ;
+; Tue March 10, 1987 -by- Bob Gunderson [bobgu] ;
+; To accomidate free list, must impose a minimum block size to prevent ;
+; allocating a block on top of the extended header of previous block. ;
+; ;
+; Tue Oct 14, 1986 01:56:42p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lalign,<PUBLIC,NEAR>
+cBegin nogen
+ jnc align0
+ mov bx,LA_MASK
+align0: cmp bx,SIZE LocalArenaFree
+ jae align2
+ mov bx,SIZE LocalArenaFree ; Must impose a minimum size
+align2: lea dx,[bx+LA_ALIGN]
+ and dl,LA_MASK
+ cmp dx,bx ; Test for overflow
+ jae align1 ; No, continue
+ mov dx,LA_MASK ; Yes, return largest possible size
+align1: ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; ldref ;
+; ;
+; Dereferences a local handle. ;
+; ;
+; Arguments: ;
+; SI = handle ;
+; ;
+; Returns: ;
+; AX = address of client data ;
+; BX = address of arena header ;
+; CH = lock count or zero for fixed objects ;
+; SI = handle table entry address or zero for fixed objects ;
+; ZF = 1 if NULL handle passed in ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; CL ;
+; ;
+; Calls: ;
+; lhdref ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 01:58:58p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc ldref,<PUBLIC,NEAR>
+cBegin nogen
+ xor cx,cx ; Zero lock count
+ mov ax,si ; Return handle if fixed object
+ test al,LA_MOVEABLE ; Is it moveable?
+ jnz dref3 ; Yes, go dereference handle
+ xor si,si ; Set SI to zero for fixed objects
+ or ax,ax ; No, were we passed NULL?
+ jz dref2 ; Yes, then all done
+dref1: mov bx,ax ; No, return BX pointing
+ and bl,LA_MASK ; ...to arena header
+ sub bx,la_fixedsize ; Leaving ZF = 0
+dref2: ret
+
+dref3: call lhdref ; Get true address in AX
+ ; and lock count in CH
+ife KDEBUG
+ jz done ; Compute arena header if valid true address
+ mov bx,ax ; See if arena header points to
+ sub bx,SIZE LocalArena
+done: ret ; No, return with ZF = 1
+else
+ test cl,LHE_DISCARDED ; Discarded?
+ jnz dref5 ; Yes, all done
+ or ax,ax ; Is there a true address?
+ jz dref4 ; No, then must be error
+ mov bx,ax ; See if arena header points to
+ sub bx,SIZE LocalArena
+ cmp [bx].la_handle,si ; handle table entry?
+ je dref5 ; Yes, continue
+dref4: xor bx,bx
+ kerror ERR_LMEMHANDLE,<LDREF: Invalid local handle>,bx,si
+ xor ax,ax
+dref5: or ax,ax
+ ret
+endif
+
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; lnotify ;
+; ;
+; Calls the local heap's notify proc (if any). ;
+; ;
+; Arguments: ;
+; AL = message code ;
+; BX = handle or largest free block ;
+; CX = optional argument ;
+; ;
+; Returns: ;
+; AX = return value from notify proc or AL ;
+; ZF = 1 if AX = 0 ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; ;
+; Registers Destroyed: ;
+; BX,CX,DX,ES ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Tue Oct 14, 1986 02:03:14p -by- David N. Weise [davidw] ;
+; Added this nifty comment block. ;
+;-----------------------------------------------------------------------;
+
+cProc lnotify,<PUBLIC,NEAR>
+cBegin nogen
+ cmp word ptr [di+2].li_notify,0
+ je notify1
+ xor ah,ah
+ cCall [di].li_notify,<ax,bx,cx>
+notify1:
+ or ax,ax
+ ret
+cEnd nogen
+
+
+; The remainder of this file implements the exported interface to the
+; local memory manager. A summary follows:
+;
+; HANDLE far PASCAL LocalAlloc( WORD, WORD );
+; HANDLE far PASCAL LocalReAlloc( HANDLE, WORD, WORD );
+; HANDLE far PASCAL LocalFree( HANDLE );
+; WORD far PASCAL LocalSize( HANDLE );
+; char * far PASCAL LocalLock( HANDLE );
+; BOOL far PASCAL LocalUnlock( HANDLE );
+; WORD far PASCAL LocalCompact( WORD );
+; WORD far PASCAL LocalShrink( HANDLE , WORD );
+; FARPROC far PASCAL LocalNotify( FARPROC );
+; #define LocalDiscard( h ) LocalReAlloc( h, 0, LMEM_MOVEABLE )
+; BOOL far PASCAL LocalInit( char *, char * );
+;
+; extern WORD * PASCAL pLocalHeap;
+;
+; #define dummy 0
+; #define LocalFreeze( dummy ) ( *(pLocalHeap+1) += 1 )
+; #define LocalThaw( dummy ) ( *(pLocalHeap+1) -= 1 )
+;
+
+cProc ILocalAlloc,<PUBLIC,FAR>,<si,di>
+ parmW flags
+ parmW nbytes
+cBegin
+ WOWTrace "LocalAlloc(#AX,#BX)",<<ax,flags>,<bx,nbytes>>
+ CheckHeap LocalAlloc
+ call lenter ; About to modify memory arena
+ jcxz la_ok
+ xor ax, ax
+ jmp la_crit
+la_ok:
+ mov ax,flags ; Allocate space for object
+ test al,LA_NOCOMPACT
+ jz all0
+ inc [di].hi_freeze
+all0: mov bx,nbytes
+ or bx,bx ; Zero length?
+ jnz alloc0 ; No, continue
+ and ax,LA_MOVEABLE ; Yes, moveable?
+ jz alloc1 ; No, return error
+ call halloc ; Yes, allocate handle
+ or ax,ax ; failure??
+ jz alloc1 ; yep... return a NULL
+ xor byte ptr [bx].lhe_address,LA_MOVEABLE ; and zero address field
+ or byte ptr [bx].lhe_flags,LHE_DISCARDED ; and mark as discarded
+ jmps alloc1 ; all done
+
+alloc0: test al,LA_MOVEABLE ; Is this a moveable object?
+ jz dont_need_handle
+ push ax
+ push bx
+ call halloc ; Allocate handle first.
+
+ or ax,ax
+ jnz all2 ; error?
+ pop bx ; yes, DON'T destroy the NULL in AX
+ pop bx
+ jmps alloc1
+all2:
+ pop bx
+ pop ax
+
+; pop bx
+; pop ax
+; jcxz alloc1
+
+ push cx ; this is handle
+ call lalloc
+ pop si ; get handle in index register
+ jnz got_space
+ call lhfree ; free the allocated handle
+ jmps alloc1
+
+got_space:
+ mov [si].lhe_address,ax ; Store address away.
+ mov bx,ax ; Store back link to handle in header
+ mov [bx-SIZE LocalArena].la_handle,si ; Mark as moveable block
+ or byte ptr [bx-SIZE LocalArena].la_prev,LA_MOVEABLE
+ mov ax,si ; return the handle
+ and dh,LHE_DISCARDABLE ; Discardable object?
+ jz alloc1 ; No, continue
+ mov [si].lhe_flags,dh ; Yes, save discard level in handle
+ jmps alloc1 ; table entry
+
+dont_need_handle:
+ call lalloc
+alloc1: test byte ptr flags,LA_NOCOMPACT
+ jz all1
+ dec [di].hi_freeze
+all1: call lleave ; Arena is consistent now
+la_crit:
+ or ax,ax
+ jnz @F
+ KernelLogError DBF_WARNING,ERR_LALLOC,"LocalAlloc failed" ; LocalAlloc failure
+ xor ax, ax ; preserve the return value
+@@:
+ mov cx,ax ; Let caller do jcxz to test failure
+ WOWTrace "LocalAlloc: #AX"
+cEnd
+
+
+cProc ILocalReAlloc,<PUBLIC,FAR>,<si,di>
+ parmW h
+ parmW nbytes
+ parmW rflags
+cBegin
+ WOWTrace "LocalReAlloc(#AX,#BX,#CX)",<<ax,h>,<bx,nbytes>,<cx,rflags>>
+ CheckHeap LocalReAlloc
+ call lenter ; About to modify memory arena
+ jcxz lr_ok
+ xor ax, ax
+ jmp lr_crit
+lr_ok:
+ test byte ptr rflags,LA_NOCOMPACT
+ jz rel0
+ inc [di].hi_freeze
+rel0:
+ mov si,h ; Dereference handle
+ call ldref
+ jz racreate ; If zero handle, check for re-creation.
+ test byte ptr rflags,LA_MODIFY ; Want to modify handle table flags
+ jnz ramodify ; Yes, go do it
+ mov si,bx ; SI = arena header
+ mov bx,ax ; Compute address of new next header
+ mov dx,nbytes ; assuming there is room.
+ cmp dx,SIZE LocalArenaFree ; Minimum size must be large enough
+ jae @F ; to a hold free header.
+ mov dx,SIZE LocalArenaFree
+@@: add bx,dx
+ call lalign
+ mov bx,[si].la_next ; Get address of current next header
+ cmp nbytes,0 ; Are we reallocing to zero length?
+ jne raokay ; No, continue
+ jcxz radiscard ; Yes, discard if not locked
+rafail:
+ KernelLogError DBF_WARNING,ERR_LREALLOC,"LocalReAlloc failed"
+ xor ax,ax
+ jmp raexit
+
+radiscard:
+
+; Here to discard object, when reallocating to zero size. This
+; feature is only enabled if the caller passes the moveable flag
+
+ test byte ptr rflags,LA_MOVEABLE ; Did they want to discard?
+ jz rafail ; No, then return failure.
+ mov al,LN_DISCARD ; AL = discard message code
+ xor cx,cx ; CX = disc level of 0 (means realloc)
+ mov bx,h ; BX = handle
+ call lnotify ; See if okay to discard
+ jz rafail ; No, do nothing
+ xor ax,ax ; Yes, free client data
+ mov bx,si
+ call lfree
+ jz rax ; Return NULL if freed a fixed block
+ mov [si].lhe_address,ax ; No, zero addr in handle table entry
+ or [si].lhe_flags,LHE_DISCARDED ; and mark as discarded
+ jmps rasame ; Return original handle, except
+ ; LocalLock will now return null.
+
+ramodify:
+ mov ax,rflags ; Get new flags
+ or si,si ; Moveable object?
+ jz rasame ; No, all done
+ and [si].lhe_flags,not LHE_USERFLAGS ; Clear old flags
+ and ah,LHE_USERFLAGS; Get new flags
+ or [si].lhe_flags,ah ; Store new flags in handle table entry
+ jmps rasame
+
+racreate:
+ test cl,LHE_DISCARDED ; Is this a discarded handle?
+ jz rasame ; No, return original value
+ mov bx,nbytes ; BX = new requested size
+ push si ; save handle
+ mov ax,LA_MOVEABLE ; Reallocating a moveable object
+ or ax,rflags ; ...plus any flags from the caller
+ call lalloc ; Allocate a new block
+ pop si ; restore existing handle
+ jz rafail
+ xor [si].lhe_flags,LHE_DISCARDED ; and mark as not discarded
+ jmp ram2
+
+raokay:
+; Here if not trying to realloc this block to zero
+; SI = arena header of current block
+; AX = client address of current block
+; BX = arena header of next block
+; CH = lock count of current block
+; DX = new next block, based on new requested size
+ cmp dx,bx ; Are we growing or shrinking?
+ ja ragrow ; We are growing
+rashrink: ; We are shrinking
+; Here to shrink a block
+; SI = arena header of current block
+; BX = arena header of next block
+; DX = new next block, based on new requested size
+ push si
+ mov si,dx ; SI = new next block
+ add dx,LA_MINBLOCKSIZE ; Test for small shrinkage
+ jnc @F ; No overflow
+ pop bx ; Overflowed, obviously no room!
+ jmp rasame ; Clear stack and return same handle
+@@: cmp dx,bx ; Is there room from for free block?
+ pop bx ; BX = current block
+ jae rasame ; No, then no change to make
+ ; Splice extra free space into arena
+ mov cx,si ; [si].la_next = [bx].la_next
+ xchg [bx].la_next,cx ; [bx].la_next = si
+ mov [si].la_prev,bx ; [si].la_prev = bx
+ xchg si,cx
+ and [si].la_prev,LA_ALIGN
+ jz splice1 ; If free then coelesce
+ inc [di].hi_count ; No, adding new arena entry
+ jmps splice2
+splice1:
+
+; next block is free, must make the new block a larger free block
+
+; first remove the current free block [SI] from the free list
+
+ xchg bx,si
+ call lfreedelete
+ xchg bx,si
+ mov si,[si].la_next
+ and [si].la_prev,LA_ALIGN
+
+splice2:
+ or [si].la_prev,cx ; [[si].la_next].la_prev = si
+ xchg si,cx
+ mov [si].la_next,cx
+ mov bx,si ; BX = new block
+ xor si,si ; don't know where to insert
+ call lfreeadd ; add to free list
+rasame:
+ mov ax,h ; Return the same handle
+rax: jmps raexit ; All done
+
+; Here to try to grow the current block
+; AX = client address of current block
+; SI = arena header of current block
+; BX = arena header of next block
+; DX = new next block, based on new requested size
+ragrow:
+if KDEBUG
+ call CheckLAllocBreak
+ jc rafail1
+endif
+
+ test byte ptr [bx].la_prev,LA_BUSY ; Is next block free?
+ jnz ramove ; No, try to move the current block
+ cmp dx,[bx].la_next ; Yes, is free block big enough?
+ ja ramove ; No, try to move the current block
+ mov cx,bx ; Yes, save free block address in CX
+ call ljoin ; and attach to end of current block
+ test rflags,LA_ZEROINIT ; Zero fill extension?
+ jz ranz ; No, continue
+ call lzero ; Yes, zero fill
+ranz:
+ jmp rashrink ; Now shrink block to correct size
+
+; Here to try to move the current block
+; AX = client address of current block
+; SI = arena header of current block
+; CH = lock count of current block
+ramove:
+ mov dx,rflags ; get the passed in flags
+ mov bx,LA_MOVEABLE ; Determine if okay to move this guy
+ jcxz ramove1 ; Continue if this handle not locked
+ test dx,bx ; Locked. Did they say move anyway?
+ jnz ramove1 ; Yes, go do it
+rafail1:jmp rafail
+ramove1:
+ or dx,bx ; make sure moveable bit set
+ test h,bx ; Is it a moveable handle?
+ jnz ram1 ; Yes, okay to move
+ test rflags,bx ; No, did they say it's okay to move?
+ jz rafail1 ; No, then fail
+ xor dx,bx ; turn off moveable bit
+ram1:
+; We do this because the lalloc can move the old block to a
+; block that is larger than the requested new block. This can
+; happen if we LocalCompact durring the lalloc call. (bobgu 8/27/87)
+ mov bx,[si].la_next
+ sub bx,ax ; # client bytes in current block
+ push bx ; save it for later
+
+ mov ax,dx ; AX = allocation flags
+ mov bx,nbytes ; BX = new requested size
+ call lalloc ; Allocate a new block
+
+ pop cx ; CX = client size of old block
+ jz rafail1
+ push cx ; save it away again
+
+ push ax ; Call notify proc
+ mov cx,ax ; with new location
+ mov bx,h ; handle
+ mov al,LN_MOVE
+ call lnotify ; Notify client of new location
+ mov si,h
+ call ldref ; BX = old arena header address
+ mov si,ax ; SI = old client address
+ pop ax ; AX = new client address
+
+ pop cx ; get back size of old client
+; mov cx,[bx].la_next ; Compute length of old client data
+; sub cx,si
+ call lrepsetup ; Setup for copy of words
+ push di
+ mov di,ax ; DI = new client data address
+ rep movsw ; Copy old client data to new area
+ pop di ; Restore DI
+ call lfree ; Free old block
+ jz raexit
+ram2:
+ mov [si].lhe_address,ax ; Set new client data address
+ xchg ax,si ; Return original handle
+ ; Set back link to handle in new block
+ or byte ptr [si-SIZE LocalArena].la_prev,LA_MOVEABLE
+ mov [si-SIZE LocalArena].la_handle,ax
+raexit:
+ test byte ptr rflags,LA_NOCOMPACT
+ jz rel1
+ dec [di].hi_freeze
+rel1:
+ call lleave ; Arena is consistent now
+lr_crit:
+ mov cx,ax ; Let caller do jcxz to test failure
+ WOWTrace "LocalReAlloc: #AX"
+cEnd
+
+
+cProc ILocalFree,<PUBLIC,FAR>,<si,di>
+ parmW h
+cBegin
+ WOWTrace "LocalFree(#AX)",<<ax,h>>
+ call lenter ; About to modify memory arena
+ jcxz lf_ok
+ xor ax, ax
+ jmp lf_crit
+lf_ok:
+ CheckHeap LocalFree
+ mov si,h ; Dereference handle
+ call ldref
+ jz free1 ; Free handle if object discarded
+if KDEBUG
+ push ds
+ SetKernelDS
+ mov ds,curTDB
+ assumes ds, nothing
+ cmp ds:[TDB_ExpWinVer],201h
+ pop ds
+ jb dont_do_error_checking
+
+ or ch,ch ; No, is the handle locked?
+ jz freeo ; Yes, then don't free
+ xor bx,bx
+ kerror ERR_LMEMUNLOCK,<LocalFree: freeing locked object>,bx,h
+ mov si,h ; Dereference handle again
+ call ldref
+freeo:
+dont_do_error_checking:
+endif
+ call lfree ; No, free the object
+free1: call lhfree ; and any handle
+freex: call lleave ; Arena is consistent now
+lf_crit:
+ WOWTrace "LocalFree: #AX"
+cEnd
+
+cProc ILocalSize,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+; CheckHeap LocalSize
+ push si
+ mov si,sp
+ mov si,ss:[si+6] ; Dereference handle
+ call ldref ; into BX
+ jz size1 ; Done if AX = zero
+ sub ax,[bx].la_next ; Otherwise size =
+ neg ax ; - (client address - next block address)
+size1: mov cx,ax ; Let caller do jcxz to test failure
+ pop si
+ ret 2
+cEnd nogen
+
+
+cProc ILocalFlags,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+; CheckHeap LocalFlags
+ push si
+ mov si,sp
+ mov si,ss:[si+6] ; Dereference handle
+ call ldref ; into BX
+ mov cx,si
+ jcxz flags1 ; Done if not moveable
+ mov cx,word ptr [si].lhe_flags ; Return flags and lock count
+flags1:
+ xchg cl,ch ; Return lock count in low half
+ mov ax,cx ; Let caller do jcxz to test failure
+ pop si
+ ret 2
+cEnd nogen
+
+
+
+if KDEBUG
+cProc ILocalLock,<PUBLIC,FAR>,<si>
+ parmW h
+cBegin
+ WOWTrace "LocalLock(#AX)",<<ax,h>>
+; CheckHeap LocalLock
+ mov si,h
+ call ldref ; SI = handle table entry
+ jz lock2 ; Done if invalid handle or discarded
+ or si,si
+ jz lock2 ; or if not moveable
+
+ inc [si].lhe_count ; Increment usage count
+ jnz lock1
+ xor cx,cx
+ kerror ERR_LMEMLOCK,<LocalLock: Object usage count overflow>,cx,h
+ dec [si].lhe_count ; Keep pinned at max value
+lock1: mov ax,[si].lhe_address ; Return true address in AX
+lock2:
+ or ax, ax
+ jnz @F
+ KernelLogError DBF_WARNING,ERR_LLOCK,"LocalLock failed"
+ xor ax,ax ; Get back the NULL value in ax
+@@: mov cx,ax ; Let caller do jcxz to test failure
+ WOWTrace "LocalLock: #AX"
+cEnd
+
+else
+cProc ILocalLock,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+ mov bx,sp ; Get handle parameter from stack
+ mov bx,SS:[bx+4]
+ mov ax,bx ; Return in AX
+ test bl,LA_MOVEABLE ; Test for moveable (also null)
+ jz lock2 ; Return if not moveable or null
+ test [bx].lhe_flags,LHE_DISCARDED ; Return zero if discarded
+ jnz lock1
+ inc [bx].lhe_count ; Increment usage count
+ jz lock3 ; Special case if overflow
+lock1:
+ mov ax,[bx].lhe_address ; Return true address in AX or zero
+lock2: mov cx,ax ; Let caller do jcxz to test failure
+ ret 2
+lock3:
+ dec [bx].lhe_count ; Ooops, keep pinned at max value
+ jmp lock1
+
+cEnd nogen
+endif
+
+
+if KDEBUG
+cProc ILocalUnlock,<PUBLIC,FAR>,<si>
+ parmW h
+cBegin
+ WOWTrace "LocalUnlock(#AX)",<<ax,h>>
+; CheckHeap LocalUnlock
+ mov si,h
+ call ldref ; SI = handle table entry
+ jz unlock1 ; Done if invalid handle or discarded
+ xor ax,ax
+ or si,si
+ jz unlock1 ; or if not moveable
+
+ or ch, ch
+ jz unlockerr
+ dec ch ; Decrement usage count
+ cmp ch,0FFh-1 ; 0 -> ff, ff -> fe
+ jae unlock1 ; Return if pinned or already unlocked
+ mov [si].lhe_count,ch
+; mov ax,bx
+ mov al,ch
+ cbw
+ jmps unlock1
+unlockerr:
+ xor cx,cx
+ kerror ERR_LMEMUNLOCK,<LocalUnlock: Object usage count underflow>,cx,h
+ xor ax,ax
+unlock1:
+ mov cx,ax ; Let caller do jcxz to test failure
+ WOWTrace "LocalUnlock: #AX"
+cEnd
+
+else
+cProc ILocalUnlock,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+ mov bx,sp ; Get handle parameter from stack
+ mov bx,SS:[bx+4]
+ xor ax,ax
+ test bl,LA_MOVEABLE ; Test for moveable (also null)
+ jz unlock1 ; Return if not moveable or null
+ mov cx,word ptr [bx].lhe_flags
+ errnz <2-lhe_flags>
+ errnz <3-lhe_count>
+ and cl,LHE_DISCARDED
+ jnz unlock1 ; Return if discarded
+ dec ch ; Decrement usage count
+ cmp ch,0FFh-1 ; 0 -> ff, ff -> fe
+ jae unlock1 ; Return if pinned or already unlocked
+ mov [bx].lhe_count,ch
+; mov ax,bx
+ mov al,ch
+ cbw
+unlock1:
+ mov cx,ax ; Let caller do jcxz to test failure
+ ret 2
+cEnd nogen
+endif
+
+
+
+cProc LocalHandle,<PUBLIC,FAR>
+; parmW h
+cBegin nogen
+ mov bx,sp
+ mov bx,SS:[bx+4]
+ test bl,LA_MOVEABLE
+ jz lh1
+ mov ax,bx
+ mov bx,[bx-SIZE LocalArena].la_handle
+ cmp [bx].lhe_address,ax
+ je lh1
+ xor bx,bx
+lh1:
+ mov ax,bx
+ ret 2
+cEnd nogen
+
+
+cProc LocalCompact,<PUBLIC,FAR>,<si,di>
+ parmW minBytes
+cBegin
+ CheckHeap LocalCompact
+ call lenter ; About to modify memory arena
+ jcxz lc_ok
+ xor ax, ax
+ jmp lc_crit
+lc_ok:
+ mov bx,minBytes
+ clc
+ call lalign
+ call lcompact
+ or ax,ax
+ jz compact1
+ sub ax,SIZE LocalArena ; Reduce available size by header size
+compact1:
+ call lleave ; Arena is consistent now
+lc_crit:
+cEnd
+
+
+cProc LocalShrink,<PUBLIC,FAR>,<si,di>
+ parmW hseg
+ parmW wsize
+cBegin
+ mov ax,hseg
+ or ax,ax ; use heap in current DS ?
+ jz ls_useds ; yes
+
+; Use the segment handle passed
+ push ax
+ call GlobalHandle
+ or ax,ax ; valid handle ?
+ jz ls_errexit ; no....
+ mov ds,dx ; set the proper DS
+ls_useds:
+; check the heap and lock it
+ CheckHeap LocalShrink
+ call lenter ; About to modify memory arena
+ jcxz ls_ok
+ xor ax, ax
+ jmp short ls_crit
+ls_ok:
+
+ mov bx,wsize ; get requested min size
+ call lshrink ; Let's get small
+; AX = new local heap size
+ call lleave ; Arena is consistent now
+ls_crit:
+ls_errexit:
+
+cEnd
+
+
+cProc LocalNotifyDefault,<PUBLIC,FAR>,<si,di>
+ parmW msg
+ parmW handle ; or largest free block
+ parmW arg1
+cBegin
+ mov ax,msg
+ or ax,ax
+ jnz dlnexit1
+ cCall GlobalHandle,<ds>
+ or ax,ax
+ jz dlnexit1
+ ; Fix for FORMBASE who uses a fixed
+ ; segment for a local heap. This blows
+ ; up if we cause the calling segment
+ ; to be discarded since the DS saved by
+ ; Local???? is a fixed segment which
+ ; SearchStack can't handle. Confused?
+ ; This was not a problem in 2.x because
+ ; 2.x failed to grow a fixed object.
+ ; Using a fixed segment for a local heap
+ ; is not valid and this is really a problem
+ ; with FORMBASE.
+ mov si,ax
+ cCall GlobalFlags,<si> ; Get flags
+ xchg ah, al
+ push ax
+ cCall GlobalSize,<si>
+ sub ax, handle ; Temorarily subtract out largest free
+ pop bx ; Get flags in BX
+ xor cx,cx
+ add ax,arg1
+ adc dx,cx ; Fail if DS attempts to grow
+ jnz dln_too_large ; beyond 64k.
+ add ax,18h ; since li_extra isn't guaranteed
+ adc dx,cx
+ jnz dln_too_large
+ add ax,[di].li_extra
+ adc dx,cx ; Fail if DS attempts to grow
+ jnz @F ; beyond 64k.
+ add ax, handle ; add back largest free
+ adc dx, cx
+ jnz @F
+ cmp ax,0FFF0h
+ jbe dln0
+@@: mov ax,0FFF0h
+ xor dx,dx
+ jmps dln0
+dln_too_large:
+ xor ax,ax
+dlnexit1:
+ jmp dlnexit
+dln0:
+ test si,GA_FIXED ; Is DS fixed?
+ jnz dln1 ; Yes, must grow in place
+ cmp bh,1 ; No, is lock count 1?
+ jne dln1 ; No must grow in place if locked
+ or cl,GA_MOVEABLE ; Yes, okay to move even though locked
+dln1:
+ push bx
+grow_DS:
+ cCall GlobalReAlloc,<si,dxax,cx>
+ pop bx
+ jcxz dlnexit
+ push bx
+ cCall GlobalSize,<ax>
+
+ or dx,dx ; Did we get rounded up >= 64K?
+ jz @F ; No, OK
+ mov ax,0FFFFh ; This only happens under 386pmode
+@@:
+ mov bx,ax
+ sub bx,la_freefixedsize
+ and bl,LA_MASK
+ mov di,ds:[pLocalHeap]
+ mov si,[di].hi_last
+ mov [bx].la_next,bx
+ mov [bx].la_prev,si
+ or byte ptr [bx].la_prev,LA_BUSY
+ mov [si].la_next,bx
+
+; Maintain the free list.
+
+ mov ax,[si].la_free_prev
+ mov [bx].la_free_prev,ax
+ mov [bx].la_free_next,bx
+ mov [bx].la_size,WORD PTR la_freefixedsize
+ push si
+ mov si,ax
+ mov [si].la_free_next,bx
+ pop si
+
+ mov [di].hi_last,bx
+ inc [di].hi_count
+ mov bx,si
+ call lfree
+
+; Don't do this... (bobgu 8/4/87)
+; stc
+; call lalign
+; call lcompact
+
+ mov ax,1
+ pop bx
+ mov ax,1
+dlnexit:
+cEnd
+
+cProc LocalNotifyDib,<PUBLIC,FAR>,<si,di>
+ parmW msg
+ parmW handle ; or largest free block
+ parmW arg1
+cBegin
+ mov ax,msg
+ or ax,ax
+ jnz dlnexit1dib
+ cCall GlobalHandle,<ds>
+ or ax,ax
+ jz dlnexit1dib
+ ; Fix for FORMBASE who uses a fixed
+ ; segment for a local heap. This blows
+ ; up if we cause the calling segment
+ ; to be discarded since the DS saved by
+ ; Local???? is a fixed segment which
+ ; SearchStack can't handle. Confused?
+ ; This was not a problem in 2.x because
+ ; 2.x failed to grow a fixed object.
+ ; Using a fixed segment for a local heap
+ ; is not valid and this is really a problem
+ ; with FORMBASE.
+ mov si,ax
+ cCall GlobalFlags,<si> ; Get flags
+ xchg ah, al
+ push ax
+ cCall GlobalSize,<si>
+ sub ax, handle ; Temorarily subtract out largest free
+ pop bx ; Get flags in BX
+ xor cx,cx
+ add ax,arg1
+ adc dx,cx ; Fail if DS attempts to grow
+ jnz dib_too_large ; beyond 64k.
+ add ax,18h ; since li_extra isn't guaranteed
+ adc dx,cx
+ jnz dib_too_large
+ add ax,[di].li_extra
+ adc dx,cx ; Fail if DS attempts to grow
+ jnz @F ; beyond 64k.
+ add ax, handle ; add back largest free
+ adc dx, cx
+ jnz @F
+ cmp ax,0FFF0h
+ jbe dln0dib
+@@: mov ax,0FFF0h
+ xor dx,dx
+ jmps dln0dib
+dib_too_large:
+ xor ax,ax
+dlnexit1Dib:
+ jmp dlnexitdib
+dln0dib:
+ test si,GA_FIXED ; Is DS fixed?
+ jnz dln1dib ; Yes, must grow in place
+ cmp bh,1 ; No, is lock count 1?
+ jne dln1dib ; No must grow in place if locked
+ or cl,GA_MOVEABLE ; Yes, okay to move even though locked
+dln1dib:
+ push bx
+ cCall DibReAlloc,<ds,ax>
+ or ax,ax
+ jz dlnexitdib0
+ cCall GlobalSize,<si>
+
+ or dx,dx ; Did we get rounded up >= 64K?
+ jz @F ; No, OK
+ mov ax,0FFFFh ; This only happens under 386pmode
+@@:
+ mov bx,ax
+ sub bx,la_freefixedsize
+ and bl,LA_MASK
+ mov di,ds:[pLocalHeap]
+ mov si,[di].hi_last
+ mov [bx].la_next,bx
+ mov [bx].la_prev,si
+ or byte ptr [bx].la_prev,LA_BUSY
+ mov [si].la_next,bx
+
+; Maintain the free list.
+
+ mov ax,[si].la_free_prev
+ mov [bx].la_free_prev,ax
+ mov [bx].la_free_next,bx
+ mov [bx].la_size,WORD PTR la_freefixedsize
+ push si
+ mov si,ax
+ mov [si].la_free_next,bx
+ pop si
+
+ mov [di].hi_last,bx
+ inc [di].hi_count
+ mov bx,si
+ call lfree
+
+; Don't do this... (bobgu 8/4/87)
+; stc
+; call lalign
+; call lcompact
+
+
+ mov ax,1
+dlnexitdib0:
+ pop bx
+dlnexitdib:
+cEnd
+
+sEnd CODE
+
+externFP Far_lalign
+externFP Far_lrepsetup
+if KDEBUG
+externFP Far_lfillCC
+endif
+
+sBegin NRESCODE
+assumes CS,NRESCODE
+assumes DS,NOTHING
+assumes ES,NOTHING
+
+cProc ILocalNotify,<PUBLIC,FAR>
+; parmD lpProc
+cBegin nogen
+ mov bx,sp
+ mov ax,SS:[bx+4]
+ mov dx,SS:[bx+6]
+ mov bx,ds:[pLocalHeap]
+ xchg word ptr [bx].li_notify,ax
+ xchg word ptr [bx].li_notify+2,dx
+ ret 4
+cEnd nogen
+
+
+cProc LocalInit,<PUBLIC,FAR>,<ds,si,di>
+ parmW pseg
+ parmW pstart
+ parmW pend
+cBegin
+
+; Init current DS if none passed.
+
+ mov cx,pseg
+ jcxz li1
+ mov ds,cx
+li1:
+
+; Place local arena info at the beginning
+
+ mov bx,pstart
+ or bx,bx
+ jnz li2
+ cCall GlobalSize,<ds>
+
+; Here we must do a little checking... The global memory manager may have
+; rounded up the size on us so that the DS is >=64K! If this has happened,
+; we can simply ignore the extra (since app can't look at it anyway) and
+; pretend the DS is actually 0000FFFFH bytes big.
+
+ or dx,dx ; Did we get rounded up >= 64K?
+ jz li1a ; No, OK
+ mov ax,0FFFFH ; Pretend heap is 64K-1
+li1a:
+ mov bx,ax
+ dec bx
+ xchg pend,bx
+ sub bx,pend
+ neg bx ; BX = first byte in arena
+li2:
+ clc
+ call Far_lalign
+ mov bx,dx ; DX = addr of first block to use
+
+; OK, so here's how it works... In order to keep a free block list, there
+; are 4 blocks allocated initially. First is a dummy marker block that is
+; free but marked busy. Second is the local arena information block which
+; is a standard busy block. Third is the really big free block. And lastly
+; is another busy type free block. All free blocks have an extended header
+; in order to keep a free block list.
+
+; Reserve room for the first free busy block.
+
+ lea bx,[bx].la_freefixedsize ; move over first free block
+ push dx ; preserve first free block address
+ clc
+ call Far_lalign
+ mov bx,dx ; BX = arena info block address
+ pop dx ; DX = first block address
+ push dx ; * Save the address of the first
+ push bx ; * two block on the stack for later
+
+; DI = client address of info block.
+
+ lea di,[bx].la_fixedsize
+ xor ax,ax ; Zero local arena info
+ mov cx,pend
+ cmp bx,cx ; start > end?
+
+;;;;;;; jae lix
+ jb li21
+ pop dx ; clean up the stack first
+ pop dx
+ jmp lix
+li21:
+ sub cx,di
+ call Far_lrepsetup
+ push di
+ rep stosw
+ pop di
+ lea bx,[di].SIZE LocalInfo
+if KDEBUG
+ mov [di].hi_pstats,bx
+ add bx,SIZE LocalStats
+
+ifdef DISABLE
+
+; Set the heap checking flag.
+
+ push es
+ push dx
+ cCall GlobalMasterHandle
+ mov es,dx
+ mov ax,es:[hi_check]
+ pop dx
+ pop es
+else
+ push es
+ push _DATA
+ pop es
+assumes es,DATA
+;
+; hi_check = 0;
+; if (DebugOptions & DBO_CHECKHEAP)
+; {
+; hi_check = 1
+; if (DebugOptions & DBO_CHECKFREE)
+; hi_check = 2;
+; }
+;
+ xor ax,ax
+ test es:DebugOptions,DBO_CHECKHEAP
+ jz @F
+ inc ax
+ test es:DebugOptions,DBO_CHECKFREE
+ jz @F
+ inc ax
+@@:
+assumes es,NOTHING
+ pop es
+endif
+ mov [di].hi_check,ax
+endif
+
+; set the rest of the heap info
+
+ mov byte ptr [di].hi_hdelta,32
+ mov byte ptr [di].hi_count,4
+ mov [di].hi_first,dx
+ mov word ptr [di].li_notify,codeOFFSET LocalNotifyDefault
+ mov word ptr [di].li_notify+2,codeBASE
+ mov word ptr [di].hi_hexpand,codeOFFSET lhexpand
+ mov [di].li_extra,512
+ mov [di].li_sig,LOCALHEAP_SIG
+
+; Move SI to first aligned block after info record
+
+ clc
+ call Far_lalign
+ mov si,dx
+
+; Move BX to last aligned block at end of local heap
+
+ mov bx,pend ; BX = end address
+ sub bx,la_freefixedsize ; Make room for an arena header
+ and bl,LA_MASK ; Align downwards to 4 byte boundary
+
+ cmp bx, si ; If heap is too small, the
+ ja @f ; supposed free block could be
+ xor ax, ax ; beyond the end block
+ jmp lix
+@@:
+
+; Setup reserved pointer in DS to point to LocalInfo
+
+ mov [di].hi_last,bx
+ mov ds:[pLocalHeap],di
+
+; Finish linking entries in the local heap.
+;
+; DX = address of the first arena block. Free busy marker.
+; DI = address of the element which contains the local heap
+; information struc.
+; SI = address of large free block that is the initial heap.
+; BX = address of a zero length arena element that is used to
+; mark the end of the local heap.
+;
+;
+; This last arena element is always busy, with a length of
+; zero. This allows us to always calculate the length of an
+; arena entry by subtracting the address of the arena element
+; from the hi_next field of the arena element (see lsize subr)
+
+ pop di ; Get the address of the first two
+ pop dx ; ... blocks off the stack
+
+; Setup first block in arena, busy free block.
+
+ xchg bx,dx ;bx = first block (temporarily)
+ lea ax,[bx+LA_BUSY] ; ...as a busy block
+ mov [bx].la_prev,ax ; point to self
+ mov [bx].la_next,di ; point to next
+ mov [bx].la_free_prev,bx ; previous free block is self
+ mov [bx].la_free_next,si ; next free is large block
+ mov [bx].la_size,WORD PTR la_freefixedsize ; set the block size
+ xchg bx,dx ; back to normal
+
+; Setup block that contains info structure.
+
+ xchg dx,bx
+ lea ax,[bx+LA_BUSY] ; ...as a busy block
+ xchg dx,bx
+ mov [di].la_prev,ax ; point to previous block
+ mov [di].la_next,si ; point to next block
+
+; Setup large free block with extended free block header.
+
+ mov [si].la_prev,di ; Point middle block to first and
+ mov [si].la_next,bx ; last blocks
+ mov [si].la_free_prev,dx ; previous free block
+ mov [si].la_free_next,bx ; next free block
+ mov ax,bx
+ sub ax,si
+ mov [si].la_size,ax ; length of free block
+
+if KDEBUG
+ xchg si,bx ; BX = large free block
+ call Far_lfillCC ; Fill with 0CCh
+ xchg si,bx
+endif
+
+; Setup last free block with extended header.
+
+ mov [bx].la_next,bx ; Point last block to middle and itself
+ lea ax,[si+LA_BUSY] ; ...as a busy block
+ mov [bx].la_prev,ax
+ mov [bx].la_free_prev,si ; previous free block
+ mov [bx].la_free_next,bx ; next free block is self
+ mov [bx].la_size,WORD PTR la_freefixedsize ; set the block size
+
+; Set the minimum size in arena header.
+
+ mov bx,ds:[pLocalHeap]
+ mov ax,[bx].hi_last
+ add ax,SIZE LocalArenaFree
+ sub ax,[bx].hi_first
+ mov [bx].li_minsize,ax
+
+ cCall GlobalLock,<ds> ; Make moveable DS initially locked.
+ ; (see LocalNotifyDefault)
+ mov al,1
+lix:
+ mov cx,ax
+cEnd
+
+
+;-----------------------------------------------------------------------;
+; LocalCountFree ;
+; ;
+; Return the count of free bytes in the local heap. This was motivated ;
+; by the InitApp routines that want at least 4K available to continue ;
+; the app running. ;
+; ;
+; Arguments: ;
+; DS = heap segment ;
+; ;
+; Returns: ;
+; AX = free bytes in local heap ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; all ;
+; ;
+; Registers Destroyed: ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Aug 15, 1987 04:35:55p -by- Bob Gunderson [bobgu] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+
+cProc LocalCountFree,<PUBLIC,FAR>
+cBegin nogen
+ push di
+ push si
+ mov di,pLocalHeap
+ lea si, [di].li_sig
+ cCall FarValidatePointer,<ds,si>
+ or ax, ax ; OK pointer?
+ jz countexit ; no, just exit
+ xor ax,ax ; start with 0 bytes free
+ cmp [di].li_sig, LOCALHEAP_SIG
+ jne countexit ; No local heap!!
+ mov si,[di].hi_last ; sentenal block
+ mov di,[di].hi_first ; arena header
+ mov di,[di].la_free_next ; first free block
+countloop:
+ cmp di,si
+ jz countexit
+ add ax,[di].la_size ; count size of this block
+ sub ax,SIZE LocalArenaFree ; less block overhead
+ mov di,[di].la_free_next ; next free block
+ jmp countloop
+countexit:
+ pop si
+ pop di
+ ret
+cEnd nogen
+
+
+
+;-----------------------------------------------------------------------;
+; LocalHeapSize ;
+; ;
+; Return the # bytes allocated to the local heap. ;
+; ;
+; Arguments: ;
+; DS = heap segment ;
+; ;
+; Returns: ;
+; AX = size of local heap ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,SI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; BX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+; Sat Aug 15, 1987 04:35:55p -by- Bob Gunderson [bobgu] ;
+; Wrote it. ;
+;-----------------------------------------------------------------------;
+
+
+cProc LocalHeapSize,<PUBLIC,FAR>
+cBegin nogen
+ mov bx,pLocalHeap
+ mov ax,[bx].hi_last
+ sub ax,[bx].hi_first
+ ret
+cEnd nogen
+
+
+;-----------------------------------------------------------------------;
+; LocalHandleDelta ;
+; ;
+; Change the number of handles to allocate each time ;
+; ;
+; Arguments: ;
+; delta = new # of handles or 0 ;
+; DS = heap segment ;
+; ;
+; Returns: ;
+; AX = new number of handles ;
+; ;
+; Error Returns: ;
+; ;
+; Registers Preserved: ;
+; CX,DX,SI,SI,DS,ES ;
+; ;
+; Registers Destroyed: ;
+; BX ;
+; ;
+; Calls: ;
+; ;
+; History: ;
+; ;
+;-----------------------------------------------------------------------;
+
+
+cProc LocalHandleDelta,<PUBLIC,FAR>
+ parmW delta
+cBegin
+ mov bx,pLocalHeap
+ mov ax, delta
+ or ax, ax ; Zero means return present value
+ jz return_present_value
+ mov ax, delta
+ mov [bx].hi_hdelta, ax ; Set new value
+return_present_value:
+ mov ax, [bx].hi_hdelta
+cEnd
+
+sEnd NRESCODE
+
+end