windows-nt/Source/XPSP1/NT/com/ole32/stg/msf/page.cxx
2020-09-26 16:20:57 +08:00

1148 lines
29 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1992.
//
// File: page.cxx
//
// Contents: Paging code for MSF
//
// Classes: Defined in page.hxx
//
// Functions:
//
// History: 20-Oct-92 PhilipLa Created
//
//----------------------------------------------------------------------------
#include "msfhead.cxx"
#pragma hdrstop
#include <mread.hxx>
#include <filest.hxx>
#define FLUSH_MULTIPLE
//+---------------------------------------------------------------------------
//
// Member: CMSFPage::SetSect, public
//
// Synopsis: Sets the SECT for this page
//
// History: 20-Oct-92 PhilipLa Created
//
//----------------------------------------------------------------------------
#ifdef SORTPAGETABLE
inline void CMSFPage::SetSect(const SECT sect)
{
msfAssert(_pmpNext != NULL && _pmpPrev != NULL);
msfAssert((_pmpPrev->_sect >= _pmpNext->_sect) || //Edge
((_sect >= _pmpPrev->_sect) && (_sect <= _pmpNext->_sect)));
_sect = sect;
}
#endif
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::IsSorted, public
//
// Synopsis: Return TRUE if the specified page is in the right place
// in the list.
//
// Arguments: [pmp] -- Page to check
//
// History: 13-Dec-95 PhilipLa Created
//
//----------------------------------------------------------------------------
inline BOOL CMSFPageTable::IsSorted(CMSFPage *pmp)
{
//There are three cases:
//1) Page is first in the list.
//2) Page is last in the list.
//3) Page is in the middle of the list.
SECT sect = pmp->GetSect();
CMSFPage *pmpStart = BP_TO_P(CMSFPage *, _pmpStart);
CMSFPage *pmpNext = pmp->GetNext();
if (pmp == pmpStart)
{
return (sect <= pmpNext->GetSect());
}
if (pmpNext == pmpStart)
{
return (sect >= pmp->GetPrev()->GetSect());
}
return ((sect <= pmpNext->GetSect()) &&
(sect >= pmp->GetPrev()->GetSect()));
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::SetSect, public
//
// Synopsis: Set the sector stamp on a page, and sort the list if
// necessary.
//
// Arguments: [pmp] -- Pointer to page to stamp
// [sect] -- SECT to stamp it with
//
// Returns: void
//
// History: 12-Dec-95 PhilipLa Created
//
//----------------------------------------------------------------------------
void CMSFPageTable::SetSect(CMSFPage *pmp, SECT sect)
{
msfDebugOut((DEB_ITRACE, "In CMSFPageTable::SetSect:%p(%p, %lX)\n",
this,
pmp,
sect));
pmp->SetSect(sect);
//Resort list if necessary.
if (!IsSorted(pmp))
{
CMSFPage *pmpTemp, *pmpStart;
pmpStart = BP_TO_P(CMSFPage *, _pmpStart);
if (pmpStart == pmp)
{
pmpStart = pmp->GetNext();
_pmpStart = P_TO_BP(CBasedMSFPagePtr , pmpStart);
}
pmp->Remove();
pmpTemp = pmpStart;
while (sect > pmpTemp->GetSect())
{
pmpTemp = pmpTemp->GetNext();
if (pmpTemp == pmpStart)
{
break;
}
}
//Insert node before pmpTemp.
pmpTemp->GetPrev()->SetNext(pmp);
pmp->SetChain(pmpTemp->GetPrev(), pmpTemp);
pmpTemp->SetPrev(pmp);
if (sect <= pmpStart->GetSect())
{
_pmpStart = P_TO_BP(CBasedMSFPagePtr, pmp);
}
}
msfAssert(IsSorted(pmp));
msfDebugOut((DEB_ITRACE, "Out CMSFPageTable::SetSect\n"));
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::CMSFPageTable, public
//
// Synopsis: CMSFPageTable constructor.
//
// Arguments: [pmsParent] -- Pointer to multistream for this page table.
//
// History: 22-Oct-92 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
CMSFPageTable::CMSFPageTable(
CMStream *const pmsParent,
const ULONG cMinPages,
const ULONG cMaxPages)
: _cbSector(pmsParent->GetSectorSize()),
_cMinPages(cMinPages), _cMaxPages(cMaxPages)
{
_pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
_cActivePages = 0;
_cPages = 0;
_pmpCurrent = NULL;
#ifdef SORTPAGETABLE
_pmpStart = NULL;
#endif
_cReferences = 1;
#if DBG == 1
_cCurrentPageRef = 0;
_cMaxPageRef = 0;
#endif
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPage::CMSFPage, public
//
// Synopsis: CMSFPage default constructor
//
// History: 20-Oct-92 PhilipLa Created
//
//----------------------------------------------------------------------------
#if DBG == 1
CMSFPage::CMSFPage(CMSFPage *pmp, CMSFPageTable *pmpt)
#else
CMSFPage::CMSFPage(CMSFPage *pmp)
#endif
{
if (pmp == NULL)
{
SetChain(this, this);
}
else
{
SetChain(pmp->GetPrev(), pmp);
GetPrev()->SetNext(this);
GetNext()->SetPrev(this);
}
#if DBG == 1
_pmpt = P_TO_BP(CBasedMSFPageTablePtr, pmpt);
#endif
SetSid(NOSTREAM);
SetOffset(0);
// SetSect(ENDOFCHAIN);
//SetSect() contains assertions to verify sortedness of the list,
//which we don't want here.
_sect = ENDOFCHAIN;
SetFlags(0);
SetVector(NULL);
_cReferences = 0;
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::GetNewPage, private
//
// Synopsis: Insert a new page into the list and return a pointer to it.
//
// Arguments: None.
//
// Returns: Pointer to new page. Null if there was an allocation error.
//
// History: 22-Oct-92 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline CMSFPage * CMSFPageTable::GetNewPage(void)
{
#ifndef SORTPAGETABLE
#if DBG == 1
return new (_pmsParent->GetMalloc(), (size_t)_cbSector)
CMSFPage(BP_TO_P(CMSFPage *, _pmpCurrent), this);
#else
return new (_pmsParent->GetMalloc(), (size_t)_cbSector)
CMSFPage(BP_TO_P(CMSFPage *, _pmpCurrent));
#endif
#else
#if DBG == 1
return new (_pmsParent->GetMalloc(), (size_t)_cbSector)
CMSFPage(BP_TO_P(CMSFPage *, _pmpStart), this);
#else
return new (_pmsParent->GetMalloc(), (size_t)_cbSector)
CMSFPage(BP_TO_P(CMSFPage *, _pmpStart));
#endif
#endif //SORTPAGETABLE
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::~CMSFPageTable, public
//
// Synopsis: CMSFPageTable destructor
//
// History: 26-Oct-92 PhilipLa Created
// 21-Jul-95 SusiA Modified to delete the object without
// obtaining the mutex. Calling functions
// should have locked the mutex first.
//
//----------------------------------------------------------------------------
CMSFPageTable::~CMSFPageTable()
{
if (_pmpCurrent != NULL)
{
CMSFPage *pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
CMSFPage *pmpNext;
while (pmp != pmp->GetNext())
{
pmpNext = pmp->GetNext();
msfAssert(pmpNext != NULL &&
aMsg("NULL found in page table circular list."));
#if DBG == 1
msfAssert(!pmp->IsInUse() &&
aMsg("Active page left at page table destruct time."));
if (!_pmsParent->IsScratch())
{
//Dirty paged can be thrown away if we are unconverted or
// in a commit.
if ((!_pmsParent->IsUnconverted()) &&
(_pmsParent->GetParentSize() == 0))
{
msfAssert(!pmp->IsDirty() &&
aMsg("Dirty page left at page table destruct time."));
}
}
#endif
pmp->~CMSFPage();
pmp->deleteNoMutex(pmp);
pmp = pmpNext;
}
pmp->~CMSFPage();
pmp->deleteNoMutex(pmp);
}
#if DBG == 1
msfDebugOut((DEB_ITRACE,
"Page Table Max Page Count for %s: %lu\n",
(_pmsParent->IsScratch()) ? "Scratch" : "Base",
_cMaxPageRef));
#endif
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::Init, public
//
// Synopsis: Initialize a CMSFPageTable
//
// Arguments: [cPages] -- Number of pages to preallocate.
//
// Returns: Appropriate status code
//
// History: 22-Oct-92 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::Init(void)
{
SCODE sc = S_OK;
msfDebugOut((DEB_ITRACE, "In CMSFPageTable::Init:%p()\n", this));
for (ULONG i = 0; i < _cMinPages; i++)
{
CMSFPage *pmp;
msfMem(pmp = GetNewPage());
#ifndef SORTPAGETABLE
_pmpCurrent = P_TO_BP(CBasedMSFPagePtr, pmp);
#else
_pmpStart = P_TO_BP(CBasedMSFPagePtr, pmp);
#endif
}
_cPages = _cMinPages;
_cActivePages = 0;
#ifdef SORTPAGETABLE
_pmpCurrent = _pmpStart;
#endif
msfDebugOut((DEB_ITRACE, "Out CMSFPageTable::Init\n"));
Err:
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::FlushPage, public
//
// Synopsis: Flush a page
//
// Arguments: [pmp] -- Pointer to page to flush
//
// Returns: Appropriate status code
//
// History: 09-Nov-92 PhilipLa Created
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::FlushPage(CMSFPage *pmp)
{
SCODE sc = S_OK;
pmp->AddRef();
CMStream *pms;
pms = pmp->GetVector()->GetParent();
//Flush the page, reset the dirty bit.
msfAssert((pmp->GetSect() != ENDOFCHAIN) &&
aMsg("Page location not set - don't know where to flush to."));
msfAssert (pms != NULL);
ULONG ulRet;
ILockBytes *pilb;
#if DBG == 1
if ((pmp->GetSid() == SIDFAT) && (pms->IsInCOW()))
{
msfDebugOut((DEB_ITRACE, "** Fat sect %lu written to %lX\n",
pmp->GetOffset(), pmp->GetSect()));
}
if ((pmp->GetSid() == SIDDIF) && (pms->IsInCOW()))
{
msfDebugOut((DEB_ITRACE, "** DIF sect %lu written to %lX\n",
pmp->GetOffset(), pmp->GetSect()));
}
#endif
ULARGE_INTEGER ul;
#ifdef LARGE_DOCFILE
ul.QuadPart = ConvertSectOffset(
pmp->GetSect(),
0,
pms->GetSectorShift());
#else
ULISet32(ul, ConvertSectOffset(
pmp->GetSect(),
0,
pms->GetSectorShift()));
#endif
pilb = pms->GetILB();
msfAssert(!pms->IsUnconverted() &&
aMsg("Tried to flush page to unconverted base."));
sc = GetScode(pilb->WriteAt(ul,
(BYTE *)(pmp->GetData()),
_cbSector,
&ulRet));
if (sc == E_PENDING)
{
sc = STG_E_PENDINGCONTROL;
}
msfChk(sc);
pmp->ResetDirty();
Err:
pmp->Release();
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::GetFreePage, public
//
// Synopsis: Return a pointer to a free page.
//
// Arguments: [ppmp] -- Pointer to storage for return pointer
//
// Returns: Appropriate status code
//
// History: 22-Oct-92 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::GetFreePage(CMSFPage **ppmp)
{
SCODE sc = S_OK;
CMSFPage *pmp;
if (_cPages > _cActivePages)
{
//We have some unused page already allocated. Find and return it.
pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
do
{
pmp = pmp->GetNext();
}
while ((pmp != _pmpCurrent) && (pmp->GetSid() != NOSTREAM));
msfAssert((pmp->GetSid() == NOSTREAM) &&
aMsg("Expected empty page, none found."));
*ppmp = pmp;
_cActivePages++;
}
else if (_cPages == _cMaxPages)
{
msfMem(pmp = FindSwapPage());
msfDebugOut((DEB_ITRACE, "Got swap page %p\n",pmp));
msfAssert((pmp->GetVector() != NULL) &&
aMsg("FindSwapPage returned unowned page."));
msfDebugOut((DEB_ITRACE, "Freeing page %lu from vector %p\n",
pmp->GetOffset(), pmp->GetVector()));
if (pmp->IsDirty())
{
msfChk(FlushPage(pmp));
msfAssert(!pmp->IsDirty() &&
aMsg("Page remained dirty after flush call"));
}
pmp->GetVector()->FreeTable(pmp->GetOffset());
#if DBG == 1
pmp->SetVector(NULL);
#endif
*ppmp = pmp;
}
else
{
//Create a new page and return it.
pmp = GetNewPage();
if (pmp != NULL)
{
*ppmp = pmp;
_cActivePages++;
_cPages++;
}
else
{
msfMem(pmp = FindSwapPage());
if (pmp->IsDirty())
{
msfChk(FlushPage(pmp));
msfAssert(!pmp->IsDirty() &&
aMsg("Page remained dirty after flush call"));
}
pmp->GetVector()->FreeTable(pmp->GetOffset());
#if DBG == 1
pmp->SetVector(NULL);
#endif
*ppmp = pmp;
}
}
Err:
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::FindPage, public
//
// Synopsis: Find and return a given page
//
// Arguments: [ppv] -- Pointer to vector of page to return
// [sid] -- SID of page to return
// [ulOffset] -- Offset of page to return
// [ppmp] -- Location to return pointer
//
// Returns: Appropriate status code
//
// History: 22-Oct-92 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::FindPage(
CPagedVector *ppv,
SID sid,
ULONG ulOffset,
CMSFPage **ppmp)
{
SCODE sc;
CMSFPage *pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
do
{
if ((pmp->GetVector() == ppv) && (pmp->GetOffset() == ulOffset))
{
//Bingo!
*ppmp = pmp;
return STG_S_FOUND;
}
pmp = pmp->GetNext();
}
while (pmp != _pmpCurrent);
//The page isn't currently in memory. Get a free page and
//bring it into memory.
msfChk(GetFreePage(&pmp));
msfAssert((pmp->GetVector() == NULL) &&
aMsg("Attempting to reassign owned page."));
pmp->SetVector(ppv);
pmp->SetSid(sid);
pmp->SetOffset(ulOffset);
#ifdef SORTPAGETABLE
SetSect(pmp, ENDOFCHAIN);
#else
pmp->SetSect(ENDOFCHAIN);
#endif
*ppmp = pmp;
Err:
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::GetPage, public
//
// Synopsis: Find and return a given page
//
// Arguments: [sid] -- SID of page to return
// [ulOffset] -- Offset of page to return
// [ppmp] -- Location to return pointer
//
// Returns: Appropriate status code
//
// History: 22-Oct-92 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::GetPage(
CPagedVector *ppv,
SID sid,
ULONG ulOffset,
SECT sectKnown,
CMSFPage **ppmp)
{
SCODE sc;
*ppmp = NULL;
msfChk(FindPage(ppv, sid, ulOffset, ppmp));
(*ppmp)->AddRef();
if (sc != STG_S_FOUND)
{
ULONG ulRet;
SECT sect;
if (sectKnown != ENDOFCHAIN)
{
sect = sectKnown;
}
else
{
msfChk(ppv->GetParent()->GetSect(sid, ulOffset, &sect));
}
#ifdef SORTPAGETABLE
SetSect(*ppmp, sect);
#else
(*ppmp)->SetSect(sect);
#endif
CMStream *pms = (*ppmp)->GetVector()->GetParent();
#if DBG == 1
if ((sid == SIDFAT) && (pms->IsInCOW()))
{
msfDebugOut((DEB_ITRACE, "Fat sect %lu read from %lX\n",
ulOffset, sect));
}
if ((sid == SIDDIF) && (pms->IsInCOW()))
{
msfDebugOut((DEB_ITRACE, "DIF sect %lu read from %lX\n",
ulOffset, sect));
}
#endif
ULARGE_INTEGER ul;
#ifdef LARGE_DOCFILE
ul.QuadPart = ConvertSectOffset(
(*ppmp)->GetSect(),
0,
pms->GetSectorShift());
#else
ULISet32(ul, ConvertSectOffset(
(*ppmp)->GetSect(),
0,
pms->GetSectorShift()));
#endif
msfAssert(pms->GetILB() != NULL &&
aMsg("NULL ILockBytes - missing SetAccess?"));
sc = GetScode(pms->GetILB()->ReadAt(ul,
(BYTE *)((*ppmp)->GetData()),
_cbSector,
&ulRet));
if (sc == E_PENDING)
{
sc = STG_E_PENDINGCONTROL;
}
msfChk(sc);
if (ulRet != _cbSector)
{
// 09/23/93 - No error, but insufficient bytes read
sc = STG_E_READFAULT;
}
}
Err:
if (*ppmp != NULL)
{
if (FAILED(sc))
{
// 09/19/93 - Reset page so that we don't accidentally use it
(*ppmp)->SetSid(NOSTREAM);
(*ppmp)->SetOffset(0);
#ifdef SORTPAGETABLE
SetSect(*ppmp, ENDOFCHAIN);
#else
(*ppmp)->SetSect(ENDOFCHAIN);
#endif
(*ppmp)->SetFlags(0);
(*ppmp)->SetVector(NULL);
_cActivePages--;
}
(*ppmp)->Release();
}
return sc;
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::ReleasePage, public
//
// Synopsis: Release a given page
//
// Arguments: [sid] -- SID of page to release
// [ulOffset] -- Offset of page to release
//
// History: 28-Oct-92 PhilipLa Created
//
//----------------------------------------------------------------------------
void CMSFPageTable::ReleasePage(CPagedVector *ppv,
SID sid, ULONG ulOffset)
{
SCODE sc;
CMSFPage *pmp;
sc = FindPage(ppv, sid, ulOffset, &pmp);
if (SUCCEEDED(sc))
{
pmp->Release();
}
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::Flush, public
//
// Synopsis: Flush dirty pages to disk
//
// Returns: Appropriate status code
//
// History: 02-Nov-92 PhilipLa Created
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::Flush(void)
{
#ifndef SORTPAGETABLE
SCODE sc = S_OK;
CMSFPage *pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
//We use pmpLast in case FlushPage changes _pmpCurrent.
CMSFPage *pmpLast = pmp;
do
{
if ((pmp->IsDirty()) && !(pmp->IsInUse()) &&
!(pmp->GetVector()->GetParent()->IsScratch()))
{
msfChk(FlushPage(pmp));
}
pmp = pmp->GetNext();
}
while (pmp != pmpLast);
Err:
return sc;
#else
SCODE sc = S_OK;
msfDebugOut((DEB_ITRACE, "In CMSFPageTable::Flush()\n"));
CMSFPage *pmp;
CMSFPage *pmpStart;
BYTE *pb = NULL;
ULONG ulBufferSize = 0;
pmpStart = BP_TO_P(CMSFPage *, _pmpStart);
pmp = pmpStart;
do
{
CMSFPage *pmpFirst;
CMSFPage *pmpLast;
//Find first page that needs to be flushed.
while (!pmp->IsFlushable())
{
pmp = pmp->GetNext();
if (pmp == pmpStart)
break;
}
//If we haven't hit the end of the list, then find a contiguous
// range of pages to flush.
if (pmp->IsFlushable())
{
pmpFirst = pmp;
//Store pointer to last page in range in pmpLast.
while (pmp->IsFlushable())
{
pmpLast = pmp;
pmp = pmp->GetNext();
if (pmp->GetSect() != pmpLast->GetSect() + 1)
{
break;
}
}
//At this point, we can flush everything from pmpFirst to
// pmpLast, and they are all contiguous. pmp points to the
// next sector after the current range.
if (pmpFirst == pmpLast)
{
msfDebugOut((DEB_ITRACE,
"Flushing page to %lx\n",
pmpFirst->GetSect()));
//Only one page: Call FlushPage.
msfChk(FlushPage(pmpFirst));
}
else
{
ULONG ulWriteSize;
ULONG cSect;
CMSFPage *pmpTemp;
ULONG i;
msfDebugOut((DEB_ITRACE,
"Flushing pages from %lx to %lx\n",
pmpFirst->GetSect(),
pmpLast->GetSect()));
cSect = pmpLast->GetSect() - pmpFirst->GetSect() + 1;
ulWriteSize = cSect * _cbSector;
if (ulWriteSize > ulBufferSize)
{
delete pb;
pb = new BYTE[ulWriteSize];
ulBufferSize = ulWriteSize;
}
pmpTemp = pmpFirst;
if (pb == NULL)
{
ulBufferSize = 0;
//Low memory case - write out pages one at a time
for (i = 0; i < cSect; i++)
{
msfChk(FlushPage(pmpTemp));
pmpTemp = pmpTemp->GetNext();
}
}
else
{
for (i = 0; i < cSect; i++)
{
memcpy(pb + (i * _cbSector),
pmpTemp->GetData(),
_cbSector);
pmpTemp = pmpTemp->GetNext();
}
//The buffer is loaded up - now write it out.
ULARGE_INTEGER ul;
ULONG cbWritten;
ULONG cbTotal = 0;
BYTE *pbCurrent = pb;
#ifdef LARGE_DOCFILE
ul.QuadPart = ConvertSectOffset(pmpFirst->GetSect(),
0,
_pmsParent->GetSectorShift());
#else
ULISet32(ul, ConvertSectOffset(pmpFirst->GetSect(),
0,
_pmsParent->GetSectorShift()));
#endif
while (cbTotal < ulWriteSize)
{
sc = _pmsParent->GetILB()->WriteAt(ul,
pbCurrent,
ulWriteSize - cbTotal,
&cbWritten);
if (sc == E_PENDING)
{
sc = STG_E_PENDINGCONTROL;
}
msfChk(sc);
if (cbWritten == 0)
{
msfErr(Err, STG_E_WRITEFAULT);
}
cbTotal += cbWritten;
pbCurrent += cbWritten;
ul.QuadPart += cbWritten;
}
//Mark all the pages as clean.
pmpTemp = pmpFirst;
for (i = 0; i < cSect; i++)
{
pmpTemp->ResetDirty();
pmpTemp = pmpTemp->GetNext();
}
}
}
}
else
{
//We've hit the end of the list, do nothing.
}
}
while (pmp != pmpStart);
msfDebugOut((DEB_ITRACE, "Out CMSFPageTable::Flush() => %lX\n", sc));
Err:
if (pb != NULL)
{
delete pb;
}
return sc;
#endif //SORTPAGETABLE
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::FreePages, public
//
// Synopsis: Free all the pages associated with a vector.
//
// Arguments: [ppv] -- Pointer to vector to free pages for.
//
// History: 09-Nov-92 PhilipLa Created
//
//----------------------------------------------------------------------------
void CMSFPageTable::FreePages(CPagedVector *ppv)
{
CMSFPage *pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
do
{
if (pmp->GetVector() == ppv)
{
pmp->SetSid(NOSTREAM);
pmp->SetVector(NULL);
pmp->ResetDirty();
_cActivePages--;
}
pmp = pmp->GetNext();
}
while (pmp != _pmpCurrent);
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::FindSwapPage, private
//
// Synopsis: Find a page to swap out.
//
// Arguments: None.
//
// Returns: Pointer to page to swap out.
//
// History: 22-Oct-92 PhilipLa Created
//
//----------------------------------------------------------------------------
CMSFPage * CMSFPageTable::FindSwapPage(void)
{
#if DBG == 1
ULONG cpInUse = 0;
#endif
while (TRUE)
{
if (!_pmpCurrent->IsInUse())
{
DWORD dwFlags;
dwFlags = _pmpCurrent->GetFlags();
_pmpCurrent->SetFlags(dwFlags & ~FB_TOUCHED);
CMSFPage *pmpTemp = _pmpCurrent->GetNext();
_pmpCurrent = P_TO_BP(CBasedMSFPagePtr, pmpTemp);
if (!(dwFlags & FB_TOUCHED))
{
return _pmpCurrent->GetPrev();
}
}
else
{
CMSFPage *pmpTemp = _pmpCurrent->GetNext();
_pmpCurrent = P_TO_BP(CBasedMSFPagePtr, pmpTemp);
}
#if DBG == 1
cpInUse++;
msfAssert((cpInUse < 3 * _cPages) &&
aMsg("No swappable pages."));
#endif
}
}
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::CopyPage, public
//
// Synopsis: Copy a page in memory, returning NULL if there is
// insufficient space for a new page without swapping.
//
// Arguments: [ppv] -- Pointer to vector that will own the copy.
// [pmpOld] -- Pointer to page to copy.
// [ppmp] -- Pointer to return value
//
// Returns: Appropriate status code
//
// Modifies:
//
// History: 04-Dec-92 PhilipLa Created
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::CopyPage(
CPagedVector *ppv,
CMSFPage *pmpOld,
CBasedMSFPagePtr *ppmp)
{
CMSFPage *pmp;
pmp = NULL;
if (pmpOld != NULL)
{
msfAssert(!pmpOld->IsDirty() &&
aMsg("Copying dirty page."));
if (_cPages > _cActivePages)
{
//We have some unused page already allocated. Find and return it.
pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
do
{
pmp = pmp->GetNext();
}
while ((pmp != _pmpCurrent) && (pmp->GetSid() != NOSTREAM));
msfAssert((pmp->GetSid() == NOSTREAM) &&
aMsg("Expected empty page, none found."));
_cActivePages++;
}
else if (_cPages < _cMaxPages)
{
//Create a new page and return it.
pmp = GetNewPage();
if (pmp != NULL)
{
_cActivePages++;
_cPages++;
}
}
if (pmp != NULL)
{
msfAssert((pmp->GetVector() == NULL) &&
aMsg("Attempting to reassign owned page."));
pmp->SetVector(ppv);
pmp->SetSid(pmpOld->GetSid());
pmp->SetOffset(pmpOld->GetOffset());
#ifdef SORTPAGETABLE
SetSect(pmp, pmpOld->GetSect());
#else
pmp->SetSect(pmpOld->GetSect());
#endif
memcpy(pmp->GetData(), pmpOld->GetData(), (USHORT)_cbSector);
}
}
*ppmp = P_TO_BP(CBasedMSFPagePtr, pmp);
return S_OK;
}
#if DBG == 1
void CMSFPageTable::AddPageRef(void)
{
msfAssert((LONG) _cCurrentPageRef >= 0);
_cCurrentPageRef++;
if (_cCurrentPageRef > _cMaxPageRef)
{
_cMaxPageRef = _cCurrentPageRef;
}
}
void CMSFPageTable::ReleasePageRef(void)
{
_cCurrentPageRef--;
msfAssert((LONG) _cCurrentPageRef >= 0);
}
#endif