home *** CD-ROM | disk | FTP | other *** search
- /***
- * vfree.c - Free memory routines
- *
- * Copyright (c) 1989-1992, Microsoft Corporation. All rights reserved.
- *
- *******************************************************************************/
-
- #include <version.h>
- #include <system.h>
- #include <vmassert.h>
- #include <stdlib.h>
- #include <string.h>
- #include <vmlist.h>
- #include <vmm.h>
- #include <vmbm.h>
-
- extern PFBD _pfbdVirtHead;
- extern PFBD _pfbdVirtCurr;
- extern unsigned long _cVirtPageMax;
-
- /*** VmFreeHbk
- *
- * Purpose: To Free the allocated block specified
- *
- * Input:
- * hbk The handle to the block to be freed
- *
- * Output:
- *
- * Exceptions:
- *
- * Notes:
- * On a free it might be nice to free complete pages, however this
- * causes terrible fragmentation. Its better to merge the free pages
- * and reallocate them.
- *
- * Also since free pages can only grow in size, cbMaxFree will stay
- * the same or grow. But it can't shrink.
- *
- *************************************************************************/
- void VMFUNC __VmFreeHbk(
- HBK hbk
- ) {
- VPVOID vp;
- PHDF phdf;
- PHDB phdb;
- HDF hdf;
- unsigned cb;
-
- int fAddFree = TRUE, fMerge = FALSE;
- HBK hbkMerge;
-
- if (!_fVmInit || (unsigned long)hbk < (unsigned long)_hbkMin || (unsigned long)hbk >= (unsigned long)_hbkMax)
- return;
-
- _fmemset( &hdf, 0, sizeof(HDF) );
-
- // load the page
- phdb = __PVmLoadVp((VPVOID) hbk, FALSE);
-
- if (!phdb || phdb->fFree)
- return;
-
- // unlock the block before freeing, if necessary
-
- while (phdb->cLock != 0)
- {
- __VmUnlockHbk(hbk, FALSE);
- phdb = __PVmLoadVp((VPVOID) hbk, FALSE);
- }
-
- // copy header
-
- _fmemcpy( &hdf, phdb, sizeof(HDB) );
-
- // if this was allocated by page, then free it by page
- if(hdf.fByPage)
- {
- Assert(hdf.cPage > 0 && ((long)hbk % cbVmPage) == 0);
-
- // put on free list of free pages
- __VmAddFreeBlock(&_pfbdVirtHead, &_pfbdVirtCurr, &_cVirtPageMax,
- hdf.cPage, (unsigned long)hbk);
-
- for(vp=(VPVOID) hbk; hdf.cPage>0; hdf.cPage--, vp += cbVmPage)
- {
- Assert( __CVmLockVp(vp) == 0 );
- __VmFreePageVp( vp );
- }
- return;
- }
-
- // merge with the top block
- if( hdf.fAdjacent ) {
-
- hbkMerge = AddHbk(hbk, CbGetSize(hdf.cbSize));
- phdf = __PVmLoadVp((VPVOID) hbkMerge, FALSE);
-
- // if it is free, then merge with the block below
- if( phdf->fFree &&
- ((unsigned long) CbGetSize(hdf.cbSize) +
- (unsigned long) CbGetSize(phdf->cbSize)) < cbBig ) {
-
- // add the size to the block before, also set the adjacent flag
- fMerge = TRUE;
- hdf.cbSize = CbMakeSize( CbGetSize(hdf.cbSize) +
- CbGetSize(phdf->cbSize),
- phdf->fAdjacent );
-
- // take this guy out of the list
- __VmFreeLink(phdf->hbkBackHdf, phdf->hbkNextHdf);
- _gvmbm.cFree--;
-
- // see if this was the last block
- if( hbkMerge == _gvmbm.hbkLastBlock )
- _gvmbm.hbkLastBlock = hbk;
- }
- }
-
- // merge with the bottom block
- if( hdf.szbkBack.fAdjacent ) {
-
- cb = CbGetSize(hdf.szbkBack.cbSize);
- hbkMerge = AddHbk(hbk, - (long) cb);
- phdf = __PVmLoadVp((VPVOID) hbkMerge, FALSE);
- Assert( cb == CbGetSize(phdf->cbSize) );
-
- if( phdf->fFree &&
- ((unsigned long) CbGetSize(hdf.cbSize) + cb) < cbBig ) {
-
- // we don't want to add anything to the free list
- // because the one below will take it
- fAddFree = FALSE;
- fMerge = TRUE;
-
- // add the size to the block before, also set the adjacent flag
- hdf.cbSize = CbMakeSize( CbGetSize(hdf.cbSize) + cb,
- hdf.fAdjacent );
- hdf.szbkBack = phdf->szbkBack;
- hdf.hbkBackHdf = phdf->hbkBackHdf;
- hdf.hbkNextHdf = phdf->hbkNextHdf;
-
- // see if this was the last block
- if( hbk == _gvmbm.hbkLastBlock )
- _gvmbm.hbkLastBlock = hbkMerge;
-
- // adjust the free page to add
- hbk = hbkMerge;
- }
- }
-
- // Now the page above me may need its back pointer adjusted
- // if I did any kind of merge.
- if( fMerge && hdf.fAdjacent ) {
-
- // get the block above and set it's back size and adjacent bit
- // to match the current block
- phdb = __PVmLoadVp((VPVOID) AddHbk(hbk, CbGetSize(hdf.cbSize)), TRUE);
- Assert( phdb != NULL );
- phdb->szbkBack.cbSize = hdf.cbSize;
- }
-
- // make this a free page
- phdf = __PVmLoadVp((VPVOID) hbk, TRUE);
- *phdf = hdf;
- phdf->fFree = TRUE;
-
- // if required add this to the end of the free list
- if( fAddFree )
- __VmFreeLinkEnd(hbk, CbGetSize(hdf.cbSize));
-
- // check the free list
- #ifdef VMDEBUG
- hbk = _gvmbm.hbkFreeStart;
- hbkMerge = NULL;
- while( hbk ) {
- phdf = __PVmLoadVp( (VPVOID) hbk, FALSE );
- Assert( phdf != NULL );
- Assert( phdf->fFree == TRUE );
- Assert( phdf->hbkBackHdf == hbkMerge );
- hbkMerge = hbk;
- hbk = phdf->hbkNextHdf;
- }
- #endif
- }
-