diff options
Diffstat (limited to 'private/mvdm/wow16/kernel31/linterf.asm')
-rw-r--r-- | private/mvdm/wow16/kernel31/linterf.asm | 1572 |
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 |