home *** CD-ROM | disk | FTP | other *** search
- /***
- * vrealloc.c - Reallocate space
- *
- * Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
- *
- *******************************************************************************/
-
- #include <version.h>
- #include <vmassert.h>
- #include <stdlib.h>
- #include <string.h>
- #include <vmm.h>
- #include <vmbm.h>
-
- 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);
- }
-