blob: f62f2fd0df2606e3d568ba5e3cca8e991365507f [file] [log] [blame]
/*
* Global heap functions
*
* Copyright 1995 Alexandre Julliard
*/
#include <stdlib.h>
#include <string.h>
#include "windows.h"
#include "toolhelp.h"
#include "selectors.h"
#include "stackframe.h"
#include "stddebug.h"
#include "debug.h"
#define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
#define HGLOBAL_TO_SEL(handle) \
((handle == (HGLOBAL)-1) ? CURRENT_DS : GlobalHandleToSel(handle))
/***********************************************************************
* GlobalAlloc (KERNEL.15)
*/
HGLOBAL GlobalAlloc( WORD flags, DWORD size )
{
WORD sel;
void *ptr;
dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
/* Fixup the size */
if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x0f) return 0;
if (size == 0) size = 0x10;
else size = (size + 0x0f) & ~0x0f;
/* Allocate the linear memory */
ptr = malloc( size );
if (!ptr) return 0;
/* Allocate the selector(s) */
sel = SELECTOR_AllocBlock( ptr, size, SEGMENT_DATA, 0, 0 );
if (!sel)
{
free( ptr );
return 0;
}
if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
/* Return the handle */
/* If allocating a GMEM_FIXED block, the handle is the selector. */
/* Otherwise, the handle is the selector-1 (don't ask me why :-) */
if (flags & GMEM_MOVEABLE) return sel - 1;
else return sel;
}
/***********************************************************************
* GlobalReAlloc (KERNEL.16)
*/
HGLOBAL GlobalReAlloc( HGLOBAL handle, DWORD size, WORD flags )
{
WORD sel;
DWORD oldsize;
void *ptr;
dprintf_global( stddeb, "GlobalReAlloc: %04x %ld flags=%04x\n",
handle, size, flags );
/* Fixup the size */
if (size >= 0x00ff0000-0x0f) return 0; /* No allocation > 16Mb-64Kb */
if (size == 0) size = 0x10;
else size = (size + 0x0f) & ~0x0f;
/* Reallocate the linear memory */
sel = GlobalHandleToSel( handle );
ptr = (void *)GET_SEL_BASE( sel );
oldsize = GlobalSize( handle );
if (size == oldsize) return handle; /* Nothing to do */
ptr = realloc( ptr, size );
if (!ptr)
{
FreeSelector( sel );
return 0;
}
/* Reallocate the selector(s) */
sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
if (!sel)
{
free( ptr );
return 0;
}
if ((oldsize < size) && (flags & GMEM_ZEROINIT))
memset( (char *)ptr + oldsize, 0, size - oldsize );
if (sel == GlobalHandleToSel( handle ))
return handle; /* Selector didn't change */
if (flags & GMEM_MOVEABLE) return sel - 1;
else return sel;
}
/***********************************************************************
* GlobalFree (KERNEL.17)
*/
HGLOBAL GlobalFree( HGLOBAL handle )
{
WORD sel;
void *ptr;
dprintf_global( stddeb, "GlobalFree: %04x\n", handle );
sel = GlobalHandleToSel( handle );
ptr = (void *)GET_SEL_BASE(sel);
if (FreeSelector( sel )) return handle; /* failed */
free( ptr );
return 0;
}
/***********************************************************************
* WIN16_GlobalLock (KERNEL.18)
*
* This is the GlobalLock() function used by 16-bit code.
*/
SEGPTR WIN16_GlobalLock( HGLOBAL handle )
{
dprintf_global( stddeb, "WIN16_GlobalLock: %04x\n", handle );
if (!handle) return 0;
return (SEGPTR)MAKELONG( 0, HGLOBAL_TO_SEL(handle) );
}
/***********************************************************************
* GlobalLock (KERNEL.18)
*
* This is the GlobalLock() function used by 32-bit code.
*/
LPSTR GlobalLock( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalLock: %04x\n", handle );
if (!handle) return 0;
return (LPSTR)GET_SEL_BASE( HGLOBAL_TO_SEL(handle) );
}
/***********************************************************************
* GlobalUnlock (KERNEL.19)
*/
BOOL GlobalUnlock( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalUnlock: %04x\n", handle );
return 0;
}
/***********************************************************************
* GlobalSize (KERNEL.20)
*/
DWORD GlobalSize( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalSize: %04x\n", handle );
if (!handle) return 0;
return GET_SEL_LIMIT( HGLOBAL_TO_SEL(handle) ) + 1;
}
/***********************************************************************
* GlobalHandle (KERNEL.21)
*/
DWORD GlobalHandle( WORD sel )
{
/* FIXME: what about GMEM_FIXED blocks? */
WORD handle = sel & ~1;
dprintf_global( stddeb, "GlobalHandle(%04x): returning %08lx\n",
sel, MAKELONG( handle, sel ) );
return MAKELONG( handle, sel );
}
/***********************************************************************
* GlobalFlags (KERNEL.22)
*/
WORD GlobalFlags( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalFlags: %04x\n", handle );
return 0; /* lock count is always 0 */
}
/***********************************************************************
* LockSegment (KERNEL.23)
*/
HGLOBAL LockSegment( HGLOBAL handle )
{
dprintf_global( stddeb, "LockSegment: %04x\n", handle );
if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
return handle;
}
/***********************************************************************
* UnlockSegment (KERNEL.24)
*/
void UnlockSegment( HGLOBAL handle )
{
dprintf_global( stddeb, "UnlockSegment: %04x\n", handle );
/* FIXME: this ought to return the lock count in CX (go figure...) */
}
/***********************************************************************
* GlobalCompact (KERNEL.25)
*/
DWORD GlobalCompact( DWORD desired )
{
return GLOBAL_MAX_ALLOC_SIZE;
}
/***********************************************************************
* GlobalWire (KERNEL.111)
*/
LPSTR GlobalWire( HGLOBAL handle )
{
return GlobalLock( handle );
}
/***********************************************************************
* GlobalUnWire (KERNEL.112)
*/
BOOL GlobalUnWire( HGLOBAL handle )
{
return GlobalUnlock( handle );
}
/***********************************************************************
* GlobalDOSAlloc (KERNEL.184)
*/
DWORD GlobalDOSAlloc( DWORD size )
{
WORD sel = GlobalAlloc( GMEM_FIXED, size );
if (!sel) return 0;
return MAKELONG( sel, sel /* this one ought to be a real-mode segment */ );
}
/***********************************************************************
* GlobalDOSFree (KERNEL.185)
*/
WORD GlobalDOSFree( WORD sel )
{
return GlobalFree( GlobalHandle(sel) ) ? sel : 0;
}
/***********************************************************************
* SetSwapAreaSize (KERNEL.106)
*/
LONG SetSwapAreaSize( WORD size )
{
dprintf_heap(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
return MAKELONG( size, 0xffff );
}
/***********************************************************************
* GlobalLRUOldest (KERNEL.163)
*/
HGLOBAL GlobalLRUOldest( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalLRUOldest: %04x\n", handle );
if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
return handle;
}
/***********************************************************************
* GlobalLRUNewest (KERNEL.164)
*/
HGLOBAL GlobalLRUNewest( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalLRUNewest: %04x\n", handle );
if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
return handle;
}
/***********************************************************************
* GetFreeSpace (KERNEL.169)
*/
DWORD GetFreeSpace( UINT wFlags )
{
return GLOBAL_MAX_ALLOC_SIZE;
}
/***********************************************************************
* GlobalPageLock (KERNEL.191)
*/
WORD GlobalPageLock( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
/* Nothing to do, as we can't page-lock a block (and we don't want to) */
return 1; /* lock count */
}
/***********************************************************************
* GlobalPageUnlock (KERNEL.192)
*/
WORD GlobalPageUnlock( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
return 0; /* lock count */
}
/***********************************************************************
* GlobalFix (KERNEL.197)
*/
void GlobalFix( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalFix: %04x\n", handle );
/* Nothing to do, as all the blocks are fixed in linear memory anyway */
}
/***********************************************************************
* GlobalUnfix (KERNEL.198)
*/
void GlobalUnfix( HGLOBAL handle )
{
dprintf_global( stddeb, "GlobalUnfix: %04x\n", handle );
/* This one is even more complicated that GlobalFix() :-) */
}
/***********************************************************************
* GlobalHandleToSel (TOOLHELP.50)
*/
WORD GlobalHandleToSel( HGLOBAL handle )
{
dprintf_toolhelp( stddeb, "GlobalHandleToSel: %04x\n", handle );
if (!(handle & 7))
{
fprintf( stderr, "Program attempted invalid selector conversion\n" );
return handle - 1;
}
return handle | 1;
}
/**********************************************************************
* MemManInfo (toolhelp.72)
*/
/*
BOOL MemManInfo(LPMEMMANINFO lpmmi)
{
return 1;
}
*/