blob: 8161985c234beaf4a309afbbfb2edf515c344fc7 [file] [log] [blame]
/*
* 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 );
}