347 lines
11 KiB
C
347 lines
11 KiB
C
/*
|
|
* Local heap functions
|
|
*
|
|
* Copyright 1995 Alexandre Julliard
|
|
* Copyright 1996 Huw Davies
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Note:
|
|
* All local heap functions need the current DS as first parameter
|
|
* when called from the emulation library, so they take one more
|
|
* parameter than usual.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "wine/winbase16.h"
|
|
#include "instance.h"
|
|
#include "local.h"
|
|
#include "module.h"
|
|
#include "stackframe.h"
|
|
#include "toolhelp.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(local);
|
|
|
|
typedef struct
|
|
{
|
|
/* Arena header */
|
|
WORD prev; /* Previous arena | arena type */
|
|
WORD next; /* Next arena */
|
|
/* Start of the memory block or free-list info */
|
|
WORD size; /* Size of the free block */
|
|
WORD free_prev; /* Previous free block */
|
|
WORD free_next; /* Next free block */
|
|
} LOCALARENA;
|
|
|
|
#define ARENA_HEADER_SIZE 4
|
|
#define ARENA_HEADER( handle) ((handle) - ARENA_HEADER_SIZE)
|
|
|
|
/* Arena types (stored in 'prev' field of the arena) */
|
|
#define LOCAL_ARENA_FREE 0
|
|
#define LOCAL_ARENA_FIXED 1
|
|
|
|
#include "pshpack1.h"
|
|
|
|
typedef struct
|
|
{
|
|
WORD check; /* 00 Heap checking flag */
|
|
WORD freeze; /* 02 Heap frozen flag */
|
|
WORD items; /* 04 Count of items on the heap */
|
|
WORD first; /* 06 First item of the heap */
|
|
WORD pad1; /* 08 Always 0 */
|
|
WORD last; /* 0a Last item of the heap */
|
|
WORD pad2; /* 0c Always 0 */
|
|
BYTE ncompact; /* 0e Compactions counter */
|
|
BYTE dislevel; /* 0f Discard level */
|
|
DWORD distotal; /* 10 Total bytes discarded */
|
|
WORD htable; /* 14 Pointer to handle table */
|
|
WORD hfree; /* 16 Pointer to free handle table */
|
|
WORD hdelta; /* 18 Delta to expand the handle table */
|
|
WORD expand; /* 1a Pointer to expand function (unused) */
|
|
WORD pstat; /* 1c Pointer to status structure (unused) */
|
|
FARPROC16 notify WINE_PACKED; /* 1e Pointer to LocalNotify() function */
|
|
WORD lock; /* 22 Lock count for the heap */
|
|
WORD extra; /* 24 Extra bytes to allocate when expanding */
|
|
WORD minsize; /* 26 Minimum size of the heap */
|
|
WORD magic; /* 28 Magic number */
|
|
} LOCALHEAPINFO;
|
|
|
|
#include "poppack.h"
|
|
|
|
#define LOCAL_HEAP_MAGIC 0x484c /* 'LH' */
|
|
|
|
/* All local heap allocations are aligned on 4-byte boundaries */
|
|
#define LALIGN(word) (((word) + 3) & ~3)
|
|
|
|
#define ARENA_PTR(ptr,arena) ((LOCALARENA *)((char*)(ptr)+(arena)))
|
|
#define ARENA_PREV(ptr,arena) (ARENA_PTR((ptr),(arena))->prev & ~3)
|
|
#define ARENA_NEXT(ptr,arena) (ARENA_PTR((ptr),(arena))->next)
|
|
#define ARENA_FLAGS(ptr,arena) (ARENA_PTR((ptr),(arena))->prev & 3)
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalInit (KERNEL.4)
|
|
*/
|
|
BOOL16 WINAPI LocalInit16( HANDLE16 selector, WORD start, WORD end )
|
|
{
|
|
char *ptr;
|
|
WORD heapInfoArena, freeArena, lastArena;
|
|
LOCALHEAPINFO *pHeapInfo;
|
|
LOCALARENA *pArena, *pFirstArena, *pLastArena;
|
|
NE_MODULE *pModule;
|
|
BOOL16 ret = FALSE;
|
|
|
|
/* The initial layout of the heap is: */
|
|
/* - first arena (FIXED) */
|
|
/* - heap info structure (FIXED) */
|
|
/* - large free block (FREE) */
|
|
/* - last arena (FREE) */
|
|
|
|
TRACE("%04x %04x-%04x\n", selector, start, end);
|
|
if (!selector) selector = CURRENT_DS;
|
|
|
|
if (start == 0)
|
|
{
|
|
/* start == 0 means: put the local heap at the end of the segment */
|
|
|
|
DWORD size = GlobalSize16( GlobalHandle16( selector ) );
|
|
start = (WORD)(size > 0xffff ? 0xffff : size) - 1;
|
|
if ( end > 0xfffe ) end = 0xfffe;
|
|
start -= end;
|
|
end += start;
|
|
|
|
/* Paranoid check */
|
|
|
|
if ((pModule = NE_GetPtr( GlobalHandle16( selector ) )))
|
|
{
|
|
SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule );
|
|
int segNr;
|
|
|
|
for ( segNr = 0; segNr < pModule->seg_count; segNr++, pSeg++ )
|
|
if ( GlobalHandleToSel16(pSeg->hSeg) == selector )
|
|
break;
|
|
|
|
if ( segNr < pModule->seg_count )
|
|
{
|
|
WORD minsize = pSeg->minsize;
|
|
if ( pModule->ss == segNr+1 )
|
|
minsize += pModule->stack_size;
|
|
|
|
TRACE(" new start %04x, minstart: %04x\n", start, minsize);
|
|
}
|
|
}
|
|
}
|
|
ptr = MapSL( MAKESEGPTR( selector, 0 ) );
|
|
|
|
start = LALIGN( max( start, sizeof(INSTANCEDATA) ) );
|
|
heapInfoArena = LALIGN(start + sizeof(LOCALARENA) );
|
|
freeArena = LALIGN( heapInfoArena + ARENA_HEADER_SIZE
|
|
+ sizeof(LOCALHEAPINFO) );
|
|
lastArena = (end - sizeof(LOCALARENA)) & ~3;
|
|
|
|
/* Make sure there's enough space. */
|
|
|
|
if (freeArena + sizeof(LOCALARENA) >= lastArena) goto done;
|
|
|
|
/* Initialise the first arena */
|
|
|
|
pFirstArena = ARENA_PTR( ptr, start );
|
|
pFirstArena->prev = start | LOCAL_ARENA_FIXED;
|
|
pFirstArena->next = heapInfoArena;
|
|
pFirstArena->size = LALIGN(sizeof(LOCALARENA));
|
|
pFirstArena->free_prev = start; /* this one */
|
|
pFirstArena->free_next = freeArena;
|
|
|
|
/* Initialise the arena of the heap info structure */
|
|
|
|
pArena = ARENA_PTR( ptr, heapInfoArena );
|
|
pArena->prev = start | LOCAL_ARENA_FIXED;
|
|
pArena->next = freeArena;
|
|
|
|
/* Initialise the heap info structure */
|
|
|
|
pHeapInfo = (LOCALHEAPINFO *) (ptr + heapInfoArena + ARENA_HEADER_SIZE );
|
|
memset( pHeapInfo, 0, sizeof(LOCALHEAPINFO) );
|
|
pHeapInfo->items = 4;
|
|
pHeapInfo->first = start;
|
|
pHeapInfo->last = lastArena;
|
|
pHeapInfo->htable = 0;
|
|
pHeapInfo->hdelta = 0x20;
|
|
pHeapInfo->extra = 0x200;
|
|
pHeapInfo->minsize = lastArena - freeArena;
|
|
pHeapInfo->magic = LOCAL_HEAP_MAGIC;
|
|
|
|
/* Initialise the large free block */
|
|
|
|
pArena = ARENA_PTR( ptr, freeArena );
|
|
pArena->prev = heapInfoArena | LOCAL_ARENA_FREE;
|
|
pArena->next = lastArena;
|
|
pArena->size = lastArena - freeArena;
|
|
pArena->free_prev = start;
|
|
pArena->free_next = lastArena;
|
|
|
|
/* Initialise the last block */
|
|
|
|
pLastArena = ARENA_PTR( ptr, lastArena );
|
|
pLastArena->prev = freeArena | LOCAL_ARENA_FREE;
|
|
pLastArena->next = lastArena; /* this one */
|
|
pLastArena->size = LALIGN(sizeof(LOCALARENA));
|
|
pLastArena->free_prev = freeArena;
|
|
pLastArena->free_next = lastArena; /* this one */
|
|
|
|
/* Store the local heap address in the instance data */
|
|
|
|
((INSTANCEDATA *)ptr)->heap = heapInfoArena + ARENA_HEADER_SIZE;
|
|
ret = TRUE;
|
|
|
|
done:
|
|
CURRENT_STACK16->ecx = ret; /* must be returned in cx too */
|
|
return ret;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalAlloc (KERNEL32.@)
|
|
* RETURNS
|
|
* Handle: Success
|
|
* NULL: Failure
|
|
*/
|
|
HLOCAL WINAPI LocalAlloc(
|
|
UINT flags, /* [in] Allocation attributes */
|
|
SIZE_T size /* [in] Number of bytes to allocate */
|
|
) {
|
|
return (HLOCAL)GlobalAlloc( flags, size );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalCompact (KERNEL32.@)
|
|
*/
|
|
SIZE_T WINAPI LocalCompact( UINT minfree )
|
|
{
|
|
return 0; /* LocalCompact does nothing in Win32 */
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalFlags (KERNEL32.@)
|
|
* RETURNS
|
|
* Value specifying allocation flags and lock count.
|
|
* LMEM_INVALID_HANDLE: Failure
|
|
*/
|
|
UINT WINAPI LocalFlags(
|
|
HLOCAL handle /* [in] Handle of memory object */
|
|
) {
|
|
return GlobalFlags( (HGLOBAL)handle );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalFree (KERNEL32.@)
|
|
* RETURNS
|
|
* NULL: Success
|
|
* Handle: Failure
|
|
*/
|
|
HLOCAL WINAPI LocalFree(
|
|
HLOCAL handle /* [in] Handle of memory object */
|
|
) {
|
|
return (HLOCAL)GlobalFree( (HGLOBAL)handle );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalHandle (KERNEL32.@)
|
|
* RETURNS
|
|
* Handle: Success
|
|
* NULL: Failure
|
|
*/
|
|
HLOCAL WINAPI LocalHandle(
|
|
LPCVOID ptr /* [in] Address of local memory object */
|
|
) {
|
|
return (HLOCAL)GlobalHandle( ptr );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalLock (KERNEL32.@)
|
|
* Locks a local memory object and returns pointer to the first byte
|
|
* of the memory block.
|
|
*
|
|
* RETURNS
|
|
* Pointer: Success
|
|
* NULL: Failure
|
|
*/
|
|
LPVOID WINAPI LocalLock(
|
|
HLOCAL handle /* [in] Address of local memory object */
|
|
) {
|
|
return GlobalLock( (HGLOBAL)handle );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalReAlloc (KERNEL32.@)
|
|
* RETURNS
|
|
* Handle: Success
|
|
* NULL: Failure
|
|
*/
|
|
HLOCAL WINAPI LocalReAlloc(
|
|
HLOCAL handle, /* [in] Handle of memory object */
|
|
SIZE_T size, /* [in] New size of block */
|
|
UINT flags /* [in] How to reallocate object */
|
|
) {
|
|
return (HLOCAL)GlobalReAlloc( (HGLOBAL)handle, size, flags );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalShrink (KERNEL32.@)
|
|
*/
|
|
SIZE_T WINAPI LocalShrink( HGLOBAL handle, UINT newsize )
|
|
{
|
|
return 0; /* LocalShrink does nothing in Win32 */
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalSize (KERNEL32.@)
|
|
* RETURNS
|
|
* Size: Success
|
|
* 0: Failure
|
|
*/
|
|
SIZE_T WINAPI LocalSize(
|
|
HLOCAL handle /* [in] Handle of memory object */
|
|
) {
|
|
return GlobalSize( (HGLOBAL)handle );
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* LocalUnlock (KERNEL32.@)
|
|
* RETURNS
|
|
* TRUE: Object is still locked
|
|
* FALSE: Object is unlocked
|
|
*/
|
|
BOOL WINAPI LocalUnlock(
|
|
HLOCAL handle /* [in] Handle of memory object */
|
|
) {
|
|
return GlobalUnlock( (HGLOBAL)handle );
|
|
}
|