Leaked source code of windows server 2003
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.

787 lines
25 KiB

  1. // Ruler
  2. // 1 2 3 4 5 6 7 8
  3. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  4. /********************************************************************/
  5. /* */
  6. /* The standard layout. */
  7. /* */
  8. /* The standard layout for 'cpp' files in this code is as */
  9. /* follows: */
  10. /* */
  11. /* 1. Include files. */
  12. /* 2. Constants local to the class. */
  13. /* 3. Data structures local to the class. */
  14. /* 4. Data initializations. */
  15. /* 5. Static functions. */
  16. /* 6. Class functions. */
  17. /* */
  18. /* The constructor is typically the first function, class */
  19. /* member functions appear in alphabetical order with the */
  20. /* destructor appearing at the end of the file. Any section */
  21. /* or function this is not required is simply omitted. */
  22. /* */
  23. /********************************************************************/
  24. #include "HeapPCH.hpp"
  25. #include "Cache.hpp"
  26. #include "Heap.hpp"
  27. #include "NewPage.hpp"
  28. #include "Page.hpp"
  29. /********************************************************************/
  30. /* */
  31. /* Constants local to the class. */
  32. /* */
  33. /* The constants supplied here allow the allocation bit vector */
  34. /* to be rapidly searched for free storage. */
  35. /* */
  36. /********************************************************************/
  37. CONST BIT32 AllocatedMask = 0x2;
  38. CONST BIT32 FullSearchMask = 0xaaaaaaaa;
  39. CONST BIT32 FullWordShift = (MaxBitsPerWord - OverheadBits);
  40. CONST BIT32 SubDividedMask = 0x1;
  41. CONST BIT32 WordSearchMask = (AllocatedMask << FullWordShift);
  42. /********************************************************************/
  43. /* */
  44. /* Class constructor. */
  45. /* */
  46. /* */
  47. /* All page descriptions are actually created and deleted by */
  48. /* a separate class called 'NEW_PAGE'. Nonetheless, as a */
  49. /* step the appropriate constructors and destructors are */
  50. /* invoked to support the standard C++ programming methodology. */
  51. /* */
  52. /********************************************************************/
  53. PAGE::PAGE
  54. (
  55. VOID *NewAddress,
  56. CACHE *NewCache,
  57. SBIT32 NewPageSize,
  58. CACHE *NewParentPage,
  59. SBIT32 NewVersion
  60. )
  61. {
  62. REGISTER SBIT32 Count;
  63. REGISTER SBIT16 NumberOfElements = (NewCache -> GetNumberOfElements());
  64. REGISTER SBIT16 SizeOfElements = (NewCache -> GetSizeOfElements());
  65. //
  66. // Create a page description.
  67. //
  68. Address = (CHAR*) NewAddress;
  69. PageSize = NewPageSize;
  70. Version = NewVersion;
  71. Allocated = 0;
  72. Available = NumberOfElements;
  73. FirstFree = 0;
  74. //
  75. // Set up the pointers to related classes.
  76. //
  77. Cache = NewCache;
  78. ParentPage = NewParentPage;
  79. //
  80. // Zero the bit vector.
  81. //
  82. for ( Count=0;Count < SizeOfElements;Count ++ )
  83. { Vector[ Count ] = 0; }
  84. }
  85. /********************************************************************/
  86. /* */
  87. /* Compute the actual size. */
  88. /* */
  89. /* Almost all allocation sizes are derived from the associated */
  90. /* caches. However, there are a few special pages that contain */
  91. /* a single allocation of some weird size. */
  92. /* */
  93. /********************************************************************/
  94. SBIT32 PAGE::ActualSize( VOID )
  95. {
  96. return
  97. (
  98. (ParentPage == ((CACHE*) GlobalRoot))
  99. ? PageSize
  100. : (Cache -> GetAllocationSize())
  101. );
  102. }
  103. /********************************************************************/
  104. /* */
  105. /* Delete an allocation. */
  106. /* */
  107. /* We need to delete the memory allocation described by the */
  108. /* parameters. However, as we are of an untrusting nature */
  109. /* we carefully check the request to ensure it is valid. */
  110. /* */
  111. /********************************************************************/
  112. BOOLEAN PAGE::Delete( SEARCH_PAGE *Details )
  113. {
  114. //
  115. // We know that no one would deallocate memory
  116. // they had not previously allocated (yea - right).
  117. // So here we check for this case.
  118. //
  119. if ( (*Details -> VectorWord) & Details -> AllocationMask )
  120. {
  121. //
  122. // Nasty: it is possible for the user to give us an
  123. // address that points to the middle of the element
  124. // to be freed instead of the beginning. This is no
  125. // problem for us but we have to ponder whether the
  126. // caller knew what they were doing. If this is the
  127. // case we fail the request.
  128. //
  129. if ( Details -> Found )
  130. {
  131. //
  132. // We have found that the element is allocated
  133. // (as one might expect) so lets deallocate it
  134. // and update the various counters.
  135. //
  136. (*Details -> VectorWord) &=
  137. ~(Details -> AllocationMask | Details ->SubDivisionMask);
  138. //
  139. // We may need to push back the pointer to the
  140. // first free element. This will ensure that
  141. // we can quickly locate the freed element for
  142. // later so we can reuse it.
  143. //
  144. if ( FirstFree > Details -> VectorOffset )
  145. { FirstFree = ((SBIT16) Details -> VectorOffset); }
  146. //
  147. // If the page was full and now has an empty
  148. // slot then add it to the bucket list so that
  149. // the free space can be found.
  150. //
  151. if ( Full() )
  152. { Cache -> InsertInBucketList( this ); }
  153. //
  154. // Update the allocation information.
  155. //
  156. Allocated --;
  157. Available ++;
  158. //
  159. // If the page is now empty then delete
  160. // the page to conserve space.
  161. //
  162. if ( Empty() )
  163. {
  164. //
  165. // We immediately delete empty pages
  166. // except at the top level where it is
  167. // under user control.
  168. //
  169. if ( ! Cache -> TopCache() )
  170. { Cache -> DeletePage( this ); }
  171. else
  172. {
  173. REGISTER SBIT32 MaxFreePages =
  174. (Cache -> GetHeap() -> GetMaxFreePages());
  175. ((BUCKET*) Cache) -> ReleaseSpace( MaxFreePages );
  176. }
  177. }
  178. return True;
  179. }
  180. }
  181. return False;
  182. }
  183. /********************************************************************/
  184. /* */
  185. /* Delete all simple allocations. */
  186. /* */
  187. /* Although this routine may seem insignificant its effects are */
  188. /* dramatic. When called this function deletes all the none */
  189. /* sub-allocated elements and updates the control values. */
  190. /* */
  191. /********************************************************************/
  192. VOID PAGE::DeleteAll( VOID )
  193. {
  194. REGISTER BOOLEAN PageFull = Full();
  195. //
  196. // Simply reset the allocation counts.
  197. //
  198. Allocated = 0;
  199. Available = (Cache -> GetNumberOfElements());
  200. FirstFree = 0;
  201. //
  202. // We know that if this cache does not have any
  203. // child allocations that it is safe to simply
  204. // zero the bit vector. If not we have to do it
  205. // the long way.
  206. //
  207. if ( Cache -> GetNumberOfChildren() > 0 )
  208. {
  209. REGISTER SBIT32 Count;
  210. REGISTER SBIT16 SizeOfElements = (Cache -> GetSizeOfElements());
  211. //
  212. // We examine each word of the bit vector
  213. // and delete all the elements that are
  214. // not sub-divided into smaller sizes.
  215. //
  216. for ( Count=0;Count < SizeOfElements;Count ++ )
  217. {
  218. REGISTER BIT32 *Word = & Vector[ Count ];
  219. REGISTER BIT32 AllAllocations = ((*Word) & FullSearchMask);
  220. REGISTER BIT32 AllSubDivided = ((*Word) & (AllAllocations >> 1));
  221. REGISTER BIT32 FinalMask = (AllSubDivided | (AllSubDivided << 1));
  222. //
  223. // Delete all normal allocations.
  224. //
  225. (*Word) &= FinalMask;
  226. //
  227. // If the final mask is not zero then
  228. // we still have some allocations active.
  229. // We need to count these and update the
  230. // control information.
  231. //
  232. if ( FinalMask != 0 )
  233. {
  234. REGISTER SBIT32 Total = 0;
  235. //
  236. // Count the allocations.
  237. //
  238. for ( /* void */;FinalMask != 0;FinalMask >>= OverheadBits )
  239. { Total += (FinalMask & 1); }
  240. //
  241. // Update the control information.
  242. //
  243. Allocated = ((SBIT16) (Allocated + Total));
  244. Available = ((SBIT16) (Available - Total));
  245. }
  246. }
  247. }
  248. else
  249. {
  250. REGISTER SBIT32 Count;
  251. REGISTER SBIT16 SizeOfElements = (Cache -> GetSizeOfElements());
  252. //
  253. // Zero the bit vector.
  254. //
  255. for ( Count=0;Count < SizeOfElements;Count ++ )
  256. { Vector[ Count ] = 0; }
  257. }
  258. //
  259. // If the page was full and now has empty
  260. // slots then add it to the bucket list so
  261. // that the free space can be found.
  262. //
  263. if ( (PageFull) && (! Full()) )
  264. { Cache -> InsertInBucketList( this ); }
  265. }
  266. /********************************************************************/
  267. /* */
  268. /* Find an allocation page. */
  269. /* */
  270. /* When we receive a request to delete an allocation we don't */
  271. /* have a clue about where to find it. All we have is a hash */
  272. /* table (see 'FIND') of allocated pages. So we mask off the */
  273. /* low order bits of the address and try to find the top level */
  274. /* external allocation. If this works we see if the area we */
  275. /* are looking at has been sub-divided and if so we try the */
  276. /* same trick again until we get the the origibal allocation */
  277. /* page. */
  278. /* */
  279. /********************************************************************/
  280. PAGE *PAGE::FindPage( VOID *Memory,SEARCH_PAGE *Details,BOOLEAN Recursive )
  281. {
  282. //
  283. // We navigate through the pages trying to find
  284. // the allocation page associated with the address.
  285. // If we find a page that has no children then
  286. // we can assume we have arrived and exit early
  287. // unless the caller has requested all the realated
  288. // details.
  289. //
  290. if ( (Cache -> GetNumberOfChildren() > 0) || (Details != NULL) )
  291. {
  292. AUTO BOOLEAN Found;
  293. REGISTER SBIT32 Displacement =
  294. ((SBIT32) (((CHAR*) Memory) - Address));
  295. REGISTER SBIT32 ArrayOffset =
  296. (Cache -> ComputeOffset( Displacement,& Found ));
  297. REGISTER SBIT32 VectorOffset =
  298. (ArrayOffset / OverheadBitsPerWord);
  299. REGISTER SBIT32 WordOffset =
  300. (ArrayOffset - (VectorOffset * OverheadBitsPerWord));
  301. REGISTER SBIT32 WordShift =
  302. (((OverheadBitsPerWord-1) - WordOffset) * OverheadBits);
  303. REGISTER BIT32 AllocationMask =
  304. (AllocatedMask << WordShift);
  305. REGISTER BIT32 SubDivisionMask =
  306. (SubDividedMask << WordShift);
  307. REGISTER BIT32 *VectorWord =
  308. & Vector[ VectorOffset ];
  309. //
  310. // We will recursively search and find the target
  311. // address if requested otherwise we will just
  312. // return the details of the next level in the tree.
  313. //
  314. if
  315. (
  316. (Recursive)
  317. &&
  318. ((*VectorWord) & AllocationMask)
  319. &&
  320. ((*VectorWord) & SubDivisionMask)
  321. )
  322. {
  323. REGISTER PAGE *Page = (Cache -> FindChildPage( Memory ));
  324. //
  325. // We have found the element and checked it.
  326. // So lets pass this request on to the
  327. // child page. However, there is a slight
  328. // chance of a race condition here. It
  329. // might be that the original page was
  330. // deleted and a new page is currently
  331. // being created. If this is the case
  332. // then we will not find the page in the
  333. // hash table so we just exit and fail the
  334. // call.
  335. //
  336. if ( Page != ((PAGE*) NULL) )
  337. { return (Page -> FindPage( Memory,Details,Recursive )); }
  338. else
  339. { return NULL; }
  340. }
  341. //
  342. // We see if the caller is interested in the
  343. // details relating to this address at the
  344. // current level in the tree.
  345. //
  346. if ( Details != NULL )
  347. {
  348. //
  349. // We have computed the details relating
  350. // to this address at the current level
  351. // in the tree so load them into the
  352. // caller supplied structure.
  353. //
  354. Details -> Address = Memory;
  355. Details -> Cache = Cache;
  356. Details -> Found = Found;
  357. Details -> Page = this;
  358. Details -> AllocationMask = AllocationMask;
  359. Details -> SubDivisionMask = SubDivisionMask;
  360. Details -> VectorWord = VectorWord;
  361. Details -> ArrayOffset = ArrayOffset;
  362. Details -> VectorOffset = VectorOffset;
  363. Details -> WordShift = WordShift;
  364. }
  365. }
  366. return this;
  367. }
  368. /********************************************************************/
  369. /* */
  370. /* Multiple memory allocations. */
  371. /* */
  372. /* Allocate available memeory elements from a page. This is */
  373. /* done by scanning the bit vector looking for unallocated */
  374. /* slots. */
  375. /* */
  376. /********************************************************************/
  377. BOOLEAN PAGE::MultipleNew( SBIT32 *Actual,VOID *Array[],SBIT32 Requested )
  378. {
  379. //
  380. // We begin by making sure that there is at least
  381. // one element to allocate and that we need to
  382. // allocated at least one element.
  383. //
  384. if ( (! Full()) && ((*Actual) < Requested) )
  385. {
  386. REGISTER SBIT16 SizeOfElements = (Cache -> GetSizeOfElements());
  387. //
  388. // Search the bit vector from low addresses to
  389. // high addresses looking for a free slots.
  390. // We keep a pointer to the first word with
  391. // a free element in 'FirstFree'. Sometimes
  392. // the current word may be fully allocated so
  393. // we might need to scan. However, there can
  394. // never be any free memory before this point
  395. // in the bit vector.
  396. //
  397. for ( /* void */;FirstFree < SizeOfElements;FirstFree ++ )
  398. {
  399. REGISTER SBIT32 ArrayOffset = (FirstFree * OverheadBitsPerWord);
  400. REGISTER BIT32 AvailableMask = WordSearchMask;
  401. REGISTER BIT32 *VectorWord = & Vector[ FirstFree ];
  402. REGISTER SBIT32 WordOffset = 0;
  403. //
  404. // We scan the bit vector word at a time
  405. // looking for any free allocation slots.
  406. //
  407. while ( ((*VectorWord) & FullSearchMask) != FullSearchMask )
  408. {
  409. REGISTER BIT32 Value = (*VectorWord);
  410. //
  411. // We know there is an at least one empty
  412. // slot availabale in the current word but
  413. // don't know which one We search for the
  414. // slot with the lowest address and stop
  415. // when we find it.
  416. //
  417. for
  418. (
  419. /* void */;
  420. (AvailableMask & Value) != 0;
  421. AvailableMask >>= OverheadBits, WordOffset ++
  422. );
  423. //
  424. // We should never fail to find a free
  425. // allocation slot so if we do then the
  426. // heap must be corrupt.
  427. //
  428. if ( WordOffset < OverheadBitsPerWord )
  429. {
  430. REGISTER SBIT32 VectorOffset = (ArrayOffset + WordOffset);
  431. //
  432. // We need to ensure that the element
  433. // we have chosen if not outside the
  434. // valid range for this page.
  435. //
  436. if ( VectorOffset < (Cache -> GetNumberOfElements()) )
  437. {
  438. //
  439. // Update the allocation information.
  440. //
  441. Allocated ++;
  442. Available --;
  443. //
  444. // Turn on the bits indicating that this
  445. // element is in use.
  446. //
  447. (*VectorWord) |= AvailableMask;
  448. //
  449. // If the page is full we remove it
  450. // from the bucket list so we will no
  451. // longer look at it when we are
  452. // trying to find free space.
  453. //
  454. if ( Full() )
  455. { Cache -> DeleteFromBucketList( this ); }
  456. //
  457. // Add the element to the allocation array
  458. // so it can be returned to the caller.
  459. //
  460. Array[ (Requested - ((*Actual) ++) - 1) ] =
  461. (
  462. Cache -> ComputeAddress
  463. (
  464. Address,
  465. VectorOffset
  466. )
  467. );
  468. //
  469. // When we have got what we need we exit.
  470. //
  471. if ( ((*Actual) >= Requested) )
  472. { return True; }
  473. }
  474. else
  475. { break; }
  476. }
  477. else
  478. { Failure( "Bit vector is corrupt in MultipleNew" ); }
  479. }
  480. }
  481. }
  482. return ((*Actual) >= Requested);
  483. }
  484. /********************************************************************/
  485. /* */
  486. /* A single memory allocation. */
  487. /* */
  488. /* Allocate an available memeory element from the page. This */
  489. /* is done by scanning the bit vector looking for unallocated */
  490. /* slots. */
  491. /* */
  492. /********************************************************************/
  493. VOID *PAGE::New( BOOLEAN SubDivided )
  494. {
  495. //
  496. // We begin by making sure that there is at least
  497. // one element to allocate.
  498. //
  499. if ( ! Full() )
  500. {
  501. REGISTER SBIT16 SizeOfElements = (Cache -> GetSizeOfElements());
  502. //
  503. // Search the bit vector from low addresses to
  504. // high addresses looking for a free slot.
  505. // We keep a pointer to the first word with
  506. // a free element in 'FirstFree'. Sometimes
  507. // the current word may be fully allocated so
  508. // we might need to scan. However, there can
  509. // never be any free memory before this point
  510. // in the bit vector.
  511. //
  512. for ( /* void */;FirstFree < SizeOfElements;FirstFree ++ )
  513. {
  514. REGISTER BIT32 *VectorWord = & Vector[ FirstFree ];
  515. //
  516. // We scan the bit vector word at a time
  517. // looking for any free allocation slots.
  518. //
  519. if ( ((*VectorWord) & FullSearchMask) != FullSearchMask )
  520. {
  521. REGISTER BIT32 AvailableMask = WordSearchMask;
  522. REGISTER BIT32 Value = (*VectorWord);
  523. REGISTER SBIT32 WordOffset = 0;
  524. //
  525. // We know there is an at least one empty
  526. // slot availabale in the current word but
  527. // don't know which one We search for the
  528. // slot with the lowest address and stop
  529. // when we find it.
  530. //
  531. for
  532. (
  533. /* void */;
  534. (AvailableMask & Value) != 0;
  535. AvailableMask >>= OverheadBits, WordOffset ++
  536. );
  537. //
  538. // We should never fail to find a free
  539. // allocation slot so if we do then the
  540. // heap must be corrupt.
  541. //
  542. if ( WordOffset < OverheadBitsPerWord )
  543. {
  544. REGISTER SBIT32 VectorOffset =
  545. ((FirstFree * OverheadBitsPerWord) + WordOffset);
  546. //
  547. // We need to ensure that the element
  548. // we have chosen if not outside the
  549. // valid range for this page.
  550. //
  551. if ( VectorOffset < (Cache -> GetNumberOfElements()) )
  552. {
  553. //
  554. // Update the allocation information.
  555. //
  556. Allocated ++;
  557. Available --;
  558. //
  559. // Turn on the bit indicating that this
  560. // element is in use. If the allocation
  561. // is to be sub-divided then trun on this
  562. // bit as well.
  563. //
  564. (*VectorWord) |=
  565. (
  566. AvailableMask
  567. |
  568. (SubDivided ? (AvailableMask >> 1) : 0)
  569. );
  570. //
  571. // If the page is full we remove it
  572. // from the bucket list so we will no
  573. // longer look at it when we are
  574. // trying to find free space.
  575. //
  576. if ( Full() )
  577. { Cache -> DeleteFromBucketList( this ); }
  578. //
  579. // Return the address of the allocated
  580. // memory to the caller.
  581. //
  582. return
  583. (
  584. Cache -> ComputeAddress
  585. (
  586. Address,
  587. VectorOffset
  588. )
  589. );
  590. }
  591. }
  592. else
  593. { Failure( "Bit vector is corrupt in New" ); }
  594. }
  595. }
  596. #ifdef DEBUGGING
  597. if ( ! Full() )
  598. { Failure( "Available count corrupt in New" ); }
  599. #endif
  600. }
  601. return ((VOID*) AllocationFailure);
  602. }
  603. /********************************************************************/
  604. /* */
  605. /* Walk the heap. */
  606. /* */
  607. /* We have been asked to walk the heap. It is hard to know */
  608. /* why anybody might want to do this given the rest of the */
  609. /* functionality available. Nonetheless, we just do what is */
  610. /* required to keep everyone happy. */
  611. /* */
  612. /********************************************************************/
  613. BOOLEAN PAGE::Walk( SEARCH_PAGE *Details )
  614. {
  615. REGISTER BOOLEAN FreshPage = False;
  616. //
  617. // We have been handed the details of an allocation.
  618. // We need to walk along this allocation and find
  619. // the next non-subdivided allocation.
  620. do
  621. {
  622. //
  623. // We need to setup the heap walk if the address
  624. // is null so we skip the heap walk code.
  625. //
  626. if ( Details -> Address != NULL )
  627. {
  628. REGISTER SBIT32 Count;
  629. REGISTER SBIT32 End = Details -> Cache -> GetNumberOfElements();
  630. REGISTER SBIT32 Start = Details -> ArrayOffset;
  631. REGISTER PAGE *Page = Details -> Page;
  632. //
  633. // Walk the current page looking for a suitable
  634. // memory allocation to report to the user. When
  635. // we reach the end of the page we need to get
  636. // another page to walk.
  637. //
  638. for
  639. (
  640. Count = ((FreshPage) ? 0 : 1);
  641. (Start + Count) < End;
  642. Count ++
  643. )
  644. {
  645. //
  646. // Compute the new address.
  647. //
  648. Details -> Address =
  649. (
  650. Page -> Cache -> ComputeAddress
  651. (
  652. Page -> Address,
  653. (Start + Count)
  654. )
  655. );
  656. //
  657. // Compute the new allocation details.
  658. //
  659. Page -> FindPage
  660. (
  661. Details -> Address,
  662. Details,
  663. False
  664. );
  665. //
  666. // We skip all sub-divided allocations as they
  667. // will get reported elsewhere.
  668. //
  669. if (! ((*Details -> VectorWord) & Details -> SubDivisionMask) )
  670. { return True; }
  671. }
  672. }
  673. //
  674. // Update the flag to show that we have
  675. // had to go and get a new page.
  676. //
  677. FreshPage = True;
  678. }
  679. while ( Details -> Cache -> Walk( Details ) );
  680. return False;
  681. }
  682. /********************************************************************/
  683. /* */
  684. /* Class destructor. */
  685. /* */
  686. /* Destory the current page structure. */
  687. /* */
  688. /********************************************************************/
  689. PAGE::~PAGE( VOID )
  690. {
  691. #ifdef DEBUGGING
  692. //
  693. // Destroy the page structure.
  694. //
  695. Address = NULL;
  696. PageSize = 0;
  697. ParentPage = NULL;
  698. Allocated = 0;
  699. Available = 0;
  700. FirstFree = 0;
  701. #endif
  702. //
  703. // We update the version number whenever a page is created
  704. // or destroyed. We use the version number to ensure that
  705. // a page has not been deleteed and/or recreated between
  706. // releasing one lock and claiming a another other lock.
  707. //
  708. Version ++;
  709. }