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.

670 lines
17 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: vect.cxx
  7. //
  8. // Contents: Vector common code.
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 27-Oct-92 PhilipLa Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include "msfhead.cxx"
  18. #pragma hdrstop
  19. #include <msffunc.hxx>
  20. #include <vect.hxx>
  21. #include <ole.hxx>
  22. #include <entry.hxx>
  23. #include <smalloc.hxx>
  24. inline CVectBits * CPagedVector::GetNewVectBits(ULONG ulSize)
  25. {
  26. msfAssert(ulSize > 0);
  27. CVectBits *pfb = NULL;
  28. if (ulSize <= (_HEAP_MAXREQ / sizeof(CVectBits)))
  29. {
  30. pfb = (CVectBits *) _pmsParent->GetMalloc()->Alloc(ulSize *
  31. sizeof(CVectBits));
  32. if (pfb)
  33. {
  34. memset(pfb, 0, (ulSize * sizeof(CVectBits)));
  35. }
  36. }
  37. return pfb;
  38. }
  39. inline CBasedMSFPagePtr* VECT_CLASS
  40. CPagedVector::GetNewPageArray(ULONG ulSize)
  41. {
  42. msfAssert(ulSize > 0);
  43. if (ulSize > (_HEAP_MAXREQ / sizeof(CMSFPage *)))
  44. {
  45. return NULL;
  46. }
  47. return (CBasedMSFPagePtr *)
  48. _pmsParent->GetMalloc()->Alloc(ulSize * sizeof(CMSFPage *));
  49. }
  50. //+-------------------------------------------------------------------------
  51. //
  52. // Method: CPagedVector::Init, public
  53. //
  54. // Synopsis: CPagedVector initialization function
  55. //
  56. // Arguments: [ulSize] -- size of vector
  57. // [uFatEntries] -- number of entries in each table
  58. //
  59. // Algorithm: Allocate an array of pointer of size ulSize
  60. // For each cell in the array, allocate a CFatSect
  61. //
  62. // History: 27-Dec-91 PhilipLa Created.
  63. //
  64. // Notes:
  65. //
  66. //--------------------------------------------------------------------------
  67. SCODE VECT_CLASS CPagedVector::Init(CMStream *pmsParent,
  68. ULONG ulSize)
  69. {
  70. msfDebugOut((DEB_ITRACE,"In CPagedVector::CPagedVector(%lu)\n",ulSize));
  71. SCODE sc = S_OK;
  72. _pmsParent = P_TO_BP(CBasedMStreamPtr, pmsParent);
  73. CMSFPageTable *pmptTemp = _pmsParent->GetPageTable();
  74. _pmpt = P_TO_BP(CBasedMSFPageTablePtr, pmptTemp);
  75. msfAssert(_pmpt != NULL);
  76. ULONG i;
  77. // We don't bother allocating more than necessary here
  78. _ulAllocSize = _ulSize = ulSize;
  79. if (_ulSize > 0)
  80. {
  81. CBasedMSFPagePtr *ampTemp;
  82. msfMem(ampTemp = GetNewPageArray(ulSize));
  83. for (i = 0; i < _ulSize; i++)
  84. {
  85. ampTemp[i] = NULL;
  86. }
  87. _amp = P_TO_BP(CBasedMSFPagePtrPtr, ampTemp);
  88. CVectBits *avbTemp;
  89. msfMem(avbTemp = GetNewVectBits(ulSize));
  90. _avb = P_TO_BP(CBasedVectBitsPtr, avbTemp);
  91. }
  92. msfDebugOut((DEB_ITRACE,"Out CPagedVector::CPagedVector()\n"));
  93. return S_OK;
  94. Err:
  95. //In the error case, discard whatever vectors we were able to allocate
  96. // and return S_OK.
  97. _pmsParent->GetMalloc()->Free(BP_TO_P(CBasedMSFPagePtr *, _amp));
  98. _amp = NULL;
  99. _pmsParent->GetMalloc()->Free(BP_TO_P(CVectBits *,_avb));
  100. _avb = NULL;
  101. return S_OK;
  102. }
  103. //+-------------------------------------------------------------------------
  104. //
  105. // Method: CPagedVector::~CPagedVector, public
  106. //
  107. // Synopsis: CPagedVector constructor
  108. //
  109. // Algorithm: Delete the pointer array.
  110. //
  111. // History: 27-Oct-92 PhilipLa Created.
  112. // 20-Jul-95 SusiA Changed Free to FreeNoMutex
  113. //
  114. // Notes: This function freed the SmAllocator object without first obtaining
  115. // the mutex. Callling functions should already have the DFMutex locked.
  116. //
  117. //--------------------------------------------------------------------------
  118. VECT_CLASS CPagedVector::~CPagedVector()
  119. {
  120. if (_pmsParent != NULL)
  121. {
  122. #ifdef MULTIHEAP
  123. // Free is the same as FreeNoMutex now
  124. _pmsParent->GetMalloc()->Free(BP_TO_P(CBasedMSFPagePtr*, _amp));
  125. _pmsParent->GetMalloc()->Free(BP_TO_P(CVectBits *,_avb));
  126. #else
  127. g_smAllocator.FreeNoMutex(BP_TO_P(CBasedMSFPagePtr*, _amp));
  128. g_smAllocator.FreeNoMutex(BP_TO_P(CVectBits *, _avb));
  129. #endif
  130. }
  131. else
  132. msfAssert(_amp == NULL && _avb == NULL &&
  133. aMsg("Can't free arrays without allocator"));
  134. }
  135. //+---------------------------------------------------------------------------
  136. //
  137. // Member: CPagedVector::Empty, public
  138. //
  139. // Synopsis: Discard the storage associated with this vector.
  140. //
  141. // Arguments: None.
  142. //
  143. // Returns: void.
  144. //
  145. // History: 04-Dec-92 PhilipLa Created
  146. //
  147. //----------------------------------------------------------------------------
  148. void CPagedVector::Empty(void)
  149. {
  150. if (_pmpt != NULL)
  151. {
  152. _pmpt->FreePages(this);
  153. }
  154. msfAssert(((_pmsParent != NULL) || ((_amp == NULL) && (_avb == NULL))) &&
  155. aMsg("Can't get to IMalloc for vector memory."));
  156. if (_pmsParent != NULL)
  157. {
  158. _pmsParent->GetMalloc()->Free(BP_TO_P(CBasedMSFPagePtr*, _amp));
  159. _pmsParent->GetMalloc()->Free(BP_TO_P(CVectBits *, _avb));
  160. }
  161. _amp = NULL;
  162. _avb = NULL;
  163. _pmpt = NULL;
  164. _ulAllocSize = _ulSize = 0;
  165. _pmsParent = NULL;
  166. }
  167. //+---------------------------------------------------------------------------
  168. //
  169. // Member: CPagedVector::Flush, public
  170. //
  171. // Synopsis: Flush the dirty pages for this vector
  172. //
  173. // Arguments: None.
  174. //
  175. // Returns: Appropriate status code
  176. //
  177. // History: 02-Nov-92 PhilipLa Created
  178. //
  179. //----------------------------------------------------------------------------
  180. SCODE CPagedVector::Flush(void)
  181. {
  182. #ifndef SORTPAGETABLE
  183. SCODE sc;
  184. SCODE scRet = S_OK;
  185. if (_ulSize > 0)
  186. {
  187. if (_amp != NULL)
  188. {
  189. for (ULONG i = 0; i < _ulSize; i++)
  190. {
  191. if ((_amp[i] != NULL) && (_amp[i]->IsDirty()))
  192. {
  193. sc = _pmpt->FlushPage(BP_TO_P(CMSFPage *, _amp[i]));
  194. if ((FAILED(sc)) && (SUCCEEDED(scRet)))
  195. {
  196. scRet = sc;
  197. }
  198. }
  199. }
  200. }
  201. else
  202. {
  203. scRet = _pmpt->Flush();
  204. }
  205. }
  206. return scRet;
  207. #else
  208. return S_OK;
  209. #endif
  210. }
  211. //+-------------------------------------------------------------------------
  212. //
  213. // Method: CPagedVector::GetTable, public
  214. //
  215. // Synopsis: Return a pointer to a page for the given index
  216. // into the vector.
  217. //
  218. // Arguments: [iTable] -- index into vector
  219. // [ppmp] -- Pointer to return location
  220. //
  221. // Returns: S_OK if call completed OK.
  222. //
  223. // History: 27-Oct-92 PhilipLa Created.
  224. //
  225. // Notes:
  226. //
  227. //--------------------------------------------------------------------------
  228. SCODE VECT_CLASS CPagedVector::GetTableWithSect(
  229. const FSINDEX iTable,
  230. DWORD dwFlags,
  231. SECT sectKnown,
  232. void **ppmp)
  233. {
  234. SCODE sc = S_OK;
  235. CMSFPage *pmp;
  236. msfAssert((_pmsParent->GetILB() != NULL) &&
  237. aMsg("Null ILB found on GetTable - need SetAccess call?"));
  238. // docfile is corrupted with an invalid iTable size
  239. if (iTable >= _ulSize)
  240. {
  241. msfErr(Err, STG_E_DOCFILECORRUPT);
  242. }
  243. if ((_amp == NULL) || (_amp[iTable] == NULL))
  244. {
  245. if (dwFlags & FB_NEW)
  246. {
  247. //We know that the page isn't in the page table,
  248. // so we can just get a free page an allocate it
  249. // ourselves.
  250. msfChk(_pmpt->GetFreePage(&pmp));
  251. pmp->SetVector(this);
  252. pmp->SetSid(_sid);
  253. pmp->SetOffset(iTable);
  254. #ifdef SORTPAGETABLE
  255. _pmpt->SetSect(pmp, ENDOFCHAIN);
  256. #else
  257. pmp->SetSect(ENDOFCHAIN);
  258. #endif
  259. sc = STG_S_NEWPAGE;
  260. dwFlags = (dwFlags & ~FB_NEW) | FB_DIRTY;
  261. }
  262. else
  263. {
  264. msfChk(_pmpt->GetPage(this,
  265. _sid, iTable, sectKnown, &pmp));
  266. msfAssert((pmp->GetVector() == this) &&
  267. aMsg("GetPage returned wrong page."));
  268. }
  269. if (_amp != NULL)
  270. {
  271. _amp[iTable] = P_TO_BP(CBasedMSFPagePtr, pmp);
  272. }
  273. }
  274. else
  275. {
  276. pmp = BP_TO_P(CMSFPage *, _amp[iTable]);
  277. msfAssert((pmp->GetVector() == this) &&
  278. aMsg("Cached page has wrong vector pointer"));
  279. }
  280. pmp->AddRef();
  281. if (((dwFlags & FB_DIRTY) && !(pmp->IsDirty())) &&
  282. (sc != STG_S_NEWPAGE))
  283. {
  284. //If we are not a newly created page, and we are being
  285. // dirtied for the first time, make sure that our
  286. // _sect field is correct.
  287. //
  288. //Newly created pages have to have their sect set manually
  289. // _before_ being released. This is very important.
  290. msfAssert(!_pmsParent->IsShadow() &&
  291. aMsg("Dirtying page in shadow multistream."));
  292. msfChkTo(Err_Rel, _pmsParent->GetFat()->QueryRemapped(pmp->GetSect()));
  293. if (sc == S_FALSE)
  294. {
  295. #ifdef SORTPAGETABLE
  296. _pmpt->SetSect(pmp, ENDOFCHAIN);
  297. #else
  298. pmp->SetSect(ENDOFCHAIN);
  299. #endif
  300. SECT sect;
  301. msfChkTo(Err_Rel, _pmsParent->GetESect(
  302. pmp->GetSid(),
  303. pmp->GetOffset(),
  304. &sect));
  305. #ifdef SORTPAGETABLE
  306. _pmpt->SetSect(pmp, sect);
  307. #else
  308. pmp->SetSect(sect);
  309. #endif
  310. }
  311. }
  312. #if DBG == 1
  313. else if ((pmp->IsDirty()) && (!pmp->IsInUse()) && (sc != STG_S_NEWPAGE))
  314. {
  315. msfAssert((_pmsParent->GetFat()->QueryRemapped(pmp->GetSect()) ==
  316. S_OK) &&
  317. aMsg("Found unremapped dirty page."));
  318. }
  319. #endif
  320. pmp->SetFlags(pmp->GetFlags() | dwFlags | FB_TOUCHED);
  321. msfAssert((pmp->GetVector() == this) &&
  322. aMsg("GetTable returned wrong page."));
  323. *ppmp = pmp->GetData();
  324. Err:
  325. return sc;
  326. Err_Rel:
  327. pmp->Release();
  328. return sc;
  329. }
  330. //+---------------------------------------------------------------------------
  331. //
  332. // Member: CPagedVector::SetDirty, public
  333. //
  334. // Synopsis: Set the dirty bit on the specified page
  335. //
  336. // Arguments: [iTable] -- Table to set bit on
  337. //
  338. // History: 28-Oct-92 PhilipLa Created
  339. //
  340. // Notes: This function is always called on a page with an
  341. // open reference. Therefore, the page is
  342. // guaranteed to be in the page table, and that
  343. // FindPage call should never return an error.
  344. //
  345. //----------------------------------------------------------------------------
  346. SCODE CPagedVector::SetDirty(ULONG iTable)
  347. {
  348. SCODE sc = S_OK;
  349. CMSFPage *pmp;
  350. msfAssert((!_pmsParent->IsShadow()) &&
  351. aMsg("Dirtying page in shadow."));
  352. if (_amp == NULL)
  353. {
  354. msfChk(_pmpt->FindPage(this, _sid, iTable, &pmp));
  355. msfAssert(sc == STG_S_FOUND);
  356. msfAssert(pmp->IsInUse() &&
  357. aMsg("Called SetDirty on page not in use."));
  358. }
  359. else
  360. {
  361. msfAssert(_amp != NULL);
  362. msfAssert(_amp[iTable] != NULL);
  363. pmp = BP_TO_P(CMSFPage *, _amp[iTable]);
  364. }
  365. if (!pmp->IsDirty())
  366. {
  367. //We are not a newly created page, and we are being
  368. // dirtied for the first time, make sure that our
  369. // _sect field is correct.
  370. //
  371. msfAssert(!_pmsParent->IsShadow() &&
  372. aMsg("Dirtying page in shadow multistream."));
  373. pmp->AddRef();
  374. msfChkTo(Err_Rel, _pmsParent->GetFat()->QueryRemapped(pmp->GetSect()));
  375. if (sc == S_FALSE)
  376. {
  377. #ifdef SORTPAGETABLE
  378. _pmpt->SetSect(pmp, ENDOFCHAIN);
  379. #else
  380. pmp->SetSect(ENDOFCHAIN);
  381. #endif
  382. SECT sect;
  383. msfChkTo(Err_Rel, _pmsParent->GetESect(
  384. pmp->GetSid(),
  385. pmp->GetOffset(),
  386. &sect));
  387. #ifdef SORTPAGETABLE
  388. _pmpt->SetSect(pmp, sect);
  389. #else
  390. pmp->SetSect(sect);
  391. #endif
  392. }
  393. pmp->Release();
  394. }
  395. #if DBG == 1
  396. else
  397. {
  398. pmp->AddRef();
  399. sc = _pmsParent->GetFat()->QueryRemapped(pmp->GetSect());
  400. msfAssert((SUCCEEDED(sc)) &&
  401. aMsg("QueryRemapped returned error"));
  402. msfAssert((sc == S_OK) &&
  403. aMsg("QueryRemapped returned non-TRUE value."));
  404. pmp->Release();
  405. }
  406. #endif
  407. pmp->SetDirty();
  408. Err:
  409. return sc;
  410. Err_Rel:
  411. pmp->Release();
  412. return sc;
  413. }
  414. //+-------------------------------------------------------------------------
  415. //
  416. // Method: CPagedVector::Resize, public
  417. //
  418. // Synopsis: Resize a CPagedVector
  419. //
  420. // Arguments: [ulSize] -- Size of new vector
  421. //
  422. // Algorithm: Create new pointer array of size ulSize.
  423. // For each entry in old array, copy the pointer over.
  424. //
  425. // History: 27-Oct-92 PhilipLa Created.
  426. // 08-Feb-93 AlexT Add LARGETHRESHOLD support
  427. //
  428. // Notes:
  429. //
  430. //--------------------------------------------------------------------------
  431. #define LARGETHRESHOLD 1024
  432. #define VECTORBLOCK 1024 // Must be power of 2
  433. SCODE VECT_CLASS CPagedVector::Resize(FSINDEX ulSize)
  434. {
  435. msfDebugOut((DEB_ITRACE,"In CPagedVector::CPagedVector(%lu)\n",ulSize));
  436. msfAssert(ulSize >= _ulSize);
  437. msfAssert(_ulSize <= _ulAllocSize);
  438. msfAssert(((VECTORBLOCK & (VECTORBLOCK - 1)) == 0) &&
  439. aMsg("VECTORBLOCK must be power of 2"));
  440. msfAssert(!((_amp == NULL) && (_avb != NULL)) &&
  441. aMsg("Resize precondition failed."));
  442. if (ulSize > _ulAllocSize)
  443. {
  444. // We don't have room in the existing vector; grow it
  445. ULONG ulNewAllocSize = ulSize;
  446. if (ulNewAllocSize > LARGETHRESHOLD)
  447. {
  448. // We're dealing with a large vector; grow it a VECTORBLOCK
  449. // at a time
  450. ulNewAllocSize = (ulNewAllocSize + VECTORBLOCK - 1) &
  451. ~(VECTORBLOCK - 1);
  452. }
  453. CBasedMSFPagePtr *amp = GetNewPageArray(ulNewAllocSize);
  454. CVectBits *avb = GetNewVectBits(ulNewAllocSize);
  455. // Can't fail after this point
  456. _ulAllocSize = ulNewAllocSize;
  457. // Copy over the old entries
  458. if ((amp != NULL) && (avb != NULL))
  459. {
  460. if ((_amp != NULL) && (_avb != NULL))
  461. {
  462. // Both allocations succeeded
  463. for (ULONG iamp = 0; iamp < _ulSize; iamp++)
  464. {
  465. amp[iamp] = _amp[iamp];
  466. avb[iamp] = _avb[iamp];
  467. }
  468. }
  469. else if (_amp != NULL)
  470. {
  471. for (ULONG iamp = 0; iamp < _ulSize; iamp++)
  472. {
  473. amp[iamp] = _amp[iamp];
  474. }
  475. }
  476. else
  477. {
  478. for (ULONG iamp = 0; iamp < _ulSize; iamp++)
  479. {
  480. amp[iamp] = NULL;
  481. }
  482. }
  483. }
  484. else
  485. {
  486. // At least one of the allocations failed
  487. _pmsParent->GetMalloc()->Free(avb);
  488. avb = NULL;
  489. _pmsParent->GetMalloc()->Free(amp);
  490. amp = NULL;
  491. }
  492. // Delete the old vector and put in the new one (if any).
  493. // In the error case, throw away the vectors we are currently
  494. // holding (since they are of insufficient size) and return S_OK.
  495. _pmsParent->GetMalloc()->Free(BP_TO_P(CBasedMSFPagePtr*, _amp));
  496. _amp = P_TO_BP(CBasedMSFPagePtrPtr, amp);
  497. _pmsParent->GetMalloc()->Free(BP_TO_P(CVectBits *, _avb));
  498. _avb = P_TO_BP(CBasedVectBitsPtr, avb);
  499. }
  500. if (_amp != NULL)
  501. {
  502. // Initialize the new elements in the vector
  503. for (ULONG iamp = _ulSize; iamp < ulSize; iamp++)
  504. _amp[iamp] = NULL;
  505. }
  506. _ulSize = ulSize;
  507. msfDebugOut((DEB_ITRACE,"Out CPagedVector resize constructor\n"));
  508. return S_OK;
  509. }
  510. //+-------------------------------------------------------------------------
  511. //
  512. // Method: CPagedVector::InitCopy, public
  513. //
  514. // Synopsis: CPagedVector Init function for copying
  515. //
  516. // Arguments: [vectOld] -- Reference to vector to be copied.
  517. //
  518. // Algorithm: *Finish This*
  519. //
  520. // History: 27-Oct-92 PhilipLa Created.
  521. //
  522. // Notes:
  523. //
  524. //--------------------------------------------------------------------------
  525. void VECT_CLASS CPagedVector::InitCopy(CPagedVector *pvectOld)
  526. {
  527. msfDebugOut((DEB_ITRACE,"In CPagedVector copy constructor\n"));
  528. SCODE sc;
  529. ULONG i;
  530. _pmsParent = pvectOld->_pmsParent;
  531. CMSFPageTable *pmpt;
  532. pmpt = _pmsParent->GetPageTable();
  533. _pmpt = P_TO_BP(CBasedMSFPageTablePtr, pmpt);
  534. _ulAllocSize = _ulSize = pvectOld->_ulSize;
  535. if (_ulSize > 0)
  536. {
  537. CBasedMSFPagePtr* amp;
  538. msfMem(amp = GetNewPageArray(_ulSize));
  539. for (i = 0; i < _ulSize; i++)
  540. {
  541. amp[i] = NULL;
  542. if (pvectOld->_amp != NULL)
  543. {
  544. _pmpt->CopyPage(this,
  545. BP_TO_P(CMSFPage *, pvectOld->_amp[i]),
  546. &(amp[i]));
  547. }
  548. }
  549. _amp = P_TO_BP(CBasedMSFPagePtrPtr, amp);
  550. CVectBits *avb;
  551. msfMem(avb = GetNewVectBits(_ulSize));
  552. if (pvectOld->_avb != NULL)
  553. {
  554. for (i = 0; i < _ulSize; i++)
  555. {
  556. avb[i] = ((CPagedVector *)pvectOld)->_avb[i];
  557. }
  558. }
  559. _avb = P_TO_BP(CBasedVectBitsPtr, avb);
  560. }
  561. msfDebugOut((DEB_ITRACE,"Out CPagedVector copy constructor\n"));
  562. //In the error case, keep whatever vectors we managed to allocate
  563. // and return.
  564. Err:
  565. return;
  566. }