Category : C++ Source Code
Archive   : VMVCPP.ZIP
Filename : VREALLOC.C

 
Output of file : VREALLOC.C contained in archive : VMVCPP.ZIP

/***
* vrealloc.c - Reallocate space
*
* Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
*
*******************************************************************************/

#include
#include
#include
#include
#include
#include

HBK near pascal __HbkVmAllocCopy(HBK, unsigned long, unsigned long);


/*** HbkVmReallocate
*
* Purpose: To Realloc the memory
*
* Input:
* hbk The handle to the block to be reallocated
* cb The new size of the allocation
*
* Output:
*
* Exceptions:
*
* Notes:
*
* Functionality Notes:
* 1) If supplied handle is NULL, realloc maps to malloc
* 2) If supplied size is 0, realloc maps to free
*
* Implimentation Notes:
* 1) See if adjacent block to merge to, and make big block
* 2) See if the block is big enough, and make free block
* 3) or allocate a new area and copy
*
* If the reallocate fails, there may be a side effect of merging a
* free block at the end of the old block.
*
*
*************************************************************************/
HBK VMFUNC __HbkVmReallocate(
HBK hbk,
unsigned long cb
) {
unsigned long cbT, cbSize, cbOrg;
HBK hbkNext;
PHDB phdb;
PHDF phdf;
SZBK szbk;
HDF hdf;
int fMergeAbove = FALSE;

if (!_fVmInit)
return NULL;

// Special cases:
// (1) If handle is null, realloc maps to malloc
// (2) If size is 0, realloc maps to free
// (3) If size is > cbMaxAlloc, we can't satisfy it so return NULL.
if (hbk == NULL)
return (__HbkVmAllocate(cb));

if ((unsigned long)hbk < (unsigned long)_hbkMin || (unsigned long)hbk > (unsigned long)_hbkMax)
return NULL;

if (cb == 0)
{
__VmFreeHbk(hbk);
return(NULL);
}

if( cb > cbMaxAlloc )
return(NULL);

// round the size to an int boundary
cb = ((cb + sizeof(int) - 1) / sizeof(int)) * sizeof(int);

// determine the actual size to allocate, must be big enough for a free
cbT = max(cb + sizeof(HDB), sizeof(HDF));

phdb = __PVmLoadVp((VPVOID) hbk, FALSE);

if (!phdb || phdb->fFree || phdb->cLock)
return NULL;

// do the page realloc
if( phdb->fByPage ) {

phdb = __PVmLoadVp((VPVOID) hbk, TRUE);
cbSize = phdb->cPage * (unsigned long) cbVmPage;

// if it is smaller, just shrink the current page count
if( cbSize >= cbT ) {

// get the page count
cbSize = phdb->cPage;
phdb->cPage = (unsigned short) ((cbT + cbVmPage - 1) / cbVmPage);

// free all extra pages
for(cb = phdb->cPage; cb < cbSize; cb++)
__VmFreePageVp( (((VPVOID) hbk) + (cbVmPage * cb)) );
return(hbk);
}

// must allocate and copy
else
return(__HbkVmAllocCopy(hbk, cbSize - sizeof(HDB), cb));
}

// we are dealing with blocks if we got here

// if the size stays the same
cbOrg = cbSize = CbGetSize(phdb->cbSize);
Assert( cbSize >= sizeof(HDF) );
if( (cbSize - sizeof(HDF)) < cbT &&
cbT <= CbGetSize(phdb->cbSize) )
return(hbk);

// if there is an adjacent free block, merge it in
szbk.cbSize = phdb->cbSize;
if( phdb->fAdjacent ) {

hbkNext = AddHbk(hbk, CbGetSize(szbk.cbSize));
phdf = __PVmLoadVp((VPVOID) hbkNext, FALSE);

// if it is free, merge in with the current hbk
if( phdf->fFree &&
(cbSize + CbGetSize(phdf->cbSize)) < cbBig ) {

fMergeAbove = TRUE;
hdf = *phdf;

// get the size of the new block
szbk.cbSize = CbMakeSize(CbGetSize(phdf->cbSize) + (unsigned short) cbSize,
phdf->fAdjacent);

_gvmbm.cFree--;
if( hbkNext == _gvmbm.hbkLastBlock )
_gvmbm.hbkLastBlock = hbk;
}
}

cbSize = CbGetSize(szbk.cbSize);
// make a free block
if( (cbSize - sizeof(HDF)) >= cbT ) {

// make the size of the free block and tell the one above
// about it
szbk.cbSize = CbMakeSize((cbSize - cbT), szbk.fAdjacent);
if(szbk.fAdjacent) {
phdb = __PVmLoadVp((VPVOID) AddHbk(hbk, cbSize), TRUE);
phdb->szbkBack = szbk;
}

// make the free page and add it to the list
hbkNext = AddHbk(hbk, cbT);
phdf = __PVmLoadVp((VPVOID) hbkNext, TRUE);
_fmemset( phdf, 0, sizeof(HDF) );
phdf->cbSize = szbk.cbSize;
phdf->szbkBack.cbSize = CbMakeSize(cbT, TRUE);
phdf->fFree = TRUE;

// if the new free block is the last block
if( hbk == _gvmbm.hbkLastBlock )
_gvmbm.hbkLastBlock = hbkNext;

// put in the free list
if( fMergeAbove )
__VmFreeLinkIn(hbkNext, CbGetSize(szbk.cbSize),
hdf.hbkBackHdf, hdf.hbkNextHdf);
else
__VmFreeLinkEnd(hbkNext, CbGetSize(szbk.cbSize));

// make the new allocation
phdb = __PVmLoadVp((VPVOID) hbk, TRUE);
Assert( phdb->fFree == FALSE );
phdb->cbSize = CbMakeSize(cbT, TRUE);
}

// must allocate and copy
else {

// fix the next entry but only if we merged, otherwise the
// next entry will be fine.
if(fMergeAbove) {

if( szbk.fAdjacent ) {
phdb = __PVmLoadVp((VPVOID) AddHbk(hbk, cbSize), TRUE);
phdb->szbkBack = szbk;
}

// if there was a merge, then there is a dangling free
// that must be removed
__VmFreeLink(hdf.hbkBackHdf, hdf.hbkNextHdf);

// make the new allocation
phdb = __PVmLoadVp((VPVOID) hbk, TRUE);
Assert( phdb->fFree == FALSE );
phdb->cbSize = szbk.cbSize;
}

if( cbSize < cbT )
hbk = __HbkVmAllocCopy(hbk, cbOrg - sizeof(HDB), cb);
}

return(hbk);
}

