|
|
//+---------------------------------------------------------------------------
//
// 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, §)); } #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
|