Commit 54f377c6 authored by Jukka Heinonen's avatar Jukka Heinonen Committed by Alexandre Julliard

Move resize memory block to winedos and make it resize in place and

work correctly even when trying to allocate too much memory.
parent f540ea64
......@@ -1142,6 +1142,7 @@
@ cdecl DOSMEM_FreeBlock(ptr) DOSMEM_FreeBlock
@ cdecl DOSMEM_GetBlock(long ptr) DOSMEM_GetBlock
@ cdecl DOSMEM_Init(long) DOSMEM_Init
@ cdecl DOSMEM_ResizeBlock(ptr long long) DOSMEM_ResizeBlock
@ cdecl DRIVE_OpenDevice(long long) DRIVE_OpenDevice
@ stdcall INT_Int21Handler(ptr) INT_Int21Handler
@ cdecl LOCAL_Alloc(long long long) LOCAL_Alloc
......
......@@ -1365,7 +1365,33 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
break;
case 0x4a: /* RESIZE MEMORY BLOCK */
INT_Int21Handler( context );
TRACE( "RESIZE MEMORY segment %04lX to %d paragraphs\n",
context->SegEs, BX_reg(context) );
{
DWORD newsize = (DWORD)BX_reg(context) << 4;
if (!ISV86(context) && DOSVM_IsWin16())
{
FIXME( "Resize memory block - unsupported under Win16\n" );
}
else
{
LPVOID address = (void*)((DWORD)context->SegEs << 4);
UINT blocksize = DOSMEM_ResizeBlock( address, newsize, FALSE );
if (blocksize == (UINT)-1)
{
SET_CFLAG( context );
SET_AX( context, 0x0009 ); /* illegal address */
}
else if(blocksize != newsize)
{
SET_CFLAG( context );
SET_AX( context, 0x0008 ); /* insufficient memory */
SET_BX( context, blocksize >> 4 ); /* new block size */
}
}
}
break;
case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
......
......@@ -169,7 +169,7 @@ extern void DOSMEM_Tick(WORD timer);
extern WORD DOSMEM_AllocSelector(WORD);
extern LPVOID DOSMEM_GetBlock(UINT size, WORD* p);
extern BOOL DOSMEM_FreeBlock(void* ptr);
extern LPVOID DOSMEM_ResizeBlock(void* ptr, UINT size, WORD* p);
extern UINT DOSMEM_ResizeBlock(void* ptr, UINT size, BOOL exact);
extern UINT DOSMEM_Available(void);
extern LPVOID DOSMEM_MapRealToLinear(DWORD); /* real-mode to linear */
extern LPVOID DOSMEM_MapDosToLinear(UINT); /* linear DOS to Wine */
......
......@@ -308,7 +308,10 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
if (!(pArena->flags & GA_MOVEABLE) ||
!(pArena->flags & GA_DISCARDABLE) ||
(pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
HeapFree( GetProcessHeap(), 0, (void *)pArena->base );
if (pArena->flags & GA_DOSMEM)
DOSMEM_FreeBlock( (void *)pArena->base );
else
HeapFree( GetProcessHeap(), 0, (void *)pArena->base );
pArena->base = 0;
/* Note: we rely on the fact that SELECTOR_ReallocBlock won't
......@@ -343,18 +346,43 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
if (ptr && (size == oldsize)) return handle; /* Nothing to do */
if (pArena->flags & GA_DOSMEM)
newptr = DOSMEM_ResizeBlock(ptr, size, NULL);
{
if (DOSMEM_ResizeBlock(ptr, size, TRUE) == size)
newptr = ptr;
else if(pArena->pageLockCount > 0)
newptr = 0;
else
{
newptr = DOSMEM_GetBlock( size, 0 );
if (newptr)
{
memcpy( newptr, ptr, oldsize );
DOSMEM_FreeBlock( ptr );
}
}
}
else
/* if more then one reader (e.g. some pointer has been given out by GetVDMPointer32W16),
only try to realloc in place */
{
/*
* if more then one reader (e.g. some pointer has been
* given out by GetVDMPointer32W16),
* only try to realloc in place
*/
newptr = HeapReAlloc( GetProcessHeap(),
(pArena->pageLockCount > 0)?HEAP_REALLOC_IN_PLACE_ONLY:0, ptr, size );
(pArena->pageLockCount > 0) ?
HEAP_REALLOC_IN_PLACE_ONLY : 0,
ptr, size );
}
if (!newptr)
{
FIXME("Realloc failed lock %d\n",pArena->pageLockCount);
if (pArena->pageLockCount <1)
{
HeapFree( GetProcessHeap(), 0, ptr );
if (pArena->flags & GA_DOSMEM)
DOSMEM_FreeBlock( (void *)pArena->base );
else
HeapFree( GetProcessHeap(), 0, ptr );
SELECTOR_FreeBlock( sel );
memset( pArena, 0, sizeof(GLOBALARENA) );
}
......@@ -367,15 +395,21 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
sel = SELECTOR_ReallocBlock( sel, ptr, size );
if (!sel)
{
HeapFree( GetProcessHeap(), 0, ptr );
if (pArena->flags & GA_DOSMEM)
DOSMEM_FreeBlock( (void *)pArena->base );
else
HeapFree( GetProcessHeap(), 0, ptr );
memset( pArena, 0, sizeof(GLOBALARENA) );
return 0;
}
selcount = (size + 0xffff) / 0x10000;
if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
{
HeapFree( GetProcessHeap(), 0, ptr );
{
if (pArena->flags & GA_DOSMEM)
DOSMEM_FreeBlock( (void *)pArena->base );
else
HeapFree( GetProcessHeap(), 0, ptr );
SELECTOR_FreeBlock( sel );
return 0;
}
......
......@@ -581,89 +581,79 @@ BOOL DOSMEM_FreeBlock(void* ptr)
/***********************************************************************
* DOSMEM_ResizeBlock
*
* Resize DOS memory block in place. Returns block size or -1 on error.
*
* If exact is TRUE, returned value is either old or requested block
* size. If exact is FALSE, block is expanded even if there is not
* enough space for full requested block size.
*/
LPVOID DOSMEM_ResizeBlock(void* ptr, UINT size, UINT16* pseg)
UINT DOSMEM_ResizeBlock(void *ptr, UINT size, BOOL exact)
{
char *block = NULL;
dosmem_info *info_block = DOSMEM_InfoBlock();
dosmem_entry *dm;
dosmem_entry *next;
UINT blocksize;
UINT orgsize;
if( ptr >= (void*)(((char*)DOSMEM_RootBlock()) + sizeof(dosmem_entry)) &&
ptr < (void*)DOSMEM_MemoryTop() && !((((char*)ptr)
- DOSMEM_dosmem) & 0xf) )
if( ptr < (void*)(((char*)DOSMEM_RootBlock()) + sizeof(dosmem_entry)) ||
(ptr >= (void*)DOSMEM_MemoryTop() &&
!((((char*)ptr) - DOSMEM_dosmem) & 0xf)))
return (UINT)-1;
dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
if( dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL) )
return (UINT)-1;
next = NEXT_BLOCK(dm);
orgsize = dm->size & DM_BLOCK_MASK;
/* collapse free blocks */
while( next->size & DM_BLOCK_FREE )
{
dosmem_entry *dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
next = NEXT_BLOCK(dm);
}
if( pseg ) *pseg = ((char*)ptr - DOSMEM_dosmem) >> 4;
blocksize = dm->size & DM_BLOCK_MASK;
if( !(dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL))
)
{
dosmem_entry *next = NEXT_BLOCK(dm);
UINT blocksize, orgsize = dm->size & DM_BLOCK_MASK;
while( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
{
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
next = NEXT_BLOCK(dm);
}
blocksize = dm->size & DM_BLOCK_MASK;
if (blocksize >= size)
{
block = ((char*)dm) + sizeof(dosmem_entry);
if( blocksize - size > 0x20 )
{
/* split dm so that the next one stays
* paragraph-aligned (and next gains free bit) */
dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
sizeof(dosmem_entry));
next = (dosmem_entry*)(((char*)dm) +
sizeof(dosmem_entry) + dm->size);
next->size = (blocksize - (dm->size +
sizeof(dosmem_entry))) | DM_BLOCK_FREE
;
} else dm->size &= DM_BLOCK_MASK;
info_block->free += orgsize - dm->size;
} else {
/* the collapse didn't help, try getting a new block */
block = DOSMEM_GetBlock(size, pseg);
if (block) {
/* we got one, copy the old data there (we do need to, right?) */
memcpy(block, ((char*)dm) + sizeof(dosmem_entry),
(size<orgsize) ? size : orgsize);
/* free old block */
info_block->blocks--;
info_block->free += dm->size;
dm->size |= DM_BLOCK_FREE;
} else {
/* and Bill Gates said 640K should be enough for everyone... */
/* need to split original and collapsed blocks apart again,
* and free the collapsed blocks again, before exiting */
if( blocksize - orgsize > 0x20 )
{
/* split dm so that the next one stays
* paragraph-aligned (and next gains free bit) */
dm->size = (((orgsize + 0xf + sizeof(dosmem_entry)) & ~0xf) -
sizeof(dosmem_entry));
next = (dosmem_entry*)(((char*)dm) +
sizeof(dosmem_entry) + dm->size);
next->size = (blocksize - (dm->size +
sizeof(dosmem_entry))) | DM_BLOCK_FREE
;
} else dm->size &= DM_BLOCK_MASK;
}
}
}
/*
* If collapse didn't help we either expand block to maximum
* available size (exact == FALSE) or give collapsed blocks
* back to free storage (exact == TRUE).
*/
if (blocksize < size)
size = exact ? orgsize : blocksize;
block = ((char*)dm) + sizeof(dosmem_entry);
if( blocksize - size > 0x20 )
{
/*
* split dm so that the next one stays
* paragraph-aligned (and next gains free bit)
*/
dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
sizeof(dosmem_entry));
next = (dosmem_entry*)(((char*)dm) +
sizeof(dosmem_entry) + dm->size);
next->size = (blocksize - (dm->size +
sizeof(dosmem_entry))) | DM_BLOCK_FREE;
}
else
{
dm->size &= DM_BLOCK_MASK;
}
return (LPVOID)block;
}
/*
* Adjust available memory if block size changes.
*/
info_block->free += orgsize - dm->size;
return size;
}
/***********************************************************************
* DOSMEM_Available
......
......@@ -1253,23 +1253,6 @@ void WINAPI INT_Int21Handler( CONTEXT86 *context )
bSetDOSExtendedError = !INT21_GetCurrentDirectory(context);
break;
case 0x4a: /* RESIZE MEMORY BLOCK */
TRACE("RESIZE MEMORY segment %04lX to %d paragraphs\n", context->SegEs, BX_reg(context));
if (!ISV86(context))
FIXME("RESIZE MEMORY probably insufficient implementation. Expect crash soon\n");
{
LPVOID *mem = DOSMEM_ResizeBlock(DOSMEM_MapDosToLinear(context->SegEs<<4),
BX_reg(context)<<4,NULL);
if (mem)
SET_AX( context, DOSMEM_MapLinearToDos(mem)>>4 );
else {
SET_CFLAG(context);
SET_AX( context, 0x0008 ); /* insufficient memory */
SET_BX( context, DOSMEM_Available()>>4 ); /* not quite right */
}
}
break;
case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
TRACE("FINDFIRST mask 0x%04x spec %s\n",CX_reg(context),
(LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment