Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1147 lines
29 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: page.cxx
  7. //
  8. // Contents: Paging code for MSF
  9. //
  10. // Classes: Defined in page.hxx
  11. //
  12. // Functions:
  13. //
  14. // History: 20-Oct-92 PhilipLa Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "msfhead.cxx"
  18. #pragma hdrstop
  19. #include <mread.hxx>
  20. #include <filest.hxx>
  21. #define FLUSH_MULTIPLE
  22. //+---------------------------------------------------------------------------
  23. //
  24. // Member: CMSFPage::SetSect, public
  25. //
  26. // Synopsis: Sets the SECT for this page
  27. //
  28. // History: 20-Oct-92 PhilipLa Created
  29. //
  30. //----------------------------------------------------------------------------
  31. #ifdef SORTPAGETABLE
  32. inline void CMSFPage::SetSect(const SECT sect)
  33. {
  34. msfAssert(_pmpNext != NULL && _pmpPrev != NULL);
  35. msfAssert((_pmpPrev->_sect >= _pmpNext->_sect) || //Edge
  36. ((_sect >= _pmpPrev->_sect) && (_sect <= _pmpNext->_sect)));
  37. _sect = sect;
  38. }
  39. #endif
  40. //+---------------------------------------------------------------------------
  41. //
  42. // Member: CMSFPageTable::IsSorted, public
  43. //
  44. // Synopsis: Return TRUE if the specified page is in the right place
  45. // in the list.
  46. //
  47. // Arguments: [pmp] -- Page to check
  48. //
  49. // History: 13-Dec-95 PhilipLa Created
  50. //
  51. //----------------------------------------------------------------------------
  52. inline BOOL CMSFPageTable::IsSorted(CMSFPage *pmp)
  53. {
  54. //There are three cases:
  55. //1) Page is first in the list.
  56. //2) Page is last in the list.
  57. //3) Page is in the middle of the list.
  58. SECT sect = pmp->GetSect();
  59. CMSFPage *pmpStart = BP_TO_P(CMSFPage *, _pmpStart);
  60. CMSFPage *pmpNext = pmp->GetNext();
  61. if (pmp == pmpStart)
  62. {
  63. return (sect <= pmpNext->GetSect());
  64. }
  65. if (pmpNext == pmpStart)
  66. {
  67. return (sect >= pmp->GetPrev()->GetSect());
  68. }
  69. return ((sect <= pmpNext->GetSect()) &&
  70. (sect >= pmp->GetPrev()->GetSect()));
  71. }
  72. //+---------------------------------------------------------------------------
  73. //
  74. // Member: CMSFPageTable::SetSect, public
  75. //
  76. // Synopsis: Set the sector stamp on a page, and sort the list if
  77. // necessary.
  78. //
  79. // Arguments: [pmp] -- Pointer to page to stamp
  80. // [sect] -- SECT to stamp it with
  81. //
  82. // Returns: void
  83. //
  84. // History: 12-Dec-95 PhilipLa Created
  85. //
  86. //----------------------------------------------------------------------------
  87. void CMSFPageTable::SetSect(CMSFPage *pmp, SECT sect)
  88. {
  89. msfDebugOut((DEB_ITRACE, "In CMSFPageTable::SetSect:%p(%p, %lX)\n",
  90. this,
  91. pmp,
  92. sect));
  93. pmp->SetSect(sect);
  94. //Resort list if necessary.
  95. if (!IsSorted(pmp))
  96. {
  97. CMSFPage *pmpTemp, *pmpStart;
  98. pmpStart = BP_TO_P(CMSFPage *, _pmpStart);
  99. if (pmpStart == pmp)
  100. {
  101. pmpStart = pmp->GetNext();
  102. _pmpStart = P_TO_BP(CBasedMSFPagePtr , pmpStart);
  103. }
  104. pmp->Remove();
  105. pmpTemp = pmpStart;
  106. while (sect > pmpTemp->GetSect())
  107. {
  108. pmpTemp = pmpTemp->GetNext();
  109. if (pmpTemp == pmpStart)
  110. {
  111. break;
  112. }
  113. }
  114. //Insert node before pmpTemp.
  115. pmpTemp->GetPrev()->SetNext(pmp);
  116. pmp->SetChain(pmpTemp->GetPrev(), pmpTemp);
  117. pmpTemp->SetPrev(pmp);
  118. if (sect <= pmpStart->GetSect())
  119. {
  120. _pmpStart = P_TO_BP(CBasedMSFPagePtr, pmp);
  121. }
  122. }
  123. msfAssert(IsSorted(pmp));
  124. msfDebugOut((DEB_ITRACE, "Out CMSFPageTable::SetSect\n"));
  125. }
  126. //+---------------------------------------------------------------------------
  127. //
  128. // Member: CMSFPageTable::CMSFPageTable, public
  129. //
  130. // Synopsis: CMSFPageTable constructor.
  131. //
  132. // Arguments: [pmsParent] -- Pointer to multistream for this page table.
  133. //
  134. // History: 22-Oct-92 PhilipLa Created
  135. //
  136. // Notes:
  137. //
  138. //----------------------------------------------------------------------------
  139. CMSFPageTable::CMSFPageTable(
  140. CMStream *const pmsParent,
  141. const ULONG cMinPages,
  142. const ULONG cMaxPages)
  143. : _cbSector(pmsParent->GetSectorSize()),
  144. _cMinPages(cMinPages), _cMaxPages(cMaxPages)
  145. {
  146. _pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
  147. _cActivePages = 0;
  148. _cPages = 0;
  149. _pmpCurrent = NULL;
  150. #ifdef SORTPAGETABLE
  151. _pmpStart = NULL;
  152. #endif
  153. _cReferences = 1;
  154. #if DBG == 1
  155. _cCurrentPageRef = 0;
  156. _cMaxPageRef = 0;
  157. #endif
  158. }
  159. //+---------------------------------------------------------------------------
  160. //
  161. // Member: CMSFPage::CMSFPage, public
  162. //
  163. // Synopsis: CMSFPage default constructor
  164. //
  165. // History: 20-Oct-92 PhilipLa Created
  166. //
  167. //----------------------------------------------------------------------------
  168. #if DBG == 1
  169. CMSFPage::CMSFPage(CMSFPage *pmp, CMSFPageTable *pmpt)
  170. #else
  171. CMSFPage::CMSFPage(CMSFPage *pmp)
  172. #endif
  173. {
  174. if (pmp == NULL)
  175. {
  176. SetChain(this, this);
  177. }
  178. else
  179. {
  180. SetChain(pmp->GetPrev(), pmp);
  181. GetPrev()->SetNext(this);
  182. GetNext()->SetPrev(this);
  183. }
  184. #if DBG == 1
  185. _pmpt = P_TO_BP(CBasedMSFPageTablePtr, pmpt);
  186. #endif
  187. SetSid(NOSTREAM);
  188. SetOffset(0);
  189. // SetSect(ENDOFCHAIN);
  190. //SetSect() contains assertions to verify sortedness of the list,
  191. //which we don't want here.
  192. _sect = ENDOFCHAIN;
  193. SetFlags(0);
  194. SetVector(NULL);
  195. _cReferences = 0;
  196. }
  197. //+---------------------------------------------------------------------------
  198. //
  199. // Member: CMSFPageTable::GetNewPage, private
  200. //
  201. // Synopsis: Insert a new page into the list and return a pointer to it.
  202. //
  203. // Arguments: None.
  204. //
  205. // Returns: Pointer to new page. Null if there was an allocation error.
  206. //
  207. // History: 22-Oct-92 PhilipLa Created
  208. //
  209. // Notes:
  210. //
  211. //----------------------------------------------------------------------------
  212. inline CMSFPage * CMSFPageTable::GetNewPage(void)
  213. {
  214. #ifndef SORTPAGETABLE
  215. #if DBG == 1
  216. return new (_pmsParent->GetMalloc(), (size_t)_cbSector)
  217. CMSFPage(BP_TO_P(CMSFPage *, _pmpCurrent), this);
  218. #else
  219. return new (_pmsParent->GetMalloc(), (size_t)_cbSector)
  220. CMSFPage(BP_TO_P(CMSFPage *, _pmpCurrent));
  221. #endif
  222. #else
  223. #if DBG == 1
  224. return new (_pmsParent->GetMalloc(), (size_t)_cbSector)
  225. CMSFPage(BP_TO_P(CMSFPage *, _pmpStart), this);
  226. #else
  227. return new (_pmsParent->GetMalloc(), (size_t)_cbSector)
  228. CMSFPage(BP_TO_P(CMSFPage *, _pmpStart));
  229. #endif
  230. #endif //SORTPAGETABLE
  231. }
  232. //+---------------------------------------------------------------------------
  233. //
  234. // Member: CMSFPageTable::~CMSFPageTable, public
  235. //
  236. // Synopsis: CMSFPageTable destructor
  237. //
  238. // History: 26-Oct-92 PhilipLa Created
  239. // 21-Jul-95 SusiA Modified to delete the object without
  240. // obtaining the mutex. Calling functions
  241. // should have locked the mutex first.
  242. //
  243. //----------------------------------------------------------------------------
  244. CMSFPageTable::~CMSFPageTable()
  245. {
  246. if (_pmpCurrent != NULL)
  247. {
  248. CMSFPage *pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
  249. CMSFPage *pmpNext;
  250. while (pmp != pmp->GetNext())
  251. {
  252. pmpNext = pmp->GetNext();
  253. msfAssert(pmpNext != NULL &&
  254. aMsg("NULL found in page table circular list."));
  255. #if DBG == 1
  256. msfAssert(!pmp->IsInUse() &&
  257. aMsg("Active page left at page table destruct time."));
  258. if (!_pmsParent->IsScratch())
  259. {
  260. //Dirty paged can be thrown away if we are unconverted or
  261. // in a commit.
  262. if ((!_pmsParent->IsUnconverted()) &&
  263. (_pmsParent->GetParentSize() == 0))
  264. {
  265. msfAssert(!pmp->IsDirty() &&
  266. aMsg("Dirty page left at page table destruct time."));
  267. }
  268. }
  269. #endif
  270. pmp->~CMSFPage();
  271. pmp->deleteNoMutex(pmp);
  272. pmp = pmpNext;
  273. }
  274. pmp->~CMSFPage();
  275. pmp->deleteNoMutex(pmp);
  276. }
  277. #if DBG == 1
  278. msfDebugOut((DEB_ITRACE,
  279. "Page Table Max Page Count for %s: %lu\n",
  280. (_pmsParent->IsScratch()) ? "Scratch" : "Base",
  281. _cMaxPageRef));
  282. #endif
  283. }
  284. //+---------------------------------------------------------------------------
  285. //
  286. // Member: CMSFPageTable::Init, public
  287. //
  288. // Synopsis: Initialize a CMSFPageTable
  289. //
  290. // Arguments: [cPages] -- Number of pages to preallocate.
  291. //
  292. // Returns: Appropriate status code
  293. //
  294. // History: 22-Oct-92 PhilipLa Created
  295. //
  296. // Notes:
  297. //
  298. //----------------------------------------------------------------------------
  299. SCODE CMSFPageTable::Init(void)
  300. {
  301. SCODE sc = S_OK;
  302. msfDebugOut((DEB_ITRACE, "In CMSFPageTable::Init:%p()\n", this));
  303. for (ULONG i = 0; i < _cMinPages; i++)
  304. {
  305. CMSFPage *pmp;
  306. msfMem(pmp = GetNewPage());
  307. #ifndef SORTPAGETABLE
  308. _pmpCurrent = P_TO_BP(CBasedMSFPagePtr, pmp);
  309. #else
  310. _pmpStart = P_TO_BP(CBasedMSFPagePtr, pmp);
  311. #endif
  312. }
  313. _cPages = _cMinPages;
  314. _cActivePages = 0;
  315. #ifdef SORTPAGETABLE
  316. _pmpCurrent = _pmpStart;
  317. #endif
  318. msfDebugOut((DEB_ITRACE, "Out CMSFPageTable::Init\n"));
  319. Err:
  320. return sc;
  321. }
  322. //+---------------------------------------------------------------------------
  323. //
  324. // Member: CMSFPageTable::FlushPage, public
  325. //
  326. // Synopsis: Flush a page
  327. //
  328. // Arguments: [pmp] -- Pointer to page to flush
  329. //
  330. // Returns: Appropriate status code
  331. //
  332. // History: 09-Nov-92 PhilipLa Created
  333. //
  334. //----------------------------------------------------------------------------
  335. SCODE CMSFPageTable::FlushPage(CMSFPage *pmp)
  336. {
  337. SCODE sc = S_OK;
  338. pmp->AddRef();
  339. CMStream *pms;
  340. pms = pmp->GetVector()->GetParent();
  341. //Flush the page, reset the dirty bit.
  342. msfAssert((pmp->GetSect() != ENDOFCHAIN) &&
  343. aMsg("Page location not set - don't know where to flush to."));
  344. msfAssert (pms != NULL);
  345. ULONG ulRet;
  346. ILockBytes *pilb;
  347. #if DBG == 1
  348. if ((pmp->GetSid() == SIDFAT) && (pms->IsInCOW()))
  349. {
  350. msfDebugOut((DEB_ITRACE, "** Fat sect %lu written to %lX\n",
  351. pmp->GetOffset(), pmp->GetSect()));
  352. }
  353. if ((pmp->GetSid() == SIDDIF) && (pms->IsInCOW()))
  354. {
  355. msfDebugOut((DEB_ITRACE, "** DIF sect %lu written to %lX\n",
  356. pmp->GetOffset(), pmp->GetSect()));
  357. }
  358. #endif
  359. ULARGE_INTEGER ul;
  360. #ifdef LARGE_DOCFILE
  361. ul.QuadPart = ConvertSectOffset(
  362. pmp->GetSect(),
  363. 0,
  364. pms->GetSectorShift());
  365. #else
  366. ULISet32(ul, ConvertSectOffset(
  367. pmp->GetSect(),
  368. 0,
  369. pms->GetSectorShift()));
  370. #endif
  371. pilb = pms->GetILB();
  372. msfAssert(!pms->IsUnconverted() &&
  373. aMsg("Tried to flush page to unconverted base."));
  374. sc = GetScode(pilb->WriteAt(ul,
  375. (BYTE *)(pmp->GetData()),
  376. _cbSector,
  377. &ulRet));
  378. if (sc == E_PENDING)
  379. {
  380. sc = STG_E_PENDINGCONTROL;
  381. }
  382. msfChk(sc);
  383. pmp->ResetDirty();
  384. Err:
  385. pmp->Release();
  386. return sc;
  387. }
  388. //+---------------------------------------------------------------------------
  389. //
  390. // Member: CMSFPageTable::GetFreePage, public
  391. //
  392. // Synopsis: Return a pointer to a free page.
  393. //
  394. // Arguments: [ppmp] -- Pointer to storage for return pointer
  395. //
  396. // Returns: Appropriate status code
  397. //
  398. // History: 22-Oct-92 PhilipLa Created
  399. //
  400. // Notes:
  401. //
  402. //----------------------------------------------------------------------------
  403. SCODE CMSFPageTable::GetFreePage(CMSFPage **ppmp)
  404. {
  405. SCODE sc = S_OK;
  406. CMSFPage *pmp;
  407. if (_cPages > _cActivePages)
  408. {
  409. //We have some unused page already allocated. Find and return it.
  410. pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
  411. do
  412. {
  413. pmp = pmp->GetNext();
  414. }
  415. while ((pmp != _pmpCurrent) && (pmp->GetSid() != NOSTREAM));
  416. msfAssert((pmp->GetSid() == NOSTREAM) &&
  417. aMsg("Expected empty page, none found."));
  418. *ppmp = pmp;
  419. _cActivePages++;
  420. }
  421. else if (_cPages == _cMaxPages)
  422. {
  423. msfMem(pmp = FindSwapPage());
  424. msfDebugOut((DEB_ITRACE, "Got swap page %p\n",pmp));
  425. msfAssert((pmp->GetVector() != NULL) &&
  426. aMsg("FindSwapPage returned unowned page."));
  427. msfDebugOut((DEB_ITRACE, "Freeing page %lu from vector %p\n",
  428. pmp->GetOffset(), pmp->GetVector()));
  429. if (pmp->IsDirty())
  430. {
  431. msfChk(FlushPage(pmp));
  432. msfAssert(!pmp->IsDirty() &&
  433. aMsg("Page remained dirty after flush call"));
  434. }
  435. pmp->GetVector()->FreeTable(pmp->GetOffset());
  436. #if DBG == 1
  437. pmp->SetVector(NULL);
  438. #endif
  439. *ppmp = pmp;
  440. }
  441. else
  442. {
  443. //Create a new page and return it.
  444. pmp = GetNewPage();
  445. if (pmp != NULL)
  446. {
  447. *ppmp = pmp;
  448. _cActivePages++;
  449. _cPages++;
  450. }
  451. else
  452. {
  453. msfMem(pmp = FindSwapPage());
  454. if (pmp->IsDirty())
  455. {
  456. msfChk(FlushPage(pmp));
  457. msfAssert(!pmp->IsDirty() &&
  458. aMsg("Page remained dirty after flush call"));
  459. }
  460. pmp->GetVector()->FreeTable(pmp->GetOffset());
  461. #if DBG == 1
  462. pmp->SetVector(NULL);
  463. #endif
  464. *ppmp = pmp;
  465. }
  466. }
  467. Err:
  468. return sc;
  469. }
  470. //+---------------------------------------------------------------------------
  471. //
  472. // Member: CMSFPageTable::FindPage, public
  473. //
  474. // Synopsis: Find and return a given page
  475. //
  476. // Arguments: [ppv] -- Pointer to vector of page to return
  477. // [sid] -- SID of page to return
  478. // [ulOffset] -- Offset of page to return
  479. // [ppmp] -- Location to return pointer
  480. //
  481. // Returns: Appropriate status code
  482. //
  483. // History: 22-Oct-92 PhilipLa Created
  484. //
  485. // Notes:
  486. //
  487. //----------------------------------------------------------------------------
  488. SCODE CMSFPageTable::FindPage(
  489. CPagedVector *ppv,
  490. SID sid,
  491. ULONG ulOffset,
  492. CMSFPage **ppmp)
  493. {
  494. SCODE sc;
  495. CMSFPage *pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
  496. do
  497. {
  498. if ((pmp->GetVector() == ppv) && (pmp->GetOffset() == ulOffset))
  499. {
  500. //Bingo!
  501. *ppmp = pmp;
  502. return STG_S_FOUND;
  503. }
  504. pmp = pmp->GetNext();
  505. }
  506. while (pmp != _pmpCurrent);
  507. //The page isn't currently in memory. Get a free page and
  508. //bring it into memory.
  509. msfChk(GetFreePage(&pmp));
  510. msfAssert((pmp->GetVector() == NULL) &&
  511. aMsg("Attempting to reassign owned page."));
  512. pmp->SetVector(ppv);
  513. pmp->SetSid(sid);
  514. pmp->SetOffset(ulOffset);
  515. #ifdef SORTPAGETABLE
  516. SetSect(pmp, ENDOFCHAIN);
  517. #else
  518. pmp->SetSect(ENDOFCHAIN);
  519. #endif
  520. *ppmp = pmp;
  521. Err:
  522. return sc;
  523. }
  524. //+---------------------------------------------------------------------------
  525. //
  526. // Member: CMSFPageTable::GetPage, public
  527. //
  528. // Synopsis: Find and return a given page
  529. //
  530. // Arguments: [sid] -- SID of page to return
  531. // [ulOffset] -- Offset of page to return
  532. // [ppmp] -- Location to return pointer
  533. //
  534. // Returns: Appropriate status code
  535. //
  536. // History: 22-Oct-92 PhilipLa Created
  537. //
  538. // Notes:
  539. //
  540. //----------------------------------------------------------------------------
  541. SCODE CMSFPageTable::GetPage(
  542. CPagedVector *ppv,
  543. SID sid,
  544. ULONG ulOffset,
  545. SECT sectKnown,
  546. CMSFPage **ppmp)
  547. {
  548. SCODE sc;
  549. *ppmp = NULL;
  550. msfChk(FindPage(ppv, sid, ulOffset, ppmp));
  551. (*ppmp)->AddRef();
  552. if (sc != STG_S_FOUND)
  553. {
  554. ULONG ulRet;
  555. SECT sect;
  556. if (sectKnown != ENDOFCHAIN)
  557. {
  558. sect = sectKnown;
  559. }
  560. else
  561. {
  562. msfChk(ppv->GetParent()->GetSect(sid, ulOffset, &sect));
  563. }
  564. #ifdef SORTPAGETABLE
  565. SetSect(*ppmp, sect);
  566. #else
  567. (*ppmp)->SetSect(sect);
  568. #endif
  569. CMStream *pms = (*ppmp)->GetVector()->GetParent();
  570. #if DBG == 1
  571. if ((sid == SIDFAT) && (pms->IsInCOW()))
  572. {
  573. msfDebugOut((DEB_ITRACE, "Fat sect %lu read from %lX\n",
  574. ulOffset, sect));
  575. }
  576. if ((sid == SIDDIF) && (pms->IsInCOW()))
  577. {
  578. msfDebugOut((DEB_ITRACE, "DIF sect %lu read from %lX\n",
  579. ulOffset, sect));
  580. }
  581. #endif
  582. ULARGE_INTEGER ul;
  583. #ifdef LARGE_DOCFILE
  584. ul.QuadPart = ConvertSectOffset(
  585. (*ppmp)->GetSect(),
  586. 0,
  587. pms->GetSectorShift());
  588. #else
  589. ULISet32(ul, ConvertSectOffset(
  590. (*ppmp)->GetSect(),
  591. 0,
  592. pms->GetSectorShift()));
  593. #endif
  594. msfAssert(pms->GetILB() != NULL &&
  595. aMsg("NULL ILockBytes - missing SetAccess?"));
  596. sc = GetScode(pms->GetILB()->ReadAt(ul,
  597. (BYTE *)((*ppmp)->GetData()),
  598. _cbSector,
  599. &ulRet));
  600. if (sc == E_PENDING)
  601. {
  602. sc = STG_E_PENDINGCONTROL;
  603. }
  604. msfChk(sc);
  605. if (ulRet != _cbSector)
  606. {
  607. // 09/23/93 - No error, but insufficient bytes read
  608. sc = STG_E_READFAULT;
  609. }
  610. }
  611. Err:
  612. if (*ppmp != NULL)
  613. {
  614. if (FAILED(sc))
  615. {
  616. // 09/19/93 - Reset page so that we don't accidentally use it
  617. (*ppmp)->SetSid(NOSTREAM);
  618. (*ppmp)->SetOffset(0);
  619. #ifdef SORTPAGETABLE
  620. SetSect(*ppmp, ENDOFCHAIN);
  621. #else
  622. (*ppmp)->SetSect(ENDOFCHAIN);
  623. #endif
  624. (*ppmp)->SetFlags(0);
  625. (*ppmp)->SetVector(NULL);
  626. _cActivePages--;
  627. }
  628. (*ppmp)->Release();
  629. }
  630. return sc;
  631. }
  632. //+---------------------------------------------------------------------------
  633. //
  634. // Member: CMSFPageTable::ReleasePage, public
  635. //
  636. // Synopsis: Release a given page
  637. //
  638. // Arguments: [sid] -- SID of page to release
  639. // [ulOffset] -- Offset of page to release
  640. //
  641. // History: 28-Oct-92 PhilipLa Created
  642. //
  643. //----------------------------------------------------------------------------
  644. void CMSFPageTable::ReleasePage(CPagedVector *ppv,
  645. SID sid, ULONG ulOffset)
  646. {
  647. SCODE sc;
  648. CMSFPage *pmp;
  649. sc = FindPage(ppv, sid, ulOffset, &pmp);
  650. if (SUCCEEDED(sc))
  651. {
  652. pmp->Release();
  653. }
  654. }
  655. //+---------------------------------------------------------------------------
  656. //
  657. // Member: CMSFPageTable::Flush, public
  658. //
  659. // Synopsis: Flush dirty pages to disk
  660. //
  661. // Returns: Appropriate status code
  662. //
  663. // History: 02-Nov-92 PhilipLa Created
  664. //
  665. //----------------------------------------------------------------------------
  666. SCODE CMSFPageTable::Flush(void)
  667. {
  668. #ifndef SORTPAGETABLE
  669. SCODE sc = S_OK;
  670. CMSFPage *pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
  671. //We use pmpLast in case FlushPage changes _pmpCurrent.
  672. CMSFPage *pmpLast = pmp;
  673. do
  674. {
  675. if ((pmp->IsDirty()) && !(pmp->IsInUse()) &&
  676. !(pmp->GetVector()->GetParent()->IsScratch()))
  677. {
  678. msfChk(FlushPage(pmp));
  679. }
  680. pmp = pmp->GetNext();
  681. }
  682. while (pmp != pmpLast);
  683. Err:
  684. return sc;
  685. #else
  686. SCODE sc = S_OK;
  687. msfDebugOut((DEB_ITRACE, "In CMSFPageTable::Flush()\n"));
  688. CMSFPage *pmp;
  689. CMSFPage *pmpStart;
  690. BYTE *pb = NULL;
  691. ULONG ulBufferSize = 0;
  692. pmpStart = BP_TO_P(CMSFPage *, _pmpStart);
  693. pmp = pmpStart;
  694. do
  695. {
  696. CMSFPage *pmpFirst;
  697. CMSFPage *pmpLast;
  698. //Find first page that needs to be flushed.
  699. while (!pmp->IsFlushable())
  700. {
  701. pmp = pmp->GetNext();
  702. if (pmp == pmpStart)
  703. break;
  704. }
  705. //If we haven't hit the end of the list, then find a contiguous
  706. // range of pages to flush.
  707. if (pmp->IsFlushable())
  708. {
  709. pmpFirst = pmp;
  710. //Store pointer to last page in range in pmpLast.
  711. while (pmp->IsFlushable())
  712. {
  713. pmpLast = pmp;
  714. pmp = pmp->GetNext();
  715. if (pmp->GetSect() != pmpLast->GetSect() + 1)
  716. {
  717. break;
  718. }
  719. }
  720. //At this point, we can flush everything from pmpFirst to
  721. // pmpLast, and they are all contiguous. pmp points to the
  722. // next sector after the current range.
  723. if (pmpFirst == pmpLast)
  724. {
  725. msfDebugOut((DEB_ITRACE,
  726. "Flushing page to %lx\n",
  727. pmpFirst->GetSect()));
  728. //Only one page: Call FlushPage.
  729. msfChk(FlushPage(pmpFirst));
  730. }
  731. else
  732. {
  733. ULONG ulWriteSize;
  734. ULONG cSect;
  735. CMSFPage *pmpTemp;
  736. ULONG i;
  737. msfDebugOut((DEB_ITRACE,
  738. "Flushing pages from %lx to %lx\n",
  739. pmpFirst->GetSect(),
  740. pmpLast->GetSect()));
  741. cSect = pmpLast->GetSect() - pmpFirst->GetSect() + 1;
  742. ulWriteSize = cSect * _cbSector;
  743. if (ulWriteSize > ulBufferSize)
  744. {
  745. delete pb;
  746. pb = new BYTE[ulWriteSize];
  747. ulBufferSize = ulWriteSize;
  748. }
  749. pmpTemp = pmpFirst;
  750. if (pb == NULL)
  751. {
  752. ulBufferSize = 0;
  753. //Low memory case - write out pages one at a time
  754. for (i = 0; i < cSect; i++)
  755. {
  756. msfChk(FlushPage(pmpTemp));
  757. pmpTemp = pmpTemp->GetNext();
  758. }
  759. }
  760. else
  761. {
  762. for (i = 0; i < cSect; i++)
  763. {
  764. memcpy(pb + (i * _cbSector),
  765. pmpTemp->GetData(),
  766. _cbSector);
  767. pmpTemp = pmpTemp->GetNext();
  768. }
  769. //The buffer is loaded up - now write it out.
  770. ULARGE_INTEGER ul;
  771. ULONG cbWritten;
  772. ULONG cbTotal = 0;
  773. BYTE *pbCurrent = pb;
  774. #ifdef LARGE_DOCFILE
  775. ul.QuadPart = ConvertSectOffset(pmpFirst->GetSect(),
  776. 0,
  777. _pmsParent->GetSectorShift());
  778. #else
  779. ULISet32(ul, ConvertSectOffset(pmpFirst->GetSect(),
  780. 0,
  781. _pmsParent->GetSectorShift()));
  782. #endif
  783. while (cbTotal < ulWriteSize)
  784. {
  785. sc = _pmsParent->GetILB()->WriteAt(ul,
  786. pbCurrent,
  787. ulWriteSize - cbTotal,
  788. &cbWritten);
  789. if (sc == E_PENDING)
  790. {
  791. sc = STG_E_PENDINGCONTROL;
  792. }
  793. msfChk(sc);
  794. if (cbWritten == 0)
  795. {
  796. msfErr(Err, STG_E_WRITEFAULT);
  797. }
  798. cbTotal += cbWritten;
  799. pbCurrent += cbWritten;
  800. ul.QuadPart += cbWritten;
  801. }
  802. //Mark all the pages as clean.
  803. pmpTemp = pmpFirst;
  804. for (i = 0; i < cSect; i++)
  805. {
  806. pmpTemp->ResetDirty();
  807. pmpTemp = pmpTemp->GetNext();
  808. }
  809. }
  810. }
  811. }
  812. else
  813. {
  814. //We've hit the end of the list, do nothing.
  815. }
  816. }
  817. while (pmp != pmpStart);
  818. msfDebugOut((DEB_ITRACE, "Out CMSFPageTable::Flush() => %lX\n", sc));
  819. Err:
  820. if (pb != NULL)
  821. {
  822. delete pb;
  823. }
  824. return sc;
  825. #endif //SORTPAGETABLE
  826. }
  827. //+---------------------------------------------------------------------------
  828. //
  829. // Member: CMSFPageTable::FreePages, public
  830. //
  831. // Synopsis: Free all the pages associated with a vector.
  832. //
  833. // Arguments: [ppv] -- Pointer to vector to free pages for.
  834. //
  835. // History: 09-Nov-92 PhilipLa Created
  836. //
  837. //----------------------------------------------------------------------------
  838. void CMSFPageTable::FreePages(CPagedVector *ppv)
  839. {
  840. CMSFPage *pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
  841. do
  842. {
  843. if (pmp->GetVector() == ppv)
  844. {
  845. pmp->SetSid(NOSTREAM);
  846. pmp->SetVector(NULL);
  847. pmp->ResetDirty();
  848. _cActivePages--;
  849. }
  850. pmp = pmp->GetNext();
  851. }
  852. while (pmp != _pmpCurrent);
  853. }
  854. //+---------------------------------------------------------------------------
  855. //
  856. // Member: CMSFPageTable::FindSwapPage, private
  857. //
  858. // Synopsis: Find a page to swap out.
  859. //
  860. // Arguments: None.
  861. //
  862. // Returns: Pointer to page to swap out.
  863. //
  864. // History: 22-Oct-92 PhilipLa Created
  865. //
  866. //----------------------------------------------------------------------------
  867. CMSFPage * CMSFPageTable::FindSwapPage(void)
  868. {
  869. #if DBG == 1
  870. ULONG cpInUse = 0;
  871. #endif
  872. while (TRUE)
  873. {
  874. if (!_pmpCurrent->IsInUse())
  875. {
  876. DWORD dwFlags;
  877. dwFlags = _pmpCurrent->GetFlags();
  878. _pmpCurrent->SetFlags(dwFlags & ~FB_TOUCHED);
  879. CMSFPage *pmpTemp = _pmpCurrent->GetNext();
  880. _pmpCurrent = P_TO_BP(CBasedMSFPagePtr, pmpTemp);
  881. if (!(dwFlags & FB_TOUCHED))
  882. {
  883. return _pmpCurrent->GetPrev();
  884. }
  885. }
  886. else
  887. {
  888. CMSFPage *pmpTemp = _pmpCurrent->GetNext();
  889. _pmpCurrent = P_TO_BP(CBasedMSFPagePtr, pmpTemp);
  890. }
  891. #if DBG == 1
  892. cpInUse++;
  893. msfAssert((cpInUse < 3 * _cPages) &&
  894. aMsg("No swappable pages."));
  895. #endif
  896. }
  897. }
  898. //+---------------------------------------------------------------------------
  899. //
  900. // Member: CMSFPageTable::CopyPage, public
  901. //
  902. // Synopsis: Copy a page in memory, returning NULL if there is
  903. // insufficient space for a new page without swapping.
  904. //
  905. // Arguments: [ppv] -- Pointer to vector that will own the copy.
  906. // [pmpOld] -- Pointer to page to copy.
  907. // [ppmp] -- Pointer to return value
  908. //
  909. // Returns: Appropriate status code
  910. //
  911. // Modifies:
  912. //
  913. // History: 04-Dec-92 PhilipLa Created
  914. //
  915. // Notes:
  916. //
  917. //----------------------------------------------------------------------------
  918. SCODE CMSFPageTable::CopyPage(
  919. CPagedVector *ppv,
  920. CMSFPage *pmpOld,
  921. CBasedMSFPagePtr *ppmp)
  922. {
  923. CMSFPage *pmp;
  924. pmp = NULL;
  925. if (pmpOld != NULL)
  926. {
  927. msfAssert(!pmpOld->IsDirty() &&
  928. aMsg("Copying dirty page."));
  929. if (_cPages > _cActivePages)
  930. {
  931. //We have some unused page already allocated. Find and return it.
  932. pmp = BP_TO_P(CMSFPage *, _pmpCurrent);
  933. do
  934. {
  935. pmp = pmp->GetNext();
  936. }
  937. while ((pmp != _pmpCurrent) && (pmp->GetSid() != NOSTREAM));
  938. msfAssert((pmp->GetSid() == NOSTREAM) &&
  939. aMsg("Expected empty page, none found."));
  940. _cActivePages++;
  941. }
  942. else if (_cPages < _cMaxPages)
  943. {
  944. //Create a new page and return it.
  945. pmp = GetNewPage();
  946. if (pmp != NULL)
  947. {
  948. _cActivePages++;
  949. _cPages++;
  950. }
  951. }
  952. if (pmp != NULL)
  953. {
  954. msfAssert((pmp->GetVector() == NULL) &&
  955. aMsg("Attempting to reassign owned page."));
  956. pmp->SetVector(ppv);
  957. pmp->SetSid(pmpOld->GetSid());
  958. pmp->SetOffset(pmpOld->GetOffset());
  959. #ifdef SORTPAGETABLE
  960. SetSect(pmp, pmpOld->GetSect());
  961. #else
  962. pmp->SetSect(pmpOld->GetSect());
  963. #endif
  964. memcpy(pmp->GetData(), pmpOld->GetData(), (USHORT)_cbSector);
  965. }
  966. }
  967. *ppmp = P_TO_BP(CBasedMSFPagePtr, pmp);
  968. return S_OK;
  969. }
  970. #if DBG == 1
  971. void CMSFPageTable::AddPageRef(void)
  972. {
  973. msfAssert((LONG) _cCurrentPageRef >= 0);
  974. _cCurrentPageRef++;
  975. if (_cCurrentPageRef > _cMaxPageRef)
  976. {
  977. _cMaxPageRef = _cCurrentPageRef;
  978. }
  979. }
  980. void CMSFPageTable::ReleasePageRef(void)
  981. {
  982. _cCurrentPageRef--;
  983. msfAssert((LONG) _cCurrentPageRef >= 0);
  984. }
  985. #endif