/*** HbkVmAllocCopy
*
* Purpose: To do a byte copy from one block to another
*
* Input:
* hbk The old block to copy from
* cbCopy The number to copy
* cbNew The size of the new allocation block
*
* Output:
* Return: The new allocated hbk or NULL on error
*
* Exceptions:
*
* Notes:
* The old block is freed
*
*
*************************************************************************/
HBK near pascal __HbkVmAllocCopy(
HBK hbk,
unsigned long cbCopy,
unsigned long cbNew
) {
HBK hbkNew = NULL;
VPVOID vp, vpLock;

Assert( cbCopy <= cbNew );

// allocate the new block
if( (hbkNew = __HbkVmAllocate(cbNew)) ) {

vp = VpHbk(hbkNew);
vpLock = VpHbk(hbk);

if( __VpMemCopyVp(vp, vpLock, cbCopy) )
__VmFreeHbk( hbk );
else {
__VmFreeHbk(hbkNew);
hbkNew = NULL;
}
}

return(hbkNew);
}


/*** VpMemCopyVp
*
* Purpose: To do a byte copy from one block to another
*
* Input:
* hbk The old block to copy from
* cbCopy The number to copy
* cbNew The size of the new allocation block
*
* Output:
* Return: The new allocated hbk or NULL on error
*
* Exceptions:
*
* Notes:
* The old block is freed
*
*
*************************************************************************/
int VMFUNC __VpMemCopyVp(
VPVOID vp,
VPVOID vpLock,
unsigned long cbCopy
) {
unsigned long cb;
PVOID pvoidLock, pvoid;

// copy the data
while(cbCopy) {

// how much to copy this time
cb = min(cbEndPage(vp), cbEndPage(vpLock));
cb = min(cb, cbCopy);

// if I can't lock the page, I'm done
if( !(pvoidLock = __PVmLockVp( vpLock )) )
return(FALSE);

pvoid = __PVmLoadVp( vp, TRUE );
_fmemcpy(pvoid, pvoidLock, (unsigned) cb);

__VmUnlockVp(vpLock, FALSE);

// move to the next place to copy
cbCopy -= cb;
vpLock += cb;
vp += cb;
}

return(TRUE);
}