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.

462 lines
11 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. //----------------------------------------------------------------------------
  15. #include "msfhead.cxx"
  16. #include "h/vect.hxx"
  17. //+-------------------------------------------------------------------------
  18. //
  19. // Method: CPagedVector::Init, public
  20. //
  21. // Synopsis: CPagedVector initialization function
  22. //
  23. // Arguments: [ulSize] -- size of vector
  24. //
  25. // Algorithm: Allocate an array of pointer of size ulSize
  26. // For each cell in the array, allocate a CFatSect
  27. //
  28. // Notes:
  29. //
  30. //--------------------------------------------------------------------------
  31. SCODE CPagedVector::Init(CMStream *pmsParent, ULONG ulSize)
  32. {
  33. msfDebugOut((DEB_ITRACE,"In CPagedVector::CPagedVector(%lu)\n",ulSize));
  34. SCODE sc = S_OK;
  35. _pmsParent = pmsParent;
  36. _pmpt = _pmsParent->GetPageTable();
  37. msfAssert(_pmpt != NULL);
  38. USHORT i;
  39. // We don't bother allocating more than necessary here
  40. _ulAllocSize = _ulSize = ulSize;
  41. if (_ulSize > 0)
  42. {
  43. msfMem(_amp = GetNewPageArray(ulSize));
  44. for (i = 0; i < _ulSize; i++)
  45. {
  46. _amp[i] = NULL;
  47. }
  48. msfMem(_avb = GetNewVectBits(ulSize));
  49. }
  50. msfDebugOut((DEB_ITRACE,"Out CPagedVector::CPagedVector()\n"));
  51. return S_OK;
  52. Err:
  53. //In the error case, discard whatever vectors we were able to allocate
  54. // and return S_OK.
  55. delete [] _amp;
  56. _amp = NULL;
  57. delete [] _avb;
  58. _avb = NULL;
  59. return S_OK;
  60. }
  61. //+-------------------------------------------------------------------------
  62. //
  63. // Method: CPagedVector::~CPagedVector, public
  64. //
  65. // Synopsis: CPagedVector constructor
  66. //
  67. // Algorithm: Delete the pointer array.
  68. //
  69. // Notes:
  70. //
  71. //--------------------------------------------------------------------------
  72. CPagedVector::~CPagedVector()
  73. {
  74. delete [] _amp;
  75. delete [] _avb;
  76. }
  77. //+---------------------------------------------------------------------------
  78. //
  79. // Member: CPagedVector::Empty, public
  80. //
  81. // Synopsis: Discard the storage associated with this vector.
  82. //
  83. // Arguments: None.
  84. //
  85. // Returns: void.
  86. //
  87. //----------------------------------------------------------------------------
  88. void CPagedVector::Empty(void)
  89. {
  90. if (_pmpt != NULL)
  91. {
  92. _pmpt->FreePages(this);
  93. }
  94. delete [] _amp;
  95. delete [] _avb;
  96. _amp = NULL;
  97. _avb = NULL;
  98. _pmpt = NULL;
  99. _ulAllocSize = _ulSize = 0;
  100. _pmsParent = NULL;
  101. }
  102. //+---------------------------------------------------------------------------
  103. //
  104. // Member: CPagedVector::Flush, public
  105. //
  106. // Synopsis: Flush the dirty pages for this vector
  107. //
  108. // Arguments: None.
  109. //
  110. // Returns: Appropriate status code
  111. //
  112. //----------------------------------------------------------------------------
  113. SCODE CPagedVector::Flush(void)
  114. {
  115. SCODE sc;
  116. SCODE scRet = S_OK;
  117. if (_ulSize > 0)
  118. {
  119. if (_amp != NULL)
  120. {
  121. for (USHORT i = 0; i < _ulSize; i++)
  122. {
  123. if ((_amp[i] != NULL) && (_amp[i]->IsDirty()))
  124. {
  125. sc = _pmpt->FlushPage(_amp[i]);
  126. if ((FAILED(sc)) && (SUCCEEDED(scRet)))
  127. {
  128. scRet = sc;
  129. }
  130. }
  131. }
  132. }
  133. else
  134. {
  135. scRet = _pmpt->Flush();
  136. }
  137. }
  138. return scRet;
  139. }
  140. //+-------------------------------------------------------------------------
  141. //
  142. // Method: CPagedVector::GetTable, public
  143. //
  144. // Synopsis: Return a pointer to a page for the given index
  145. // into the vector.
  146. //
  147. // Arguments: [iTable] -- index into vector
  148. // [ppmp] -- Pointer to return location
  149. //
  150. // Returns: S_OK if call completed OK.
  151. //
  152. // Notes:
  153. //
  154. //--------------------------------------------------------------------------
  155. SCODE CPagedVector::GetTable(
  156. const FSINDEX iTable,
  157. DWORD dwFlags,
  158. void **ppmp)
  159. {
  160. SCODE sc = S_OK;
  161. CMSFPage *pmp;
  162. msfAssert((_pmsParent->GetILB() != NULL) &&
  163. aMsg("Null ILB found on GetTable - need SetAccess call?"));
  164. // docfile is corrupted with an invalid iTable size
  165. if (iTable >= _ulSize)
  166. {
  167. msfErr(Err, STG_E_DOCFILECORRUPT);
  168. }
  169. if ((_amp == NULL) || (_amp[iTable] == NULL))
  170. {
  171. if (dwFlags & FB_NEW)
  172. {
  173. //We know that the page isn't in the page table,
  174. // so we can just get a free page an allocate it
  175. // ourselves.
  176. msfChk(_pmpt->GetFreePage(&pmp));
  177. pmp->SetVector(this);
  178. pmp->SetSid(_sid);
  179. pmp->SetOffset(iTable);
  180. pmp->SetSect(ENDOFCHAIN);
  181. sc = STG_S_NEWPAGE;
  182. dwFlags = (dwFlags & ~FB_NEW) | FB_DIRTY;
  183. }
  184. else
  185. {
  186. msfChk(_pmpt->GetPage(this, _sid, iTable, &pmp));
  187. msfAssert((pmp->GetVector() == this) &&
  188. aMsg("GetPage returned wrong page."));
  189. }
  190. if (_amp != NULL)
  191. {
  192. _amp[iTable] = pmp;
  193. }
  194. }
  195. else
  196. {
  197. pmp = _amp[iTable];
  198. msfAssert((pmp->GetVector() == this) &&
  199. aMsg("Cached page has wrong vector pointer"));
  200. }
  201. pmp->AddRef();
  202. if (((dwFlags & FB_DIRTY) && !(pmp->IsDirty())) &&
  203. (sc != STG_S_NEWPAGE))
  204. {
  205. //If we are not a newly created page, and we are being
  206. // dirtied for the first time, make sure that our
  207. // _sect field is correct.
  208. //
  209. //Newly created pages have to have their sect set manually
  210. // _before_ being released. This is very important.
  211. pmp->SetSect(ENDOFCHAIN);
  212. SECT sect;
  213. msfChkTo(Err_Rel, _pmsParent->GetESect(
  214. pmp->GetSid(),
  215. pmp->GetOffset(),
  216. &sect));
  217. pmp->SetSect(sect);
  218. }
  219. pmp->SetFlags(pmp->GetFlags() | dwFlags | FB_TOUCHED);
  220. msfAssert((pmp->GetVector() == this) &&
  221. aMsg("GetTable returned wrong page."));
  222. *ppmp = pmp->GetData();
  223. Err:
  224. return sc;
  225. Err_Rel:
  226. pmp->Release();
  227. return sc;
  228. }
  229. //+---------------------------------------------------------------------------
  230. //
  231. // Member: CPagedVector::SetDirty, public
  232. //
  233. // Synopsis: Set the dirty bit on the specified page
  234. //
  235. // Arguments: [iTable] -- Table to set bit on
  236. //
  237. // Notes: This function is always called on a page with an
  238. // open reference. Therefore, the page is
  239. // guaranteed to be in the page table, and that
  240. // FindPage call should never return an error.
  241. //
  242. //----------------------------------------------------------------------------
  243. SCODE CPagedVector::SetDirty(ULONG iTable)
  244. {
  245. SCODE sc = S_OK;
  246. CMSFPage *pmp;
  247. if (_amp == NULL)
  248. {
  249. msfChk(_pmpt->FindPage(this, _sid, iTable, &pmp));
  250. msfAssert(sc == STG_S_FOUND);
  251. msfAssert(pmp->IsInUse() &&
  252. aMsg("Called SetDirty on page not in use."));
  253. }
  254. else
  255. {
  256. msfAssert(_amp != NULL);
  257. msfAssert(_amp[iTable] != NULL);
  258. pmp = _amp[iTable];
  259. }
  260. if (!pmp->IsDirty())
  261. {
  262. //We are not a newly created page, and we are being
  263. // dirtied for the first time, make sure that our
  264. // _sect field is correct.
  265. //
  266. pmp->AddRef();
  267. pmp->SetSect(ENDOFCHAIN);
  268. SECT sect;
  269. msfChkTo(Err_Rel, _pmsParent->GetESect(
  270. pmp->GetSid(),
  271. pmp->GetOffset(),
  272. &sect));
  273. pmp->SetSect(sect);
  274. pmp->Release();
  275. }
  276. pmp->SetDirty();
  277. Err:
  278. return sc;
  279. Err_Rel:
  280. pmp->Release();
  281. return sc;
  282. }
  283. //+-------------------------------------------------------------------------
  284. //
  285. // Method: CPagedVector::Resize, public
  286. //
  287. // Synopsis: Resize a CPagedVector
  288. //
  289. // Arguments: [ulSize] -- Size of new vector
  290. //
  291. // Algorithm: Create new pointer array of size ulSize.
  292. // For each entry in old array, copy the pointer over.
  293. //
  294. // Notes:
  295. //
  296. //--------------------------------------------------------------------------
  297. #define LARGETHRESHOLD 1024
  298. #define VECTORBLOCK 1024 // Must be power of 2
  299. SCODE CPagedVector::Resize(FSINDEX ulSize)
  300. {
  301. msfDebugOut((DEB_ITRACE,"In CPagedVector::CPagedVector(%lu)\n",ulSize));
  302. msfAssert(ulSize >= _ulSize);
  303. msfAssert(_ulSize <= _ulAllocSize);
  304. msfAssert(((VECTORBLOCK & (VECTORBLOCK - 1)) == 0) &&
  305. aMsg("VECTORBLOCK must be power of 2"));
  306. msfAssert(!((_amp == NULL) && (_avb != NULL)) &&
  307. aMsg("Resize precondition failed."));
  308. if (ulSize > _ulAllocSize)
  309. {
  310. // We don't have room in the existing vector; grow it
  311. ULONG ulNewAllocSize = ulSize;
  312. if (ulNewAllocSize > LARGETHRESHOLD)
  313. {
  314. // We're dealing with a large vector; grow it a VECTORBLOCK
  315. // at a time
  316. ulNewAllocSize = (ulNewAllocSize + VECTORBLOCK - 1) &
  317. ~(VECTORBLOCK - 1);
  318. }
  319. CMSFPage **amp = GetNewPageArray(ulNewAllocSize);
  320. CVectBits *avb = GetNewVectBits(ulNewAllocSize);
  321. // Can't fail after this point
  322. _ulAllocSize = ulNewAllocSize;
  323. // Copy over the old entries
  324. if ((amp != NULL) && (avb != NULL))
  325. {
  326. if ((_amp != NULL) && (_avb != NULL))
  327. {
  328. // Both allocations succeeded
  329. for (ULONG iamp = 0; iamp < _ulSize; iamp++)
  330. {
  331. amp[iamp] = _amp[iamp];
  332. avb[iamp] = _avb[iamp];
  333. }
  334. }
  335. else if (_amp != NULL)
  336. {
  337. for (ULONG iamp = 0; iamp < _ulSize; iamp++)
  338. {
  339. amp[iamp] = _amp[iamp];
  340. }
  341. }
  342. else
  343. {
  344. for (ULONG iamp = 0; iamp < _ulSize; iamp++)
  345. {
  346. amp[iamp] = NULL;
  347. }
  348. }
  349. }
  350. else
  351. {
  352. // At least one of the allocations failed
  353. delete [] avb;
  354. avb = NULL;
  355. delete [] amp;
  356. amp = NULL;
  357. }
  358. // Delete the old vector and put in the new one (if any).
  359. // In the error case, throw away the vectors we are currently
  360. // holding (since they are of insufficient size) and return S_OK.
  361. delete [] _amp;
  362. _amp = amp;
  363. delete [] _avb;
  364. _avb = avb;
  365. }
  366. if (_amp != NULL)
  367. {
  368. // Initialize the new elements in the vector
  369. for (ULONG iamp = _ulSize; iamp < ulSize; iamp++)
  370. _amp[iamp] = NULL;
  371. }
  372. _ulSize = ulSize;
  373. msfDebugOut((DEB_ITRACE,"Out CPagedVector resize constructor\n"));
  374. return S_OK;
  375. }