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:
parent
f540ea642e
commit
54f377c6c5
|
@ -1142,6 +1142,7 @@
|
||||||
@ cdecl DOSMEM_FreeBlock(ptr) DOSMEM_FreeBlock
|
@ cdecl DOSMEM_FreeBlock(ptr) DOSMEM_FreeBlock
|
||||||
@ cdecl DOSMEM_GetBlock(long ptr) DOSMEM_GetBlock
|
@ cdecl DOSMEM_GetBlock(long ptr) DOSMEM_GetBlock
|
||||||
@ cdecl DOSMEM_Init(long) DOSMEM_Init
|
@ cdecl DOSMEM_Init(long) DOSMEM_Init
|
||||||
|
@ cdecl DOSMEM_ResizeBlock(ptr long long) DOSMEM_ResizeBlock
|
||||||
@ cdecl DRIVE_OpenDevice(long long) DRIVE_OpenDevice
|
@ cdecl DRIVE_OpenDevice(long long) DRIVE_OpenDevice
|
||||||
@ stdcall INT_Int21Handler(ptr) INT_Int21Handler
|
@ stdcall INT_Int21Handler(ptr) INT_Int21Handler
|
||||||
@ cdecl LOCAL_Alloc(long long long) LOCAL_Alloc
|
@ cdecl LOCAL_Alloc(long long long) LOCAL_Alloc
|
||||||
|
|
|
@ -1365,7 +1365,33 @@ void WINAPI DOSVM_Int21Handler( CONTEXT86 *context )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x4a: /* RESIZE MEMORY BLOCK */
|
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;
|
break;
|
||||||
|
|
||||||
case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
|
case 0x4b: /* "EXEC" - LOAD AND/OR EXECUTE PROGRAM */
|
||||||
|
|
|
@ -169,7 +169,7 @@ extern void DOSMEM_Tick(WORD timer);
|
||||||
extern WORD DOSMEM_AllocSelector(WORD);
|
extern WORD DOSMEM_AllocSelector(WORD);
|
||||||
extern LPVOID DOSMEM_GetBlock(UINT size, WORD* p);
|
extern LPVOID DOSMEM_GetBlock(UINT size, WORD* p);
|
||||||
extern BOOL DOSMEM_FreeBlock(void* ptr);
|
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 UINT DOSMEM_Available(void);
|
||||||
extern LPVOID DOSMEM_MapRealToLinear(DWORD); /* real-mode to linear */
|
extern LPVOID DOSMEM_MapRealToLinear(DWORD); /* real-mode to linear */
|
||||||
extern LPVOID DOSMEM_MapDosToLinear(UINT); /* linear DOS to Wine */
|
extern LPVOID DOSMEM_MapDosToLinear(UINT); /* linear DOS to Wine */
|
||||||
|
|
|
@ -308,6 +308,9 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
|
||||||
if (!(pArena->flags & GA_MOVEABLE) ||
|
if (!(pArena->flags & GA_MOVEABLE) ||
|
||||||
!(pArena->flags & GA_DISCARDABLE) ||
|
!(pArena->flags & GA_DISCARDABLE) ||
|
||||||
(pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
|
(pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
|
||||||
|
if (pArena->flags & GA_DOSMEM)
|
||||||
|
DOSMEM_FreeBlock( (void *)pArena->base );
|
||||||
|
else
|
||||||
HeapFree( GetProcessHeap(), 0, (void *)pArena->base );
|
HeapFree( GetProcessHeap(), 0, (void *)pArena->base );
|
||||||
pArena->base = 0;
|
pArena->base = 0;
|
||||||
|
|
||||||
|
@ -343,17 +346,42 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
|
||||||
if (ptr && (size == oldsize)) return handle; /* Nothing to do */
|
if (ptr && (size == oldsize)) return handle; /* Nothing to do */
|
||||||
|
|
||||||
if (pArena->flags & GA_DOSMEM)
|
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
|
else
|
||||||
/* if more then one reader (e.g. some pointer has been given out by GetVDMPointer32W16),
|
{
|
||||||
only try to realloc in place */
|
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
|
||||||
|
*/
|
||||||
newptr = HeapReAlloc( GetProcessHeap(),
|
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)
|
if (!newptr)
|
||||||
{
|
{
|
||||||
FIXME("Realloc failed lock %d\n",pArena->pageLockCount);
|
FIXME("Realloc failed lock %d\n",pArena->pageLockCount);
|
||||||
if (pArena->pageLockCount <1)
|
if (pArena->pageLockCount <1)
|
||||||
{
|
{
|
||||||
|
if (pArena->flags & GA_DOSMEM)
|
||||||
|
DOSMEM_FreeBlock( (void *)pArena->base );
|
||||||
|
else
|
||||||
HeapFree( GetProcessHeap(), 0, ptr );
|
HeapFree( GetProcessHeap(), 0, ptr );
|
||||||
SELECTOR_FreeBlock( sel );
|
SELECTOR_FreeBlock( sel );
|
||||||
memset( pArena, 0, sizeof(GLOBALARENA) );
|
memset( pArena, 0, sizeof(GLOBALARENA) );
|
||||||
|
@ -367,6 +395,9 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
|
||||||
sel = SELECTOR_ReallocBlock( sel, ptr, size );
|
sel = SELECTOR_ReallocBlock( sel, ptr, size );
|
||||||
if (!sel)
|
if (!sel)
|
||||||
{
|
{
|
||||||
|
if (pArena->flags & GA_DOSMEM)
|
||||||
|
DOSMEM_FreeBlock( (void *)pArena->base );
|
||||||
|
else
|
||||||
HeapFree( GetProcessHeap(), 0, ptr );
|
HeapFree( GetProcessHeap(), 0, ptr );
|
||||||
memset( pArena, 0, sizeof(GLOBALARENA) );
|
memset( pArena, 0, sizeof(GLOBALARENA) );
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -375,6 +406,9 @@ HGLOBAL16 WINAPI GlobalReAlloc16(
|
||||||
|
|
||||||
if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
|
if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
|
||||||
{
|
{
|
||||||
|
if (pArena->flags & GA_DOSMEM)
|
||||||
|
DOSMEM_FreeBlock( (void *)pArena->base );
|
||||||
|
else
|
||||||
HeapFree( GetProcessHeap(), 0, ptr );
|
HeapFree( GetProcessHeap(), 0, ptr );
|
||||||
SELECTOR_FreeBlock( sel );
|
SELECTOR_FreeBlock( sel );
|
||||||
return 0;
|
return 0;
|
||||||
|
|
102
msdos/dosmem.c
102
msdos/dosmem.c
|
@ -581,27 +581,36 @@ BOOL DOSMEM_FreeBlock(void* ptr)
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* DOSMEM_ResizeBlock
|
* 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;
|
char *block = NULL;
|
||||||
dosmem_info *info_block = DOSMEM_InfoBlock();
|
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)) &&
|
if( ptr < (void*)(((char*)DOSMEM_RootBlock()) + sizeof(dosmem_entry)) ||
|
||||||
ptr < (void*)DOSMEM_MemoryTop() && !((((char*)ptr)
|
(ptr >= (void*)DOSMEM_MemoryTop() &&
|
||||||
- DOSMEM_dosmem) & 0xf) )
|
!((((char*)ptr) - DOSMEM_dosmem) & 0xf)))
|
||||||
{
|
return (UINT)-1;
|
||||||
dosmem_entry *dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
|
|
||||||
|
|
||||||
if( pseg ) *pseg = ((char*)ptr - DOSMEM_dosmem) >> 4;
|
dm = (dosmem_entry*)(((char*)ptr) - sizeof(dosmem_entry));
|
||||||
|
if( dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL) )
|
||||||
|
return (UINT)-1;
|
||||||
|
|
||||||
if( !(dm->size & (DM_BLOCK_FREE | DM_BLOCK_TERMINAL))
|
next = NEXT_BLOCK(dm);
|
||||||
)
|
orgsize = dm->size & DM_BLOCK_MASK;
|
||||||
{
|
|
||||||
dosmem_entry *next = NEXT_BLOCK(dm);
|
|
||||||
UINT blocksize, orgsize = dm->size & DM_BLOCK_MASK;
|
|
||||||
|
|
||||||
while( next->size & DM_BLOCK_FREE ) /* collapse free blocks */
|
/* collapse free blocks */
|
||||||
|
while( next->size & DM_BLOCK_FREE )
|
||||||
{
|
{
|
||||||
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
|
dm->size += sizeof(dosmem_entry) + (next->size & DM_BLOCK_MASK);
|
||||||
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
|
next->size = (DM_BLOCK_FREE | DM_BLOCK_TERMINAL);
|
||||||
|
@ -609,61 +618,42 @@ LPVOID DOSMEM_ResizeBlock(void* ptr, UINT size, UINT16* pseg)
|
||||||
}
|
}
|
||||||
|
|
||||||
blocksize = dm->size & DM_BLOCK_MASK;
|
blocksize = dm->size & DM_BLOCK_MASK;
|
||||||
if (blocksize >= size)
|
|
||||||
{
|
/*
|
||||||
|
* 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);
|
block = ((char*)dm) + sizeof(dosmem_entry);
|
||||||
if( blocksize - size > 0x20 )
|
if( blocksize - size > 0x20 )
|
||||||
{
|
{
|
||||||
/* split dm so that the next one stays
|
/*
|
||||||
* paragraph-aligned (and next gains free bit) */
|
* split dm so that the next one stays
|
||||||
|
* paragraph-aligned (and next gains free bit)
|
||||||
|
*/
|
||||||
|
|
||||||
dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
|
dm->size = (((size + 0xf + sizeof(dosmem_entry)) & ~0xf) -
|
||||||
sizeof(dosmem_entry));
|
sizeof(dosmem_entry));
|
||||||
next = (dosmem_entry*)(((char*)dm) +
|
next = (dosmem_entry*)(((char*)dm) +
|
||||||
sizeof(dosmem_entry) + dm->size);
|
sizeof(dosmem_entry) + dm->size);
|
||||||
next->size = (blocksize - (dm->size +
|
next->size = (blocksize - (dm->size +
|
||||||
sizeof(dosmem_entry))) | DM_BLOCK_FREE
|
sizeof(dosmem_entry))) | DM_BLOCK_FREE;
|
||||||
;
|
}
|
||||||
} else dm->size &= DM_BLOCK_MASK;
|
else
|
||||||
|
|
||||||
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
|
dm->size &= DM_BLOCK_MASK;
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (LPVOID)block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adjust available memory if block size changes.
|
||||||
|
*/
|
||||||
|
info_block->free += orgsize - dm->size;
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* DOSMEM_Available
|
* DOSMEM_Available
|
||||||
|
|
|
@ -1253,23 +1253,6 @@ void WINAPI INT_Int21Handler( CONTEXT86 *context )
|
||||||
bSetDOSExtendedError = !INT21_GetCurrentDirectory(context);
|
bSetDOSExtendedError = !INT21_GetCurrentDirectory(context);
|
||||||
break;
|
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 */
|
case 0x4e: /* "FINDFIRST" - FIND FIRST MATCHING FILE */
|
||||||
TRACE("FINDFIRST mask 0x%04x spec %s\n",CX_reg(context),
|
TRACE("FINDFIRST mask 0x%04x spec %s\n",CX_reg(context),
|
||||||
(LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
|
(LPCSTR)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx));
|
||||||
|
|
Loading…
Reference in New Issue