|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1996.
//
// File: page.cxx
//
// Contents: Paging code for MSF
//
// Classes: Defined in page.hxx
//
// Functions:
//
//----------------------------------------------------------------------------
#include "msfhead.cxx"
#include "mread.hxx"
//+---------------------------------------------------------------------
//
// Member: CMSFPage::Byteswap, public
//
// Synopsis: Byteswap the elments of the page
//
// Algorithm: Call the corresponding byteswap routine depending on the
// actual type of the Mutli-stream.
//
//----------------------------------------------------------------------
void CMSFPage::ByteSwap(void) { CPagedVector* pVect = GetVector(); if (pVect->GetParent()->GetHeader()->DiffByteOrder()) { switch (_sid) { case SIDDIR: ((CDirSect *)_ab)-> ByteSwap( ((CDirVector*)pVect)->GetSectorSize() ); break; case SIDFAT: case SIDMINIFAT: case SIDDIF: ((CFatSect *)_ab)-> ByteSwap( ((CFatVector*)pVect)->GetSectBlock() ); break; default: break; } } }
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::CMSFPageTable, public
//
// Synopsis: CMSFPageTable constructor.
//
// Arguments: [pmsParent] -- Pointer to multistream for this page table.
//
// Notes:
//
//----------------------------------------------------------------------------
CMSFPageTable::CMSFPageTable( CMStream *const pmsParent, const ULONG cMinPages, const ULONG cMaxPages) : _pmsParent(pmsParent), _cActivePages(0), _cPages(0), _pmpCurrent(NULL), _cbSector(pmsParent->GetSectorSize()), _cMinPages(cMinPages), _cMaxPages(cMaxPages), _cReferences(1) { }
//+---------------------------------------------------------------------------
//
// Member: CMSFPage::CMSFPage, public
//
// Synopsis: CMSFPage default constructor
//
//----------------------------------------------------------------------------
CMSFPage::CMSFPage(CMSFPage *pmp) { if (pmp == NULL) { SetChain(this, this); } else { SetChain(pmp->GetPrev(), pmp); GetPrev()->SetNext(this); GetNext()->SetPrev(this); }
SetSid(NOSTREAM); SetOffset(0); SetSect(ENDOFCHAIN); SetFlags(0); SetVector(NULL); _cReferences = 0; }
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::~CMSFPageTable, public
//
// Synopsis: CMSFPageTable destructor
//
//----------------------------------------------------------------------------
CMSFPageTable::~CMSFPageTable() { if (_pmpCurrent != NULL) { CMSFPage *pmp = _pmpCurrent; CMSFPage *pmpNext;
while (pmp != pmp->GetNext()) { pmpNext = pmp->GetNext(); #if DBG == 1
msfAssert(!pmp->IsInUse() && aMsg("Active page left at page table destruct time."));
#endif
delete pmp; pmp = pmpNext; } delete pmp; } }
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::Init, public
//
// Synopsis: Initialize a CMSFPageTable
//
// Arguments: [cPages] -- Number of pages to preallocate.
//
// Returns: Appropriate status code
//
// 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()); _pmpCurrent = pmp; } _cPages = _cMinPages; _cActivePages = 0;
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
//
//----------------------------------------------------------------------------
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."));
ULONG ulRet;
ILockBytes *pilb; ULARGE_INTEGER ul; ULISet32(ul, ConvertSectOffset( pmp->GetSect(), 0, pms->GetSectorShift()));
pilb = pms->GetILB();
pmp->ByteSwap(); // convert to disk format
// (if neccessary)
msfHChk(pilb->WriteAt( ul, (BYTE *)(pmp->GetData()), _cbSector, &ulRet)); pmp->ByteSwap(); // convert to back to machine format
// (if neccessary)
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
//
// 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 = _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_IERROR, "Got swap page %p\n",pmp));
msfAssert((pmp->GetVector() != NULL) && aMsg("FindSwapPage returned unowned page."));
msfDebugOut((DEB_IERROR, "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
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::FindPage( CPagedVector *ppv, SID sid, ULONG ulOffset, CMSFPage **ppmp) { SCODE sc; CMSFPage *pmp = _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); pmp->SetSect(ENDOFCHAIN);
*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
//
// Notes:
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::GetPage( CPagedVector *ppv, SID sid, ULONG ulOffset, CMSFPage **ppmp) { SCODE sc;
*ppmp = NULL; msfChk(FindPage(ppv, sid, ulOffset, ppmp));
(*ppmp)->AddRef();
if (sc != STG_S_FOUND) { ULONG ulRet; SECT sect;
msfChk(ppv->GetParent()->GetSect(sid, ulOffset, §)); (*ppmp)->SetSect(sect);
CMStream *pms = (*ppmp)->GetVector()->GetParent(); ULARGE_INTEGER ul; ULISet32(ul, ConvertSectOffset( (*ppmp)->GetSect(), 0, pms->GetSectorShift()));
msfAssert(pms->GetILB() != NULL && aMsg("NULL ILockBytes - missing SetAccess?"));
msfHChk(pms->GetILB()->ReadAt(ul, (BYTE *)((*ppmp)->GetData()), _cbSector, &ulRet)); (*ppmp)->ByteSwap(); }
Err: if (*ppmp != NULL) { (*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
//
//----------------------------------------------------------------------------
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
//
//----------------------------------------------------------------------------
SCODE CMSFPageTable::Flush(void) { SCODE sc = S_OK;
CMSFPage *pmp = _pmpCurrent;
//We use pmpLast in case FlushPage changes _pmpCurrent.
CMSFPage *pmpLast = _pmpCurrent;
do { if ((pmp->IsDirty()) && !(pmp->IsInUse())) { msfChk(FlushPage(pmp)); }
pmp = pmp->GetNext();
} while (pmp != pmpLast);
Err: return sc; }
//+---------------------------------------------------------------------------
//
// Member: CMSFPageTable::FreePages, public
//
// Synopsis: Free all the pages associated with a vector.
//
// Arguments: [ppv] -- Pointer to vector to free pages for.
//
//----------------------------------------------------------------------------
void CMSFPageTable::FreePages(CPagedVector *ppv) { CMSFPage *pmp = _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.
//
//----------------------------------------------------------------------------
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); _pmpCurrent = _pmpCurrent->GetNext();
if (!(dwFlags & FB_TOUCHED)) { return _pmpCurrent->GetPrev(); } } else { _pmpCurrent = _pmpCurrent->GetNext(); } #if DBG == 1
cpInUse++; msfAssert((cpInUse < 3 * _cPages) && aMsg("No swappable pages.")); #endif
} }
|