home *** CD-ROM | disk | FTP | other *** search
- /***
- *vmlist.c - Free List Maintenance
- *
- * Copyright (c) 1992, Microsoft Corporation. All rights reserved.
- *
- *Purpose: Generic circular free list.
- *
- *******************************************************************************/
-
- #include <version.h>
- #include <vmassert.h>
- #include <system.h>
- #include <error.h>
- #include <vm.h>
- #include <vmp.h>
- #include <vmlist.h>
-
- #define max(A,B) ((A) > (B) ? (A) : (B))
-
- #ifdef VMDEBUG
-
- void PRIVATE __VmCheckFreeBlock( PFBD pfbdHead )
- {
- PFBD pfbd1 = pfbdHead;
- PFBD pfbd2;
-
- if (pfbd1 == pfbdNil)
- return;
-
- pfbd2 = pfbd1->next;
-
- while (pfbd1 != pfbdNil)
- {
- Assert(pfbd1->cPage > 0);
-
- Assert(pfbd1->cbOffset % cbVmPage == 0);
-
- Assert(!pfbd2 ||
- pfbd1->cbOffset+pfbd1->cPage*cbVmPage <= pfbd2->cbOffset);
-
- pfbd1 = pfbd2;
- if (pfbd2 != pfbdNil)
- pfbd2 = pfbd2->next;
- }
- }
-
- #endif /*VMDEBUG*/
-
-
- unsigned long PRIVATE __VmGetFreeMax(PFBD pfbdHead)
- {
- PFBD pfbd = pfbdHead;
- unsigned long cMax = 0L;
-
- while (pfbd != pfbdNil)
- {
- cMax = max(cMax, pfbd->cPage);
- pfbd = pfbd->next;
- }
- return cMax;
- }
-
-
- // Keep "circular" linked list, start from the next block after last
- // allocation - avoid small unusable blocks at start of linear list
-
- int PUBLIC __VmGetFreeBlock(
- PFBD *pfbdHead,
- PFBD *pfbdCurr,
- unsigned long *cMax,
- unsigned long cPage,
- unsigned long *cbOffset)
- {
- PFBD pfbd1, pfbd2;
-
- VmTracePrintf(("VpGetFreeBlock: cPage=%08lX *cMax=%08lX.\n", cPage, *cMax));
-
- #ifdef VMDEBUG
- __VmCheckFreeBlock(*pfbdHead);
- #endif /*VMDEBUG*/
-
- if (*pfbdHead == pfbdNil)
- return 0;
-
- // we start loking at the node after curr
- pfbd1 = *pfbdCurr;
- pfbd2 = ((*pfbdCurr)->next != pfbdNil) ? (*pfbdCurr)->next : *pfbdHead;
-
- // in this while loop, pfbd2 always points to the node of interest, and
- // pfbd1 trails to allow chain fixup. We start at the node after curr and
- // go circularly until we find a big enough space (first fit) or go full
- // circle
-
- while (1)
- {
- // found a free block that is bigger than we need
- if (cPage < pfbd2->cPage)
- {
- *cbOffset = pfbd2->cbOffset;
- pfbd2->cPage -= cPage;
- pfbd2->cbOffset += cPage * cbVmPage;
- *pfbdCurr = pfbd2;
- *cMax = __VmGetFreeMax(*pfbdHead);
- return 1;
- }
- // found a free block that is exactly the right size
- if (cPage == pfbd2->cPage)
- {
- *cbOffset = pfbd2->cbOffset;
-
- if (pfbd2 == *pfbdHead) // remove head of list
- *pfbdHead = (*pfbdHead)->next;
- else // remove from middle
- pfbd1->next = pfbd2->next;
-
- // adust current to node after current allocation
- *pfbdCurr = (pfbd2->next != pfbdNil) ? pfbd2->next : *pfbdHead;
- _VmFree(pfbd2);
- *cMax = __VmGetFreeMax(*pfbdHead);
- return 1;
- }
- // done the loop, no blocks big enough
- if (pfbd2 == *pfbdCurr)
- return 0;
-
- pfbd1 = pfbd2;
- pfbd2 = (pfbd2->next != pfbdNil) ? pfbd2->next : *pfbdHead;
- }
- return 0;
- }
-
-
- // This routine adds a new free block descriptor to the linked list.
- // It uses two pointers to scan the list until the proper place is found.
- // New block is merged with old blocks when appropriate.
-
- int PUBLIC __VmAddFreeBlock(
- PFBD *pfbdHead,
- PFBD *pfbdCurr,
- unsigned long *cMax,
- unsigned long cPage,
- unsigned long cbOffset )
- {
- PFBD pfbd1, pfbd2;
-
- VmTracePrintf(("VpAddFreeBlock: cPage=%08lX cbOffset=%08lX.\n", cPage, cbOffset));
-
- #ifdef VMDEBUG
- __VmCheckFreeBlock(*pfbdHead);
- #endif /*VMDEBUG*/
-
- // empty list
- if (*pfbdHead == pfbdNil)
- {
- if (!(*pfbdHead = *pfbdCurr = (PFBD)_VmMalloc(sizeof(FBD))))
- return 0;
- (*pfbdHead)->cPage = cPage;
- *cMax = (*pfbdHead)->cPage;
- (*pfbdHead)->cbOffset = cbOffset;
- (*pfbdHead)->next = pfbdNil;
- return 1;
- }
-
- // new first item in list
- if (cbOffset + cPage * cbVmPage < (*pfbdHead)->cbOffset)
- {
- if (!(pfbd1 = (PFBD)_VmMalloc(sizeof(FBD))))
- return 0;
- pfbd1->cPage = cPage;
- *cMax = max(*cMax, pfbd1->cPage);
- pfbd1->cbOffset = cbOffset;
- pfbd1->next = *pfbdHead;
- *pfbdHead = pfbd1;
- return 1;
- }
-
- // merge with first item in list
- if (cbOffset + cPage * cbVmPage == (*pfbdHead)->cbOffset)
- {
- (*pfbdHead)->cbOffset = cbOffset;
- (*pfbdHead)->cPage += cPage;
- *cMax = max(*cMax, (*pfbdHead)->cPage);
- return 1;
- }
-
- // new block must go after first item in list
- pfbd1 = *pfbdHead;
- pfbd2 = (*pfbdHead)->next;
-
- while (1) {
- // if we haven't found the proper place, keep moving
- if (pfbd2 != pfbdNil && cbOffset > pfbd2->cbOffset)
- {
- pfbd1 = pfbd2;
- pfbd2 = pfbd2->next;
- continue;
- }
-
- // place new node after pfbd1 in list, pfbd2 may be == pfbdNil
-
- // merge with previous block
- if (pfbd1->cbOffset + pfbd1->cPage * cbVmPage == cbOffset)
- {
- pfbd1->cPage += cPage;
-
- // also merge with next block
- if (cbOffset + cPage * cbVmPage == pfbd2->cbOffset)
- {
- pfbd1->cPage += pfbd2->cPage;
- pfbd1->next = pfbd2->next;
- if (*pfbdCurr == pfbd2)
- *pfbdCurr = pfbd1;
- _VmFree(pfbd2);
- }
- *cMax = max(*cMax, pfbd1->cPage);
- return 1;
- }
-
- // merge with next block
- if (cbOffset + cPage * cbVmPage == pfbd2->cbOffset)
- {
- pfbd2->cbOffset = cbOffset;
- pfbd2->cPage += cPage;
- *cMax = (pfbd2->cPage > *cMax) ? pfbd2->cPage : *cMax;
- return 1;
- }
-
- // make new node
- if (!(pfbd1->next = (PFBD)_VmMalloc(sizeof(FBD))))
- return 0;
- pfbd1 = pfbd1->next;
- pfbd1->cPage = cPage;
- *cMax = (pfbd1->cPage > *cMax) ? pfbd1->cPage : *cMax;
- pfbd1->cbOffset = cbOffset;
- pfbd1->next = pfbd2;
- return 1;
- }
- }
-
-
- // Frees the linked list
-
- void PUBLIC __VmFreeFreeBlock(PFBD *pfbdHead, PFBD *pfbdCurr, unsigned long *cMax)
- {
- PFBD pfbd1, pfbd2;
-
- pfbd1 = *pfbdHead;
-
- while (pfbd1 != pfbdNil)
- {
- pfbd2 = pfbd1->next;
- _VmFree(pfbd1);
- pfbd1 = pfbd2;
- }
- *pfbdHead = pfbdNil;
- *pfbdCurr = pfbdNil;
- *cMax = 0;
- }
-
-
-
-