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

work correctly even when trying to allocate too much memory.
This commit is contained in:
Jukka Heinonen 2003-02-19 22:11:04 +00:00 committed by Alexandre Julliard
parent f540ea642e
commit 54f377c6c5
6 changed files with 137 additions and 103 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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;
}

View File

@ -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));
if( pseg ) *pseg = ((char*)ptr - DOSMEM_dosmem) >> 4;
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;
}
}
}
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
next = NEXT_BLOCK(dm);
}
return (LPVOID)block;
}
blocksize = 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;
}
/*
* Adjust available memory if block size changes.
*/
info_block->free += orgsize - dm->size;
return size;
}
/***********************************************************************
* DOSMEM_Available

View File

@ -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));