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.

1262 lines
37 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 "New.hpp"
  27. #include "NewPage.hpp"
  28. #include "Rockall.hpp"
  29. /********************************************************************/
  30. /* */
  31. /* Constants local to the class. */
  32. /* */
  33. /* The constants set overall limits on the number and size of */
  34. /* page descriptions for pages within the memory allocator. */
  35. /* */
  36. /********************************************************************/
  37. CONST SBIT32 MinNewPages = 1;
  38. CONST SBIT32 VectorRange = ((2 << 15) - 1);
  39. /********************************************************************/
  40. /* */
  41. /* Class constructor. */
  42. /* */
  43. /* A 'PAGE' structure has various fixed fields and a variable */
  44. /* sized allocation bit vector. When this class is initialized */
  45. /* the user is required to supply us with an array that details */
  46. /* the sizes of allocation bit vectors supported. */
  47. /* */
  48. /********************************************************************/
  49. NEW_PAGE::NEW_PAGE
  50. (
  51. FIND *NewFind,
  52. SBIT32 NewPageSizes[],
  53. ROCKALL *NewRockall,
  54. SBIT32 Size,
  55. BOOLEAN NewThreadSafe
  56. )
  57. {
  58. REGISTER SBIT32 DefaultRootSize = (NewRockall -> NaturalSize());
  59. REGISTER SBIT32 ReservedBytes = (Size * sizeof(NEW_PAGES));
  60. REGISTER SBIT32 SpareBytes = (DefaultRootSize - ReservedBytes);
  61. REGISTER SBIT32 StackSize = (SpareBytes / sizeof(VOID*));
  62. //
  63. // We need to make sure that we appear to have a valid
  64. // array of 'NewPageSizes' and that the bit vector sizes
  65. // do not exceed the memory addressing range.
  66. //
  67. if
  68. (
  69. PowerOfTwo( DefaultRootSize )
  70. &&
  71. (DefaultRootSize >= PageSize())
  72. &&
  73. (Size >= MinNewPages)
  74. &&
  75. ((NewPageSizes[ (Size-1) ] * OverheadBitsPerWord) <= VectorRange)
  76. )
  77. {
  78. REGISTER VOID *NewMemory =
  79. (
  80. NewRockall -> NewArea
  81. (
  82. (DefaultRootSize-1),
  83. DefaultRootSize,
  84. False
  85. )
  86. );
  87. //
  88. // We are in big trouble if we can not allocate space
  89. // to store this initial control information. If the
  90. // allocation fails we are forced to exit and the whole
  91. // memory allocator becomes unavailable.
  92. //
  93. if ( NewMemory != AllocationFailure )
  94. {
  95. REGISTER SBIT32 Count;
  96. REGISTER SBIT32 LastSize = 0;
  97. //
  98. // We are now ready to setup the configuration
  99. // information.
  100. //
  101. MaxCacheStack = 0;
  102. MaxNewPages = Size;
  103. MaxStack = StackSize;
  104. NaturalSize = DefaultRootSize;
  105. RootCoreSize = DefaultRootSize;
  106. RootStackSize = 0;
  107. ThreadSafe = NewThreadSafe;
  108. TopOfStack = 0;
  109. Version = 0;
  110. CacheStack = NULL;
  111. NewPages = ((NEW_PAGES*) NewMemory);
  112. Stack = ((VOID**) & NewPages[ Size ]);
  113. Find = NewFind;
  114. Rockall = NewRockall;
  115. TopCache = NULL;
  116. //
  117. // Create a lists for the various page
  118. // sizes and prepare them for use.
  119. //
  120. for ( Count=0;Count < Size;Count ++ )
  121. {
  122. REGISTER SBIT32 CurrentSize = NewPageSizes[ Count ];
  123. if ( CurrentSize > LastSize )
  124. {
  125. REGISTER NEW_PAGES *NewPage = & NewPages[ Count ];
  126. //
  127. // Create a list for the current
  128. // size and fill in all the related
  129. // details.
  130. //
  131. NewPage -> Elements = (CurrentSize * OverheadBitsPerWord);
  132. PLACEMENT_NEW( & NewPage -> ExternalList,LIST );
  133. PLACEMENT_NEW( & NewPage -> FullList,LIST );
  134. PLACEMENT_NEW( & NewPage -> FreeList,LIST );
  135. NewPage -> Size = (CurrentSize * sizeof(BIT32));
  136. LastSize = CurrentSize;
  137. }
  138. else
  139. { Failure( "Sizes in constructor for NEW_PAGES" ); }
  140. }
  141. }
  142. else
  143. { Failure( "No memory in constructor for NEW_PAGES" ); }
  144. }
  145. else
  146. { Failure( "Setup of pages in constructor for NEW_PAGES" ); }
  147. }
  148. /********************************************************************/
  149. /* */
  150. /* Create a new page. */
  151. /* */
  152. /* Create a new 'PAGE' structure and prepare it for use. If */
  153. /* we don't already have any pages of the required size then */
  154. /* allocate memory, create new 'PAGE' structures and link them */
  155. /* into the appropriate free chain. */
  156. /* */
  157. /********************************************************************/
  158. PAGE *NEW_PAGE::CreatePage( CACHE *Cache,SBIT32 NewSize )
  159. {
  160. REGISTER PAGE *NewPage = ((PAGE*) AllocationFailure);
  161. REGISTER SBIT16 SizeKey = (Cache -> GetSizeKey());
  162. //
  163. // All allocations are made from fixed sized
  164. // pages. These pages have a bit vector to
  165. // keep track of which elements are allocated
  166. // and available. The 'SizeKey' is an index
  167. // into 'NewPages[]' that will supply a page
  168. // that has a big enough the bit vector.
  169. //
  170. #ifdef DEBUGGING
  171. if ( (SizeKey >= 0) && (SizeKey < MaxNewPages) )
  172. {
  173. #endif
  174. REGISTER NEW_PAGES *Current;
  175. //
  176. // When there is a potential for multiple threads
  177. // we claim the lock.
  178. //
  179. ClaimNewPageLock();
  180. //
  181. // We allocate 'PAGE' structures as we need them
  182. // and link them together in the free list.
  183. // If we don't have any structures available we
  184. // allocate some more and add tem to the list.
  185. //
  186. if ( (Current = & NewPages[ SizeKey ]) -> FreeList.EndOfList() )
  187. {
  188. REGISTER SBIT32 ArrayElements = (Current -> Size - MinVectorSize);
  189. REGISTER SBIT32 ArraySize = (ArrayElements * sizeof(BIT32));
  190. REGISTER SBIT32 TotalSize = (sizeof(PAGE) + ArraySize);
  191. REGISTER SBIT32 FinalSize = CacheAlignSize( TotalSize );
  192. REGISTER SBIT32 TotalPages = (NaturalSize / FinalSize);
  193. //
  194. // Nasty, we have run out of stack space. If
  195. // we can not grow this table then the heap
  196. // will not be able to expand any further.
  197. //
  198. if ( TopOfStack >= MaxStack )
  199. {
  200. //
  201. // Try to grow the stack size.
  202. //
  203. ResizeStack();
  204. //
  205. // Update the pointer as the table may
  206. // have moved.
  207. //
  208. Current = & NewPages[ SizeKey ];
  209. }
  210. //
  211. // We may find ourseleves in a situation where
  212. // the size of the new 'PAGE' structure is larger
  213. // than the natural allocation size or the stack
  214. // is full so we can't create new pages. If so we
  215. // refuse to create any new pages so any allocation
  216. // requests for this size will fail.
  217. //
  218. if ( (TotalPages > 0) && (TopOfStack < MaxStack) )
  219. {
  220. REGISTER CHAR *NewMemory =
  221. ((CHAR*) VerifyNewArea( (NaturalSize-1),NaturalSize ));
  222. //
  223. // We may also find ourselves unable to
  224. // anymore memory. If so we will fail the
  225. // request to create a page.
  226. //
  227. if ( NewMemory != AllocationFailure )
  228. {
  229. REGISTER SBIT32 Count;
  230. //
  231. // Add the new allocation to stack of
  232. // outstanding external allocations.
  233. //
  234. Stack[ (TopOfStack ++) ] = ((VOID*) NewMemory);
  235. //
  236. // Add the new elements to the free list
  237. // for the current allocation size.
  238. //
  239. for
  240. (
  241. Count=0;
  242. Count < TotalPages;
  243. Count ++, (NewMemory += FinalSize)
  244. )
  245. {
  246. REGISTER PAGE *Page = ((PAGE*) NewMemory);
  247. //
  248. // The page has been allocated but not
  249. // initialized so call the constructor
  250. // and the destructor to get it into
  251. // a sane state.
  252. //
  253. PLACEMENT_NEW( NewPage,PAGE )
  254. (
  255. NULL,
  256. NULL,
  257. 0,
  258. NULL,
  259. 0
  260. );
  261. PLACEMENT_DELETE( Page,PAGE );
  262. //
  263. // Finally add the page to the free list
  264. // so it can be used.
  265. //
  266. Page -> InsertInNewPageList( & Current -> FreeList );
  267. }
  268. }
  269. }
  270. }
  271. //
  272. // We are now ready to create a new allocation
  273. // page. We start by requesting a page from
  274. // the parent bucket. If this works we know that
  275. // we have almost everthing we need to create the
  276. // new page.
  277. //
  278. if ( ! Current -> FreeList.EndOfList() )
  279. {
  280. REGISTER VOID *NewMemory;
  281. REGISTER CACHE *ParentPage = (Cache -> GetParentCache());
  282. NewPage = (PAGE::FirstInNewPageList( & Current -> FreeList ));
  283. //
  284. // We have found a suitable page structure
  285. // so remove it from the free list.
  286. //
  287. NewPage -> DeleteFromNewPageList( & Current -> FreeList );
  288. //
  289. // Release any lock we might have as another
  290. // thread may be waiting to delete a page and
  291. // be holding the lock we need in order to
  292. // create a page.
  293. //
  294. ReleaseNewPageLock();
  295. //
  296. // We need to allocate memory to store the users
  297. // data. After all we are the memory allocator
  298. // and that is our job in life. Typically, we do
  299. // this by making a recursive internal request
  300. // from a larger bucket. Nonetheless, at some point
  301. // we will reach the 'TopCache' and will be forced
  302. // to request memory from an external source.
  303. //
  304. if ( (Cache -> TopCache()) || (NewSize != NoSize) )
  305. {
  306. REGISTER AlignMask = (TopCache -> GetPageSize()-1);
  307. //
  308. // We allocate memory externally in large blocks
  309. // and sub-divide these allocations into smaller
  310. // blocks. The only exception is if the caller
  311. // caller is requesting some weird size in which
  312. // case we request memory directly from the
  313. // external allocator (usually the OS).
  314. //
  315. if ( NewSize == NoSize )
  316. { NewSize = (Cache -> GetPageSize()); }
  317. //
  318. // All externally allocated memory belongs
  319. // to the global root. Thus, it will be
  320. // found in the first lookup in the find
  321. // table.
  322. //
  323. ParentPage = ((CACHE*) GlobalRoot);
  324. //
  325. // Allocate from the external allocator.
  326. //
  327. NewMemory = (VerifyNewArea( AlignMask,NewSize ));
  328. }
  329. else
  330. {
  331. //
  332. // Allocate memory from a larger cache and then
  333. // sub-divide it as needed.
  334. //
  335. NewMemory =
  336. (Cache -> GetParentCache() -> CreateDataPage());
  337. }
  338. //
  339. // Reclaim any lock we have had earlier so
  340. // we can update the the new page structure.
  341. //
  342. ClaimNewPageLock();
  343. //
  344. // Lets make sure we sucessfully allocated the
  345. // memory for the data page.
  346. //
  347. if ( NewMemory != AllocationFailure )
  348. {
  349. //
  350. // We now have everything we need so lets
  351. // create a new page.
  352. //
  353. PLACEMENT_NEW( NewPage,PAGE )
  354. (
  355. NewMemory,
  356. Cache,
  357. NewSize,
  358. ParentPage,
  359. (Version += 2)
  360. );
  361. //
  362. // Finally lets add the new page to the various
  363. // lists so we can quickly find it again later.
  364. //
  365. Cache -> InsertInBucketList( NewPage );
  366. Cache -> InsertInFindList( NewPage );
  367. NewPage -> InsertInNewPageList
  368. (
  369. (Cache -> TopCache())
  370. ? & Current -> ExternalList
  371. : & Current -> FullList
  372. );
  373. }
  374. else
  375. {
  376. //
  377. // We were unable to allocate any data space
  378. // for this new page so lets free the page
  379. // description and exit.
  380. //
  381. NewPage -> InsertInNewPageList( & Current -> FreeList );
  382. NewPage = ((PAGE*) AllocationFailure);
  383. }
  384. }
  385. //
  386. // We have finished so release the lock now.
  387. //
  388. ReleaseNewPageLock();
  389. #ifdef DEBUGGING
  390. }
  391. else
  392. { Failure( "The page size key is out of range" ); }
  393. #endif
  394. return NewPage;
  395. }
  396. /********************************************************************/
  397. /* */
  398. /* Delete all allocations. */
  399. /* */
  400. /* Delete an entire heap and return all the memory to the */
  401. /* top level pool or the external allocator (usually the OS). */
  402. /* */
  403. /********************************************************************/
  404. VOID NEW_PAGE::DeleteAll( BOOLEAN Recycle )
  405. {
  406. REGISTER SBIT32 Count;
  407. //
  408. // Claim the global lock so that the various
  409. // lists can be updated.
  410. //
  411. ClaimNewPageLock();
  412. //
  413. // We assume at this point that we have blocked
  414. // all memory allocation and dealloction requests.
  415. // We are now going to walk through the various lists
  416. // and just blow away things. We are going to
  417. // do this in a tidy way just in case the caller
  418. // wants to use the heap again later.
  419. //
  420. for ( Count=0;Count < MaxNewPages;Count ++ )
  421. {
  422. REGISTER NEW_PAGES *Current = & NewPages[ Count ];
  423. REGISTER PAGE *Page;
  424. REGISTER PAGE *NextPage;
  425. //
  426. // All allocations that appear in the full list
  427. // have been sub-allocated from larger pages in
  428. // almost all cases.
  429. //
  430. for
  431. (
  432. Page = (PAGE::FirstInNewPageList( & Current -> FullList ));
  433. ! Page -> EndOfNewPageList();
  434. Page = NextPage
  435. )
  436. {
  437. REGISTER VOID *Address = (Page -> GetAddress());
  438. REGISTER CACHE *Cache = (Page -> GetCache());
  439. REGISTER SBIT32 PageSize = (Page -> GetPageSize());
  440. //
  441. // We decide here how we will deal with the page.
  442. // If it is empty, non-standard or we are not
  443. // recycling we will blow it away. If not we
  444. // simply reset it for later use.
  445. //
  446. if ( (Page -> Empty()) || (PageSize != NoSize) || (! Recycle) )
  447. {
  448. //
  449. // We need to release any associated data page.
  450. // If this is the top level then release the
  451. // memory back to the external allocator. If
  452. // not we release it back to the parent bucket.
  453. //
  454. if ( PageSize == NoSize )
  455. {
  456. //
  457. // If we are just recycling then we cleanly
  458. // delete the page. If not then we know it
  459. // will be blown away later so why bother.
  460. //
  461. if ( Recycle )
  462. {
  463. REGISTER CACHE *ParentCache =
  464. (Cache -> GetParentCache());
  465. if ( ! (ParentCache -> DeleteDataPage( Address )) )
  466. { Failure( "Reset data page in DeleteAll" ); }
  467. }
  468. }
  469. else
  470. { Rockall -> DeleteArea( Address,PageSize,True ); }
  471. //
  472. // We may have been blowing away pages
  473. // randomly and now we are about to destroy
  474. // the current page. So lets figure out
  475. // what page comes next before we continue.
  476. //
  477. NextPage = (Page -> NextInNewPageList());
  478. //
  479. // If the page is not full it will in a
  480. // bucket list somewhere. We need to remove
  481. // it as we are about to delete the page.
  482. //
  483. if ( ! Page -> Full() )
  484. { Cache -> DeleteFromBucketList( Page ); }
  485. //
  486. // Delete the page from the find list and the
  487. // new page list.
  488. //
  489. Cache -> DeleteFromFindList( Page );
  490. Page -> DeleteFromNewPageList( & Current -> FullList );
  491. //
  492. // Delete the page structure.
  493. //
  494. PLACEMENT_DELETE( Page,PAGE );
  495. //
  496. // Finally add the page to the free list
  497. // so it can be recycled.
  498. //
  499. Page -> InsertInNewPageList( & Current -> FreeList );
  500. }
  501. else
  502. {
  503. //
  504. // We know that the current page has at
  505. // least one allocation on it so instead
  506. // of deleting it we will mark it as free
  507. // (except for any sub-allocations) and
  508. // leave it around for next time. If it
  509. // is never used the next top level
  510. // 'DeleteAll' will delete it.
  511. //
  512. Page -> DeleteAll();
  513. //
  514. // We have now reset the current page so
  515. // lets figure out what page comes next.
  516. //
  517. NextPage = (Page -> NextInNewPageList());
  518. }
  519. }
  520. //
  521. // We have a choice to make. If we intend to
  522. // use this heap again we keep all top level
  523. // allocated memory in a list ready for reuse.
  524. // If not we return it to the external allocator
  525. // (usually the OS).
  526. //
  527. if ( ! Recycle )
  528. {
  529. //
  530. // The external allocations list contains an
  531. // entry for every externally allocated page
  532. // except those allocated for special internal
  533. // use within this class or for weird sized
  534. // pages that appeared above in the 'FullList'.
  535. //
  536. for
  537. (
  538. Page = (PAGE::FirstInNewPageList( & Current -> ExternalList ));
  539. ! Page -> EndOfNewPageList();
  540. Page = (PAGE::FirstInNewPageList( & Current -> ExternalList ))
  541. )
  542. {
  543. REGISTER VOID *Address = (Page -> GetAddress());
  544. REGISTER CACHE *Cache = (Page -> GetCache());
  545. REGISTER SBIT32 PageSize = (Page -> GetPageSize());
  546. //
  547. // We no longer need this top level allocation
  548. // so return it to the external allocator.
  549. //
  550. Rockall -> DeleteArea( Address,PageSize,True );
  551. //
  552. // If the page is not full it will in a
  553. // bucket list somewhere. We need to remove
  554. // it as we are about to delete the page.
  555. //
  556. if ( ! Page -> Full() )
  557. { Cache -> DeleteFromBucketList( Page ); }
  558. //
  559. // Delete the page from the find list and the
  560. // new page list.
  561. //
  562. Cache -> DeleteFromFindList( Page );
  563. Page -> DeleteFromNewPageList( & Current -> ExternalList );
  564. //
  565. // Delete the page structure.
  566. //
  567. PLACEMENT_DELETE( Page,PAGE );
  568. //
  569. // Finally add the page to the free list
  570. // so it can be recycled.
  571. //
  572. Page -> InsertInNewPageList( & Current -> FreeList );
  573. }
  574. }
  575. }
  576. //
  577. // We have finished so release the lock now.
  578. //
  579. ReleaseNewPageLock();
  580. }
  581. /********************************************************************/
  582. /* */
  583. /* Delete a page. */
  584. /* */
  585. /* Delete a page structure, free the associated memory and */
  586. /* unlink it from the various allocation lists. */
  587. /* */
  588. /********************************************************************/
  589. VOID NEW_PAGE::DeletePage( PAGE *Page )
  590. {
  591. REGISTER CACHE *Cache = Page -> GetCache();
  592. REGISTER SBIT16 SizeKey = Cache -> GetSizeKey();
  593. //
  594. // All allocations are made from fixed sized
  595. // pages. These pages have a bit vector to
  596. // keep track of which elements are allocated
  597. // and available. The 'SizeKey' is an index
  598. // into 'NewPages[]' that will supply a page
  599. // that has a big enough the bit vector.
  600. //
  601. #ifdef DEBUGGING
  602. if ( (SizeKey >= 0) && (SizeKey < MaxNewPages) )
  603. {
  604. #endif
  605. REGISTER VOID *Address = (Page -> GetAddress());
  606. REGISTER NEW_PAGES *Current = & NewPages[ SizeKey ];
  607. REGISTER SBIT32 Size = (Page -> GetPageSize());
  608. //
  609. // We need to release any associated data page.
  610. // If this is the top level then release the
  611. // memory back to the external allocator. If
  612. // not we release it back to the parent bucket.
  613. //
  614. if ( Size == NoSize )
  615. {
  616. REGISTER CACHE *ParentCache = (Cache -> GetParentCache());
  617. if ( ! (ParentCache -> DeleteDataPage( Address )) )
  618. { Failure( "Deleting data page in DeletePage" ); }
  619. }
  620. else
  621. { Rockall -> DeleteArea( Address,Size,True ); }
  622. //
  623. // Claim the global lock so that the various
  624. // lists can be updated.
  625. //
  626. ClaimNewPageLock();
  627. //
  628. // Remove the page from the lists and delete it.
  629. //
  630. Cache -> DeleteFromBucketList( Page );
  631. Cache -> DeleteFromFindList( Page );
  632. Page -> DeleteFromNewPageList
  633. (
  634. (Cache -> TopCache())
  635. ? & Current -> ExternalList
  636. : & Current -> FullList
  637. );
  638. PLACEMENT_DELETE( Page,PAGE );
  639. //
  640. // Finally add the page to the free list
  641. // so it can be recycled.
  642. //
  643. Page -> InsertInNewPageList( & Current -> FreeList );
  644. //
  645. // We have finsihed so release the lock.
  646. //
  647. ReleaseNewPageLock();
  648. #ifdef DEBUGGING
  649. }
  650. else
  651. { Failure( "The page size key out of range in DeletePage" ); }
  652. #endif
  653. }
  654. /********************************************************************/
  655. /* */
  656. /* Find the correct index in new page. */
  657. /* */
  658. /* When we come to create a new page we need to make sure the */
  659. /* bit vector is large enough for the page. We calculate this */
  660. /* here just once to save time later. */
  661. /* */
  662. /********************************************************************/
  663. SBIT16 NEW_PAGE::FindSizeKey( SBIT16 NumberOfElements )
  664. {
  665. REGISTER SBIT32 Count;
  666. //
  667. // Search the table of page structures looking for
  668. // elements of a suitable size. As the table is
  669. // known to be in order of increasing size we can
  670. // terminate the search as soon as we find something
  671. // large enough.
  672. //
  673. for ( Count=0;Count < MaxNewPages;Count ++ )
  674. {
  675. REGISTER NEW_PAGES *Current = & NewPages[ Count ];
  676. if ( NumberOfElements <= Current -> Elements )
  677. { return ((SBIT16) Count); }
  678. }
  679. //
  680. // Nasty, we don't seem to have anything large enough
  681. // to store the bit vector.
  682. //
  683. return NoSizeKey;
  684. }
  685. /********************************************************************/
  686. /* */
  687. /* Create a new cache stack. */
  688. /* */
  689. /* A cache stack is an array that contains memory allocations */
  690. /* that are waiting to be allocated or released. */
  691. /* */
  692. /********************************************************************/
  693. VOID *NEW_PAGE::NewCacheStack( SBIT32 Size )
  694. {
  695. REGISTER VOID *NewStack;
  696. //
  697. // Claim the global lock so that the various
  698. // lists can be updated.
  699. //
  700. ClaimNewPageLock();
  701. //
  702. // We ensure that there is enough space to make the
  703. // allocation. If not we request additional space
  704. // and prepare it for use.
  705. //
  706. if ( (CacheStack == NULL) || ((MaxCacheStack + Size) > NaturalSize) )
  707. {
  708. //
  709. // Nasty, we have run out of stack space. If
  710. // we can not grow this table then the heap
  711. // will not be able to expand any further.
  712. //
  713. if ( TopOfStack >= MaxStack )
  714. {
  715. //
  716. // Try to grow the stack size.
  717. //
  718. ResizeStack();
  719. }
  720. //
  721. // We may find ourseleves in a situation where
  722. // the size of the new stack structure is larger
  723. // than the natural allocation size or the stack
  724. // is full so we can't create new pages. If so we
  725. // refuse to create any new stacks.
  726. //
  727. if ( (Size < NaturalSize) && (TopOfStack < MaxStack) )
  728. {
  729. REGISTER CHAR *NewMemory =
  730. ((CHAR*) VerifyNewArea( (NaturalSize-1),NaturalSize ));
  731. //
  732. // We may also find ourselves unable to
  733. // anymore memory. If so we will fail the
  734. // request to create a new cache stack.
  735. //
  736. if ( NewMemory != AllocationFailure )
  737. {
  738. //
  739. // Add the new allocation to stack of
  740. // outstanding external allocations.
  741. //
  742. Stack[ (TopOfStack ++) ] = ((VOID*) NewMemory);
  743. //
  744. // Prepare the new memory block for use.
  745. //
  746. CacheStack = NewMemory;
  747. MaxCacheStack = 0;
  748. }
  749. else
  750. { return NULL; }
  751. }
  752. else
  753. { return NULL; }
  754. }
  755. //
  756. // We allocate some space for the new cache
  757. // stack and update and align the high water
  758. // mark of the space used.
  759. //
  760. NewStack = ((VOID*) & CacheStack[ MaxCacheStack ]);
  761. MaxCacheStack += (Size + CacheLineMask);
  762. MaxCacheStack &= ~CacheLineMask;
  763. //
  764. // We have finished so release the lock now.
  765. //
  766. ReleaseNewPageLock();
  767. return NewStack;
  768. }
  769. /********************************************************************/
  770. /* */
  771. /* Resize the new page stack. */
  772. /* */
  773. /* The new page stack holds pointers to all the pages owned */
  774. /* by the heap. If this stack become full we must expand it */
  775. /* otherwise we can no longer grow the heap. */
  776. /* */
  777. /********************************************************************/
  778. VOID NEW_PAGE::ResizeStack( VOID )
  779. {
  780. REGISTER SBIT32 NewSize =
  781. (((RootStackSize <= 0) ? NaturalSize : RootStackSize) * 2);
  782. //
  783. // Lets just check that we have really run out
  784. // of stack space as expanding it really hurts.
  785. //
  786. if ( TopOfStack >= MaxStack )
  787. {
  788. REGISTER VOID *NewMemory =
  789. (
  790. Rockall -> NewArea
  791. (
  792. (NaturalSize-1),
  793. NewSize,
  794. False
  795. )
  796. );
  797. //
  798. // We need to verify that we were able to allocate
  799. // fresh memory for the stack.
  800. //
  801. if ( NewMemory != NULL )
  802. {
  803. REGISTER BOOLEAN DeleteStack = (RootStackSize > 0);
  804. REGISTER VOID *OriginalMemory = ((VOID*) Stack);
  805. REGISTER SBIT32 OriginalSize = (MaxStack * sizeof(VOID*));
  806. //
  807. // All is well as we were able to allocate
  808. // additional space for the stack. All we
  809. // need to do now is to update the control
  810. // information.
  811. //
  812. MaxStack = (NewSize / sizeof(VOID*));
  813. RootStackSize = NewSize;
  814. Stack = ((VOID**) NewMemory);
  815. //
  816. // Now lets copy across the existing data.
  817. //
  818. memcpy( NewMemory,OriginalMemory,OriginalSize );
  819. //
  820. // When the heap is created we put the
  821. // stack on the root core page. Later
  822. // we may move it if we expand it. If
  823. // this is the case we have to delete
  824. // the previous expansion here.
  825. //
  826. if ( DeleteStack )
  827. {
  828. //
  829. // Deallocate the existing stack if it
  830. // is not on the root core page.
  831. //
  832. Rockall -> DeleteArea( OriginalMemory,OriginalSize,False );
  833. }
  834. }
  835. }
  836. }
  837. /********************************************************************/
  838. /* */
  839. /* Verify an external allocation. */
  840. /* */
  841. /* All memory requests are allocated from the external allocator */
  842. /* at the highest level. Here we have a wrapper for this */
  843. /* function so we can test the result and make sure it is sane. */
  844. /* */
  845. /********************************************************************/
  846. VOID *NEW_PAGE::VerifyNewArea( SBIT32 AlignMask,SBIT32 Size )
  847. {
  848. #ifdef DEBUGGING
  849. //
  850. // We need to ensure that the alignment of the new
  851. // external allocation is a power of two.
  852. //
  853. if ( PowerOfTwo( (AlignMask + 1) ) )
  854. {
  855. #endif
  856. REGISTER VOID *NewMemory =
  857. (Rockall -> NewArea( AlignMask,Size,True ));
  858. //
  859. // We need to ensure that the external allocation
  860. // request is sucessful. If not it makes no sense
  861. // to try and check it.
  862. //
  863. if ( NewMemory != ((VOID*) AllocationFailure) )
  864. {
  865. //
  866. // We require the external memory allocator to always
  867. // allocate memory on the requested boundary. If not
  868. // we are forced to reject the supplied memory.
  869. //
  870. if ( (((SBIT32) NewMemory) & AlignMask) == 0 )
  871. { return NewMemory; }
  872. else
  873. {
  874. Rockall -> DeleteArea( NewMemory,Size,True );
  875. Failure( "Alignment of allocation in VerifyNewArea" );
  876. }
  877. }
  878. #ifdef DEBUGGING
  879. }
  880. else
  881. { Failure( "Alignment is not a power of two in VerifyNewArea" ); }
  882. #endif
  883. return ((VOID*) AllocationFailure);
  884. }
  885. /********************************************************************/
  886. /* */
  887. /* Walk the heap. */
  888. /* */
  889. /* We have been asked to walk the heap. It is hard to know */
  890. /* why anybody might want to do this given the rest of the */
  891. /* functionality available. Nonetheless, we just do what is */
  892. /* required to keep everyone happy. */
  893. /* */
  894. /********************************************************************/
  895. BOOLEAN NEW_PAGE::Walk( SEARCH_PAGE *Details )
  896. {
  897. //
  898. // Claim the global lock so that the various
  899. // lists can be updated.
  900. //
  901. ClaimNewPageLock();
  902. //
  903. // We examine the current address to see if it
  904. // is null. If so then this is the start of a
  905. // heap walk so we need to set it up.
  906. //
  907. if ( Details -> Address == NULL )
  908. {
  909. REGISTER SBIT32 Count;
  910. //
  911. // Walk through the list of different sized
  912. // page descriptions.
  913. //
  914. for ( Count=0;Count < MaxNewPages;Count ++ )
  915. {
  916. REGISTER NEW_PAGES *Current = & NewPages[ Count ];
  917. //
  918. // Compute a pointer to the first element
  919. // of the current size.
  920. //
  921. Details -> Page =
  922. (PAGE::FirstInNewPageList( & Current -> FullList ));
  923. //
  924. // Examine the current list of full (or
  925. // partially full) pages. If there is at
  926. // least one page then this is the starting
  927. // point for the heap walk.
  928. //
  929. if ( ! Details -> Page -> EndOfNewPageList() )
  930. {
  931. //
  932. // Compute the starting address of the
  933. // heap walk.
  934. //
  935. Details -> Address =
  936. (Details -> Page -> GetAddress());
  937. break;
  938. }
  939. }
  940. }
  941. else
  942. {
  943. REGISTER PAGE *LastPage = Details -> Page;
  944. //
  945. // We have exhusted the current page so walk
  946. // the list and find the next page.
  947. //
  948. Details -> Page =
  949. (Details -> Page -> NextInNewPageList());
  950. //
  951. // We need to ensure that we have not reached
  952. // the end of the current list.
  953. //
  954. if ( Details -> Page -> EndOfNewPageList() )
  955. {
  956. REGISTER SBIT32 Count;
  957. REGISTER BOOLEAN Found = False;
  958. //
  959. // We need to find a new page description
  960. // list to walk so reset the current
  961. // address just in case we don't find
  962. // anything.
  963. //
  964. Details -> Address = NULL;
  965. //
  966. // We have reached the end of the current
  967. // list and we need to continue with the
  968. // start of the next list. However, we
  969. // don't know which list we were using
  970. // previously. So first we identify the
  971. // previous list and then select the next
  972. // avaibale list.
  973. //
  974. for ( Count=0;Count < MaxNewPages;Count ++ )
  975. {
  976. REGISTER NEW_PAGES *Current = & NewPages[ Count ];
  977. //
  978. // We search for the original list
  979. // we were walking.
  980. //
  981. if ( ! Found )
  982. {
  983. //
  984. // When we find the original list
  985. // then we set a flag showing that
  986. // the next available list is the
  987. // target.
  988. //
  989. if
  990. (
  991. LastPage
  992. ==
  993. (PAGE::LastInNewPageList( & Current -> FullList ))
  994. )
  995. { Found = True; }
  996. }
  997. else
  998. {
  999. //
  1000. // We have found the previous list
  1001. // so the first element of the next
  1002. // list seems a good place to continue.
  1003. //
  1004. Details -> Page =
  1005. (PAGE::FirstInNewPageList( & Current -> FullList ));
  1006. //
  1007. // We check to make sure that the list
  1008. // has at least one active page. If not
  1009. // it is worthless and we continue looking
  1010. // for a suitable list.
  1011. //
  1012. if ( ! Details -> Page -> EndOfNewPageList() )
  1013. {
  1014. //
  1015. // Compute the starting address for
  1016. // the next page in the heap walk.
  1017. //
  1018. Details -> Address =
  1019. (Details -> Page -> GetAddress());
  1020. break;
  1021. }
  1022. }
  1023. }
  1024. }
  1025. else
  1026. {
  1027. //
  1028. // Compute the starting address for
  1029. // the next page in the heap walk.
  1030. //
  1031. Details -> Address =
  1032. (Details -> Page -> GetAddress());
  1033. }
  1034. }
  1035. //
  1036. // If we find a new heap page to walk we update
  1037. // the details. We mark some entry's as exhusted
  1038. // so as to provoke other code to set them up.
  1039. //
  1040. if ( Details -> Address != NULL )
  1041. {
  1042. //
  1043. // Compute the new allocation details.
  1044. //
  1045. Details -> Page -> FindPage
  1046. (
  1047. Details -> Address,
  1048. Details,
  1049. False
  1050. );
  1051. }
  1052. //
  1053. // We have finished so release the lock now.
  1054. //
  1055. ReleaseNewPageLock();
  1056. return (Details -> Address != NULL);
  1057. }
  1058. /********************************************************************/
  1059. /* */
  1060. /* Class destructor. */
  1061. /* */
  1062. /* Destory all the page structures and release any allocated */
  1063. /* memory. */
  1064. /* */
  1065. /********************************************************************/
  1066. NEW_PAGE::~NEW_PAGE( VOID )
  1067. {
  1068. REGISTER SBIT32 Count;
  1069. //
  1070. // Delete all active allocations.
  1071. //
  1072. DeleteAll( False );
  1073. //
  1074. // We are about to delete all of the memory
  1075. // allocated by this class so destroy any
  1076. // internal pointers.
  1077. //
  1078. MaxCacheStack = 0;
  1079. CacheStack = NULL;
  1080. //
  1081. // We have now deleted all the memory allocated by
  1082. // this heap except for the memory allocated directly
  1083. // by this class. Here we finish off the job by
  1084. // deleting these allocations and reseting the internal
  1085. // data structures.
  1086. //
  1087. for ( Count=0;Count < TopOfStack;Count ++ )
  1088. {
  1089. REGISTER VOID *Current = Stack[ Count ];
  1090. Rockall -> DeleteArea( Current,NaturalSize,False );
  1091. }
  1092. TopOfStack = 0;
  1093. //
  1094. // If we were forced to expand the root stack then
  1095. // release this additional memory now.
  1096. //
  1097. if ( RootStackSize > 0 )
  1098. {
  1099. //
  1100. // Deallocate root stack which previously
  1101. // contained pointers to all the memory
  1102. // allocated by this class.
  1103. //
  1104. Rockall -> DeleteArea( ((VOID*) Stack),RootStackSize,False );
  1105. }
  1106. //
  1107. // Delete all the new page list headings just
  1108. // to be neat
  1109. //
  1110. for ( Count=0;Count < MaxNewPages;Count ++ )
  1111. {
  1112. REGISTER NEW_PAGES *Current = & NewPages[ Count ];
  1113. PLACEMENT_DELETE( & Current -> ExternalList,LIST );
  1114. PLACEMENT_DELETE( & Current -> FullList,LIST );
  1115. PLACEMENT_DELETE( & Current -> FreeList,LIST );
  1116. }
  1117. //
  1118. // Deallocate root core page which previously
  1119. // contained all the new page lists.
  1120. //
  1121. Rockall -> DeleteArea( ((VOID*) NewPages),RootCoreSize,False );
  1122. }