home *** CD-ROM | disk | FTP | other *** search
- /***
- *alloc.c - Allocate memory routines
- *
- * 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>
-
- VPVOID pascal near __VpAllocAtEnd(unsigned);
- VPVOID near pascal __VpAllocInFree(unsigned);
-
- // global variables to manage
- GVMBM _gvmbm = {cbMaxFreeSize};
-
-
- /*** HbkVmAllocate
- *
- * Purpose: Allocate in vm cb bytes of memory
- *
- * Input:
- * cb The minimum number of bytes to allocate. Zero length allocations
- * are allowed.
- *
- * Output:
- * Returns:
- * An HBK representing the virtual memory allocated. NULL
- * if an error.
- *
- * Exceptions:
- *
- * Notes:
- *
- * Allocated Free Page
- * Block Block Block
- *
- * FEDCBA9876543210 FEDCBA9876543210 FEDCBA9876543210
- * +----------------+ +----------------+ +----------------+
- * | | | | | |
- * | | | Free | | |
- * | Allocated | | Space | | Allocated |
- * | Space | | |E | Pages |
- * | | +----------------+ | |
- * | | | Free Next | | |
- * | | | VM Ptr |A | |
- * | | +----------------+ | |
- * | | | Free Back | | |
- * | |6 | VM Ptr |6 | |6
- * +----------------+ +----------------+ +----------------+
- * | cbBack |C|4 | cbBack |C|4 | 0 |4
- * +----------------+ +----------------+ +----------------+
- * |RRRRRR00| cLock |2 |RRRRRR01| cLock |2 |RRRRRR10| cLock |2
- * +----------------+ +----------------+ +----------------+
- * | cbSize |C|0 | cbSize |C|0 | cPage |0
- * +----------------+ +----------------+ +----------------+
- *
- *
- * Where:
- * cbSize: The nbr of bytes to the end of the block
- * cbBack The nbr of bytes of the previous block
- * C: The next/back block is adjacent.
- * Back VM Ptr: The VM Pointer to the previously allocated block.
- * Free Next: The VM pointer to the next free block.
- * Free Back: The VM pointer to the previouse free block.
- *
- * What is known:
- *
- * 1) Any free block is at least HDF is size. If not, it is merged
- * in with the previous allocation.
- *
- * 2) sizeof(HDF) >= sizeof(HDB) >= sizeof(HDP)
- *
- * 3) cbBack is zero if the previous block is not adjacent.
- *
- *************************************************************************/
- HBK VMFUNC __HbkVmAllocate(
- unsigned long cb
- ) {
- unsigned long cbT;
-
- VPVOID vp = vpNil;
- PHDP phdb;
-
- if (!_fVmInit)
- 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));
-
- // If the allocation is big, or the allocation is close to a page
- // size, then put it in as pages and not in the allocation list
- if( (cbT > cbBig || cbT == cbVmPage ||
- (cbVmPage - (cbT % cbVmPage)) < cbClose) &&
- (vp = __VpVmAllocateCb(cb + sizeof(HDB))) )
- {
-
- // load the first page
- phdb = __PVmLoadVp(vp, TRUE);
-
- // initialize the page stuff
- _fmemset( phdb, 0, sizeof(HDB) );
- phdb->cPage = (unsigned short) ((cb + sizeof(HDB) + cbVmPage - 1) / cbVmPage);
- phdb->fByPage = TRUE;
- }
-
- // if we know we have an item in the list see if it is big enough
- else if(cbT <= cbBig &&
- !(_gvmbm.cFree && (vp = __VpAllocInFree((unsigned) cbT))) )
- vp = __VpAllocAtEnd( (unsigned) cbT );
-
-
- // check the free list
- #ifdef VMDEBUG
- {
- HBK hbk, hbkBackHdf;
- PHDF phdf;
-
- hbk = _gvmbm.hbkFreeStart;
- hbkBackHdf = NULL;
- while( hbk )
- {
- phdf = __PVmLoadVp( (VPVOID) hbk, FALSE );
- Assert( phdf != NULL );
- Assert( phdf->fFree == TRUE );
- Assert( phdf->hbkBackHdf == hbkBackHdf );
- hbkBackHdf = hbk;
- hbk = phdf->hbkNextHdf;
- }
- }
- #endif
-
- return((HBK) vp);
- }
-
- /*** VpAllocAtEnd
- *
- * Purpose: Allocate cb bytes at the end of the allocate chain
- *
- * Input:
- * cb The minimum number of bytes to allocate. This count MUST
- * include the bytes for the header too.
- *
- * Output:
- * Returns:
- * A a vp to the block allocated
- *
- * Exceptions:
- *
- * Notes:
- *
- * It is known that no current free pages are big enough because then
- * were checked already
- *
- * All sizes are rounded up to a word.
- * If there is extra space in the current page, it is marked as free.
- * If the extra space is not big enough to contain an HDF, then the
- * space is included as part of the allocation.
- *
- *************************************************************************/
- VPVOID pascal near __VpAllocAtEnd(
- unsigned cb
- ) {
- VPVOID vp = vpNil, vpFree;
- SZBK szbk;
- HBK hbkBack = _gvmbm.hbkLastBlock;
- PHDF phdf;
- PHDB phdb;
- unsigned cbAllocSize;
-
- // the size must include the HDB, so it better be >=.
- Assert( cb >= sizeof(HDF) );
- _fmemset( &szbk, 0, sizeof(SZBK) );
-
- // go ahead and allocate the needed pages
- // realize that one few pages may be needed if the VMs are adjacent.
- if( (vp = __VpVmAllocateCb(cb + sizeof(HDB))) ) {
-
- cbAllocSize = (unsigned) (((cb + (unsigned long) cbVmPage - 1) / cbVmPage) * cbVmPage);
-
- // see if a free block needs to be made
- if( cbAllocSize >= cb + sizeof(HDF) ) {
-
- // get the free pointer
- vpFree = vp + cb;
-
- // make the free header
- phdf = __PVmLoadVp(vpFree, TRUE);
- _fmemset(phdf, 0, sizeof(HDF));
- phdf->fFree = TRUE;
- phdf->cbSize = CbMakeSize(cbAllocSize - cb, 0);
- phdf->szbkBack.cbSize = CbMakeSize(cb, 1);
-
- // add to the free list, and update the last block pointer
- __VmFreeLinkEnd( (HBK) vpFree, cbAllocSize - cb );
- _gvmbm.hbkLastBlock = (HBK) vpFree;
- }
-
- else {
- vpFree = vpNil;
- cb = cbAllocSize;
- _gvmbm.hbkLastBlock = (HBK) vp;
- }
-
- // the vp pointer points to the start of the block, initalize it
- phdb = __PVmLoadVp(vp, TRUE);
-
- // initialize the new allocated block
- _fmemset( phdb, 0, sizeof(HDB) );
- phdb->cbSize = CbMakeSize(cb,0);
- phdb->szbkBack = szbk;
- phdb->fAdjacent = (vpFree != vpNil);
-
- }
-
- // return the VM pointer
- return(vp);
- }
-
- /*** VpAllocInFree
- *
- * Purpose: Allocate cb bytes in the free list
- *
- * Input:
- * cb The minimum number of bytes to allocate. This count MUST
- * include the bytes for the header too.
- *
- * Output:
- * Returns:
- * A a vp to the block allocated
- *
- * Exceptions:
- *
- * Notes:
- *
- * All sizes are rounded up to a word.
- * If there is extra space in the block, it is marked as free.
- * If the extra space is not big enough to contain an HDF within the
- * same page, then the space is included as part of the allocation.
- *
- *************************************************************************/
- VPVOID near pascal __VpAllocInFree(
- unsigned cb
- ) {
-
- unsigned cbMaxFree = 0;
- VPVOID vp = vpNil, vpFree;
- PHDF phdf;
- PHDB phdb;
- HBK hbk;
- unsigned cbFree;
- HDF hdf;
-
- Assert( cb >= sizeof(HDF) );
-
- // If we are to search the free list
- if( _gvmbm.cFree && _gvmbm.cbMaxFree >= cb ) {
-
- hbk = _gvmbm.hbkFreeLast;
-
- // look until we find a page
- while( hbk ) {
-
- phdf = __PVmLoadVp((VPVOID) hbk, FALSE);
- Assert( phdf->fFree == TRUE );
-
- // is it big enough?
- if( CbGetSize(phdf->cbSize) >= cb ) {
-
- vp = (VPVOID) hbk;
-
- // see if we are going to corrupt the max free size
- // information that we have. If we found the big one
- // then we don't know what the max is. Set it to the
- // absolute max so we search the list again.
- cbFree = CbGetSize(phdf->cbSize);
- if( _gvmbm.cbMaxFree == cbFree)
- _gvmbm.cbMaxFree = cbMaxFreeSize;
-
- // save the original state
- hdf = *phdf;
-
- break;
- }
-
- cbMaxFree = max(cbMaxFree, CbGetSize(phdf->cbSize));
- hbk = phdf->hbkBackHdf;
- }
-
- // if we didn't find a vp, then we searched the whole
- // free list and we know the max size
- if( !vp ) {
- Assert( cbMaxFree <= _gvmbm.cbMaxFree );
- _gvmbm.cbMaxFree = cbMaxFree;
- }
- }
-
- // only if we found a free block big enough
- // we also know the page is loaded and pointed to by phdf
- if( vp ) {
-
- _gvmbm.cFree--;
-
- // if no room for the free block
- if( (cbFree - cb) < sizeof(HDF) ) {
- cb = cbFree;
- cbFree = 0;
- vpFree = vpNil;
- }
-
- // see if we can get the allocated block on one page by choosing the
- // top half of the free area rather than the bottom.
- else if( vp != ((VPVOID) _gvmbm.hbkLastBlock) &&
- VpVmPageVp(vp + cbFree - cb) ==
- VpVmPageVp(vp + cbFree - 1) ) {
- vpFree = vp;
- vp = vp + cbFree - cb;
- cbFree -= cb;
- }
-
- // if the free header is on one page, set the free mark
- else if( VpVmPageVp(vp + cb) ==
- VpVmPageVp(vp + cb + sizeof(HDF) - 1) ) {
- vpFree = vp + cb;
- cbFree -= cb;
- }
-
- // see if we can move the free up some
- else if( (VpVmPageVp(vp + cb) + (unsigned long) cbVmPage + sizeof(HDF)) <=
- (vp + cbFree) ) {
- vpFree = VpVmPageVp(vp + cb) + (unsigned long) cbVmPage;
- cb += cbEndPage((unsigned)vp + cb);
- cbFree -= cb;
- }
-
- // page breaks are against us, we have to keep the block as is
- else {
- cb = cbFree;
- cbFree = 0;
- vpFree = vpNil;
- }
-
- // since we found a free block, _gvmbm.hbkLastBlock can't be NULL
- // But if either vp or vpFree == _gvmbm.hbkLastBlock, then the
- // other pointer( vpFree or vp respectively) must be the new end.
- Assert( _gvmbm.hbkLastBlock != NULL );
- if( vpFree && vp == (VPVOID) _gvmbm.hbkLastBlock )
- _gvmbm.hbkLastBlock = (HBK) vpFree;
- else if( vpFree == (VPVOID) _gvmbm.hbkLastBlock )
- _gvmbm.hbkLastBlock = (HBK) vp;
-
- // do the free page first, this way the allocated page will be
- // loaded on return
- if( cbFree ) {
-
- phdf = __PVmLoadVp(vpFree, TRUE);
-
- _fmemset(phdf, 0, sizeof(HDF) );
- phdf->cbSize = CbMakeSize(cbFree, FALSE);
- phdf->fFree = TRUE;
-
- // I know that if the free is on the bottom, then the free block
- // is still in the free list. Also it is known that the allocated
- // block is adjacent to the free (doesn't have to be in the
- // same page thougth, just adjacent vm).
- if(vpFree < vp) {
- phdf->szbkBack = hdf.szbkBack;
- phdf->fAdjacent = TRUE;
- phdf->hbkBackHdf = hdf.hbkBackHdf;
- phdf->hbkNextHdf = hdf.hbkNextHdf;
- _gvmbm.cFree++;
-
- // fixup the next block to have the free size
- if(hdf.fAdjacent) {
- phdb = __PVmLoadVp((vp + cb), TRUE);
- phdb->szbkBack.cbSize = CbMakeSize(cb, TRUE);
- }
- }
-
- // if vp < vpFree, then we know the old vp pointer contains
- // the linkage to the free list
- else {
- phdf->szbkBack.cbSize = CbMakeSize(cb, TRUE);
- phdf->fAdjacent = hdf.fAdjacent;
-
- __VmFreeLinkIn((HBK) vpFree, cbFree,
- hdf.hbkBackHdf, hdf.hbkNextHdf);
-
- // fixup the next block to have the free size
- if(hdf.fAdjacent) {
- phdb = __PVmLoadVp((vpFree + cbFree), TRUE);
- phdb->szbkBack.cbSize = CbMakeSize(cbFree, TRUE);
- }
- }
- }
-
- // the free entry no longer exists so fix up the linkage
- else
- __VmFreeLink(hdf.hbkBackHdf, hdf.hbkNextHdf);
-
- // now fix up the vp
- phdb = __PVmLoadVp(vp, TRUE);
- _fmemset(phdb, 0, sizeof(HDB));
- phdb->cbSize = CbMakeSize(cb, hdf.fAdjacent);
-
- // if the vp is in the lower spot.
- if( !vpFree || vp < vpFree ) {
-
- phdb->szbkBack = hdf.szbkBack;
- phdb->fAdjacent = ((vpFree != vpNil) || hdf.fAdjacent);
- }
-
- // the vp is in the upper page, only need the back pointer
- else
- phdb->szbkBack.cbSize = CbMakeSize(cbFree, TRUE);
- }
-
- return(vp);
- }
-
- /*** VmInitialize
- *
- * Purpose:
- *
- * Input:
- *
- * Output:
- * Returns:
- *
- * Exceptions:
- *
- * Notes:
- *
- *
- *************************************************************************/
- int VMFUNC __VmInitialize( unsigned cVmParaMin, unsigned cParaVmDosMax, unsigned bitSwapArea ) {
- _fmemset(&_gvmbm, 0, sizeof(GVMBM));
- _gvmbm.cbMaxFree = cbMaxFreeSize;
- return(__FVmInitialize(cVmParaMin, cParaVmDosMax, bitSwapArea));
- };
-