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.

1745 lines
50 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 "Find.hpp"
  27. #include "Heap.hpp"
  28. /********************************************************************/
  29. /* */
  30. /* Constants local to the class. */
  31. /* */
  32. /* The constants supplied here control minimum size of an */
  33. /* allocation bucket. */
  34. /* */
  35. /********************************************************************/
  36. CONST SBIT32 MinParentSize = 32;
  37. /********************************************************************/
  38. /* */
  39. /* Class constructor. */
  40. /* */
  41. /* Create a heap and prepare it for use. Additionally, make */
  42. /* sure that the heap configuration makes sense. This is */
  43. /* tricky as the whole structure of the heap can be changed */
  44. /* by the external configuration information. */
  45. /* */
  46. /********************************************************************/
  47. HEAP::HEAP
  48. (
  49. CACHE *Caches1[],
  50. CACHE *Caches2[],
  51. SBIT32 MaxFreeSpace,
  52. FIND *NewFind,
  53. NEW_PAGE *NewPages,
  54. ROCKALL *NewRockall,
  55. SBIT32 Size1,
  56. SBIT32 Size2,
  57. SBIT32 Stride1,
  58. SBIT32 Stride2,
  59. BOOLEAN NewThreadSafe
  60. )
  61. {
  62. //
  63. // The top three buckets are special and a user can not
  64. // allocate memory from two of them. Thus, unless we have
  65. // at least four buckets the memory allocator is not going
  66. // to be very useful.
  67. //
  68. if ( (Size1 >= 1) && (Size2 >= 3) )
  69. {
  70. REGISTER CACHE *FirstCache = Caches1[0];
  71. REGISTER CACHE *MiddleCache = Caches2[0];
  72. REGISTER CACHE *LastCache = Caches2[ (Size2-3) ];
  73. //
  74. // Calculate the minimum and maximum allocation sizes.
  75. // All allocations outside of this range will be passed
  76. // directly to the external allocator.
  77. //
  78. CachesSize = (Size1 + Size2);
  79. MinCacheSize = FirstCache -> GetAllocationSize();
  80. MidCacheSize = MiddleCache -> GetAllocationSize();
  81. MaxCacheSize = LastCache -> GetAllocationSize();
  82. //
  83. // Calculate and save various useful pointers needed
  84. // during the course of execution.
  85. //
  86. Caches = Caches1;
  87. ExternalCache = (Caches2[ (Size2-1) ]);
  88. Find = NewFind;
  89. NewPage = NewPages;
  90. Rockall = NewRockall;
  91. TopCache = (Caches2[ (Size2-2) ]);
  92. #ifdef ENABLE_HEAP_STATISTICS
  93. //
  94. // Zero the heap statistics.
  95. //
  96. CopyMisses = 0;
  97. MaxCopySize = 0;
  98. MaxNewSize = 0;
  99. NewMisses = 0;
  100. Reallocations = 0;
  101. TotalCopySize = 0;
  102. TotalNewSize = 0;
  103. #endif
  104. //
  105. // The external allocation size must be reasonable.
  106. // All allocation sizes must be a multiple of the
  107. // minimum allocation size. The minimum allocation
  108. // size and the middle allocation size must be a
  109. // power of two.
  110. //
  111. if
  112. (
  113. (ExternalCache -> GetPageSize() == TopCache -> GetPageSize())
  114. &&
  115. (PowerOfTwo( Rockall -> NaturalSize() ))
  116. &&
  117. (Rockall -> NaturalSize() >= PageSize())
  118. &&
  119. (TopCache -> GetPageSize() >= PageSize())
  120. &&
  121. (PowerOfTwo( TopCache -> GetPageSize() ))
  122. &&
  123. ((Stride1 > 0) && (PowerOfTwo( Stride1 )))
  124. &&
  125. ((Stride2 >= Stride1) && (PowerOfTwo( Stride2 )))
  126. &&
  127. (ConvertDivideToShift( Stride1,& ShiftSize1 ))
  128. &&
  129. (ConvertDivideToShift( Stride2,& ShiftSize2 ))
  130. )
  131. {
  132. REGISTER SBIT32 Count1;
  133. REGISTER SBIT32 TopCacheSize = (TopCache -> GetPageSize());
  134. REGISTER SBIT32 MaxSize1 = (MidCacheSize / Stride1);
  135. REGISTER SBIT32 MaxSize2 = (TopCacheSize / Stride2);
  136. //
  137. // Calculate the maximum number of free pages
  138. // that can be kept. Also set the smallest parent
  139. // mask to the maximum value.
  140. //
  141. MaxFreePages = (MaxFreeSpace / (TopCache -> GetAllocationSize()));
  142. SmallestParentMask = ((TopCache -> GetAllocationSize())-1);
  143. ThreadSafe = NewThreadSafe;
  144. //
  145. // Calculate the sizes of the arrays that map
  146. // sizes to caches.
  147. //
  148. MaxTable1 = (MaxSize1 * sizeof(CACHE*));
  149. MaxTable2 = (MaxSize2 * sizeof(CACHE*));
  150. //
  151. // The heap pages must be specified in asceding
  152. // order of size and be an exact multiple of the
  153. // minimum allocation size.
  154. //
  155. for ( Count1=0;Count1 < Size1;Count1 ++ )
  156. {
  157. REGISTER CACHE *Current = Caches1[ Count1 ];
  158. REGISTER CACHE *Next = Caches1[ (Count1+1) ];
  159. REGISTER SBIT32 AllocationSize = Current -> GetAllocationSize();
  160. REGISTER SBIT32 ChunkSize = Current -> GetChunkSize();
  161. REGISTER SBIT32 PageSize = Current -> GetPageSize();
  162. //
  163. // Ensure each cache specification meets the
  164. // requirements of the heap. If not fail
  165. // the heap entire heap creation.
  166. //
  167. if ( (AllocationSize % Stride1) != 0 )
  168. { Failure( "Cache size not multiple of stride" ); }
  169. if ( AllocationSize >= Next -> GetAllocationSize() )
  170. { Failure( "Cache sizes not in ascending order" ); }
  171. if ( (AllocationSize > ChunkSize) || (ChunkSize > PageSize) )
  172. { Failure( "Chunk size not suitable for cache" ); }
  173. if ( AllocationSize >= PageSize )
  174. { Failure( "Cache size larger than parent size" ); }
  175. if ( PageSize > TopCacheSize )
  176. { Failure( "Parent size exceeds 'TopCache' size" ); }
  177. }
  178. //
  179. // The heap pages must be specified in asceding
  180. // order of size and be an exact multiple of the
  181. // minimum allocation size.
  182. //
  183. for ( Count1=0;Count1 < (Size2-2);Count1 ++ )
  184. {
  185. REGISTER CACHE *Current = Caches2[ Count1 ];
  186. REGISTER CACHE *Next = Caches2[ (Count1+1) ];
  187. REGISTER SBIT32 AllocationSize = Current -> GetAllocationSize();
  188. REGISTER SBIT32 ChunkSize = Current -> GetChunkSize();
  189. REGISTER SBIT32 PageSize = Current -> GetPageSize();
  190. //
  191. // Ensure each cache specification meets the
  192. // requirements of the heap. If not fail
  193. // the heap entire heap creation.
  194. //
  195. if ( (AllocationSize % Stride2) != 0 )
  196. { Failure( "Cache size not multiple of stride" ); }
  197. if ( AllocationSize >= Next -> GetAllocationSize() )
  198. { Failure( "Cache sizes not in ascending order" ); }
  199. if ( (AllocationSize > ChunkSize) || (ChunkSize > PageSize) )
  200. { Failure( "Chunk size not suitable for cache" ); }
  201. if ( AllocationSize >= PageSize )
  202. { Failure( "Cache size larger than parent size" ); }
  203. if ( PageSize > TopCacheSize )
  204. { Failure( "Parent size exceeds 'TopCache' size" ); }
  205. }
  206. //
  207. // The external and top caches have special rules
  208. // which must be checked to ensure these caches
  209. // are valid.
  210. //
  211. for ( Count1=(Size2-2);Count1 < Size2;Count1 ++ )
  212. {
  213. REGISTER CACHE *Current = Caches2[ Count1 ];
  214. REGISTER SBIT32 AllocationSize = Current -> GetAllocationSize();
  215. //
  216. // Ensure each cache specification meets the
  217. // requirements of the heap. If not fail
  218. // the heap entire heap creation.
  219. //
  220. if ( (AllocationSize % Stride2) != 0 )
  221. { Failure( "Top cache size not multiple of minimum" ); }
  222. if ( AllocationSize != Current -> GetChunkSize() )
  223. { Failure( "Chunk size not suitable for top cache" ); }
  224. if ( AllocationSize != Current -> GetPageSize() )
  225. { Failure( "Page size not suitable for top cache" ); }
  226. if ( Current -> GetCacheSize() != 0 )
  227. { Failure( "Cache size not zero for top cache" ); }
  228. }
  229. //
  230. // We need to allocate two arrays to enable requested
  231. // sizes to be quickly mapped to allocation caches.
  232. // Here we allocate the tables and later fill in all
  233. // the necessary mapping information.
  234. //
  235. SizeToCache1 = (CACHE**)
  236. (
  237. Rockall -> NewArea
  238. (
  239. (Rockall -> NaturalSize() - 1),
  240. (MaxTable1 + MaxTable2),
  241. False
  242. )
  243. );
  244. #ifdef ENABLE_HEAP_STATISTICS
  245. //
  246. // When we are compiled for statistics we keep
  247. // information on all the allocations we see.
  248. //
  249. Statistics = (SBIT32*)
  250. (
  251. Rockall -> NewArea
  252. (
  253. (Rockall -> NaturalSize() - 1),
  254. (MaxCacheSize * sizeof(SBIT32)),
  255. False
  256. )
  257. );
  258. #endif
  259. //
  260. // We make sure that the allocations we made
  261. // did not fail. If not we have to fail the
  262. // creation of the whole heap.
  263. //
  264. if
  265. (
  266. (SizeToCache1 != ((CACHE**) AllocationFailure))
  267. #ifdef ENABLE_HEAP_STATISTICS
  268. &&
  269. (Statistics != ((SBIT32*) AllocationFailure))
  270. #endif
  271. )
  272. {
  273. REGISTER SBIT32 Count2;
  274. //
  275. // Cycle through the first segment of the
  276. // mapping table creating approriate
  277. // translations.
  278. //
  279. for ( Count1=0,Count2=0;Count1 < MaxSize1;Count1 ++ )
  280. {
  281. //
  282. // We make sure that the current allocation
  283. // page is large enough to hold an element
  284. // of some given size. If not we move on to
  285. // the next allocation page.
  286. //
  287. if
  288. (
  289. ((Count1 + 1) * Stride1)
  290. >
  291. (Caches1[ Count2 ] -> GetAllocationSize())
  292. )
  293. { Count2 ++; }
  294. //
  295. // Store a pointer so that a request for
  296. // this size of allocation goes directly
  297. // to the correct page.
  298. //
  299. SizeToCache1[ Count1 ] = Caches1[ Count2 ];
  300. }
  301. //
  302. // Compute the start address for the second
  303. // segment of the table.
  304. //
  305. SizeToCache2 =
  306. ((CACHE**) & ((CHAR*) SizeToCache1)[ MaxTable1 ]);
  307. //
  308. // Cycle through the second segment of the
  309. // mapping table creating approriate
  310. // translations.
  311. //
  312. for ( Count1=0,Count2=0;Count1 < MaxSize2;Count1 ++ )
  313. {
  314. //
  315. // We make sure that the current allocation
  316. // page is large enough to hold an element
  317. // of some given size. If not we move on to
  318. // the next allocation page.
  319. //
  320. if
  321. (
  322. ((Count1 + 1) * Stride2)
  323. >
  324. (Caches2[ Count2 ] -> GetAllocationSize())
  325. )
  326. { Count2 ++; }
  327. //
  328. // Store a pointer so that a request for
  329. // this size of allocation goes directly
  330. // to the correct page.
  331. //
  332. SizeToCache2[ Count1 ] = Caches2[ Count2 ];
  333. }
  334. //
  335. // Now that we have created the size to cache
  336. // mappings lets use them to link each cache to
  337. // the cache it uses to allocate additional
  338. // memory.
  339. //
  340. for ( Count1=0;Count1 < (CachesSize-1);Count1 ++ )
  341. {
  342. REGISTER CACHE *CurrentCache = Caches[ Count1 ];
  343. REGISTER SBIT32 PageSize = CurrentCache -> GetPageSize();
  344. REGISTER CACHE *ParentCache = FindCache( PageSize );
  345. REGISTER BOOLEAN Top = (CurrentCache == ParentCache);
  346. //
  347. // Ensure that the parent cache is suitable
  348. // and in line with what we were expecting.
  349. //
  350. if
  351. (
  352. (PowerOfTwo( PageSize ))
  353. &&
  354. (PageSize >= MinParentSize)
  355. &&
  356. (PageSize == (ParentCache -> GetAllocationSize()))
  357. )
  358. {
  359. //
  360. // We keep track of the smallest
  361. // cache that is a parent. We can
  362. // use this to improve the performance
  363. // of the find hash table.
  364. //
  365. if ( ((BIT32) PageSize) < SmallestParentMask )
  366. { SmallestParentMask = (PageSize-1); }
  367. //
  368. // Update the current cache with
  369. // information about it's parent
  370. // cache.
  371. //
  372. CurrentCache -> UpdateCache
  373. (
  374. NewFind,
  375. this,
  376. NewPages,
  377. ((Top) ? ((CACHE*) GlobalRoot) : ParentCache)
  378. );
  379. }
  380. else
  381. { Failure( "Parent bucket is invalid" ); }
  382. }
  383. //
  384. // The external cache is an exact duplicate
  385. // of the top cache and is used to hold all
  386. // memory allocations that are too large for
  387. // any bucket. Nonetheless, its parent is
  388. // still the top cache.
  389. //
  390. ExternalCache -> UpdateCache
  391. (
  392. NewFind,
  393. this,
  394. NewPages,
  395. TopCache
  396. );
  397. //
  398. // Update the hash table with the minimum
  399. // parent size for this heap.
  400. //
  401. Find -> UpdateFind
  402. (
  403. (TopCache -> GetAllocationSize()-1),
  404. SmallestParentMask
  405. );
  406. //
  407. // Update the new page structure with the
  408. // details of the top cache.
  409. //
  410. NewPage -> UpdateNewPage( TopCache );
  411. //
  412. // Activate the heap.
  413. //
  414. Active = True;
  415. }
  416. else
  417. { Failure( "Mapping table in constructor for HEAP" ); }
  418. }
  419. else
  420. { Failure( "The allocation sizes in constructor for HEAP" ); }
  421. }
  422. else
  423. { Failure( "A heap size in constructor for HEAP" ); }
  424. }
  425. /********************************************************************/
  426. /* */
  427. /* Memory deallocation. */
  428. /* */
  429. /* We need to release some memory. First we try to slave the */
  430. /* request in the free cache so we can do a batch of releases */
  431. /* later. If not we are forced to do it at once. */
  432. /* */
  433. /********************************************************************/
  434. BOOLEAN HEAP::Delete( VOID *Address,SBIT32 Size )
  435. {
  436. //
  437. // Although normally a class is never called before
  438. // its constructor. The heap is subject to some strange
  439. // behaviour so we check to make sure this is not the
  440. // case.
  441. //
  442. if ( Active )
  443. {
  444. //
  445. // When the caller gives us the size of the
  446. // allocation we can short cut the deallocation
  447. // process by skipping directly to the correct
  448. // cache. However, if the user supplies us
  449. // with bogus data we will retry using the
  450. // the full deallocation process.
  451. //
  452. if ( (Size > 0) && (Size <= MaxCacheSize) )
  453. {
  454. REGISTER CACHE *Cache = (FindCache( Size ));
  455. if ( Find -> Delete( Address,Cache ) )
  456. { return True; }
  457. }
  458. //
  459. // It looks like all we have is the address so
  460. // deallocate using the long path.
  461. //
  462. return (Find -> Delete( Address,TopCache ));
  463. }
  464. else
  465. { return False; }
  466. }
  467. /********************************************************************/
  468. /* */
  469. /* Delete all allocations. */
  470. /* */
  471. /* We delete the entire heap and free all existing allocations. */
  472. /* If 'Recycle' is requested we slave the allocated memory as */
  473. /* we expect some new allocations. If not we return all the */
  474. /* memory to the external allocator. */
  475. /* */
  476. /********************************************************************/
  477. VOID HEAP::DeleteAll( BOOLEAN Recycle )
  478. {
  479. //
  480. // Although normally a class is never called before
  481. // its constructor. The heap is subject to some strange
  482. // behaviour so we check to make sure this is not the
  483. // case.
  484. //
  485. if ( Active )
  486. {
  487. REGISTER SBIT32 Count;
  488. //
  489. // We claim all of the heap locks to freeze
  490. // all new allocations or deletions.
  491. //
  492. LockAll();
  493. //
  494. // Now reset all the caches and the find
  495. // hash table statistics.
  496. //
  497. Find -> DeleteAll();
  498. for ( Count=0;Count < CachesSize;Count ++ )
  499. { Caches[ Count ] -> DeleteAll(); }
  500. //
  501. // Delete the heap.
  502. //
  503. NewPage -> DeleteAll( Recycle );
  504. //
  505. // Now release all the heap locks we claimed
  506. // earlier and unfreeze the heap.
  507. //
  508. UnlockAll();
  509. //
  510. // Trim the free space if needed.
  511. //
  512. if ( Recycle )
  513. { TopCache -> ReleaseSpace( MaxFreePages ); }
  514. }
  515. }
  516. /********************************************************************/
  517. /* */
  518. /* Details of a memory allocation. */
  519. /* */
  520. /* We need to the details of a particular memory allocation. */
  521. /* All we have is an address. We use this to find the largest */
  522. /* allocation page this address is contained in and then */
  523. /* navigate through the sub-divisions of this page until we */
  524. /* find the allocation. */
  525. /* */
  526. /********************************************************************/
  527. BOOLEAN HEAP::Details( VOID *Address,SBIT32 *Size )
  528. {
  529. //
  530. // Although normally a class is never called before
  531. // its constructor. The heap is subject to some strange
  532. // behaviour so we check to make sure this is not the
  533. // case.
  534. //
  535. if ( Active )
  536. {
  537. AUTO SBIT32 Dummy;
  538. //
  539. // We allow the caller to omit the 'Size' parameter.
  540. // I can see little reason for this but it is supported
  541. // anyway.
  542. //
  543. if ( Size == NULL )
  544. { Size = & Dummy; }
  545. //
  546. // Find the details relating to this allocation
  547. // and return them.
  548. //
  549. return (Find -> Details( Address,NULL,TopCache,Size ));
  550. }
  551. else
  552. { return False; }
  553. }
  554. /********************************************************************/
  555. /* */
  556. /* Find a cache. */
  557. /* */
  558. /* Find the allocation cache for the size supplied and return */
  559. /* a pointer to it. */
  560. /* */
  561. /********************************************************************/
  562. CACHE *HEAP::FindCache( SBIT32 Size )
  563. {
  564. REGISTER CACHE *Cache;
  565. //
  566. // Compute the cache address.
  567. //
  568. if ( Size < MidCacheSize )
  569. { return (SizeToCache1[ ((Size-1) >> ShiftSize1) ]); }
  570. else
  571. { return (SizeToCache2[ ((Size-1) >> ShiftSize2) ]); }
  572. //
  573. // Prefetch the class data if we are running a
  574. // Pentium III or better with locks. We do this
  575. // because prefetching hot SMP data structures
  576. // really helps. However, if the structures are
  577. // not shared (i.e. no locks) then it is worthless
  578. // overhead.
  579. //
  580. if ( ThreadSafe )
  581. { Prefetch.Nta( ((CHAR*) Cache),sizeof(CACHE) ); }
  582. return Cache;
  583. }
  584. /********************************************************************/
  585. /* */
  586. /* Claim a lock on the entire heap. */
  587. /* */
  588. /* We claim a lock on the heap to improve performance */
  589. /* or prevent others from performing heap operations. */
  590. /* */
  591. /********************************************************************/
  592. VOID HEAP::LockAll( VOID )
  593. {
  594. //
  595. // Although normally a class is never called before
  596. // its constructor. The heap is subject to some strange
  597. // behaviour so we check to make sure this is not the
  598. // case.
  599. //
  600. if ( Active )
  601. {
  602. //
  603. // We claim the locks if we have not already
  604. // claimed them earlier.
  605. //
  606. if ( Find -> GetLockCount() == 0 )
  607. {
  608. REGISTER SBIT32 Count;
  609. //
  610. // We claim all of the heap locks to freeze
  611. // all new allocations or deletions.
  612. //
  613. for ( Count=0;Count < CachesSize;Count ++ )
  614. { Caches[ Count ] -> ClaimCacheLock(); }
  615. //
  616. // Although the heap is frozen at this point
  617. // we claim the last few locks just to be
  618. // tidy.
  619. //
  620. Find -> ClaimFindExclusiveLock();
  621. NewPage -> ClaimNewPageLock();
  622. }
  623. //
  624. // Increment the per thread lock count.
  625. //
  626. Find -> IncrementLockCount();
  627. }
  628. }
  629. /********************************************************************/
  630. /* */
  631. /* Delete multiple allocations. */
  632. /* */
  633. /* We need to release multiple memory allocations. First we try */
  634. /* to slave the requets in the free cache so we can do a batch */
  635. /* of releases later. If not we are forced to do it immediately. */
  636. /* */
  637. /********************************************************************/
  638. BOOLEAN HEAP::MultipleDelete
  639. (
  640. SBIT32 Actual,
  641. VOID *Array[],
  642. SBIT32 Size
  643. )
  644. {
  645. //
  646. // Although normally a class is never called before
  647. // its constructor. The heap is subject to some strange
  648. // behaviour so we check to make sure this is not the
  649. // case.
  650. //
  651. if ( Active )
  652. {
  653. REGISTER SBIT32 Count;
  654. REGISTER BOOLEAN Result = True;
  655. REGISTER CACHE *ParentCache = ((CACHE*) GlobalRoot);
  656. //
  657. // When the caller gives us the size of the allocation
  658. // we can short cut the deallocation process by skipping
  659. // directly to the correct cache. However, if the user
  660. // supplies us with bogus data we will retry using the
  661. // the long path.
  662. //
  663. if ( (Size > 0) && (Size <= MaxCacheSize) )
  664. {
  665. REGISTER CACHE *Cache = (FindCache( Size ));
  666. ParentCache = (Cache -> GetParentCache());
  667. }
  668. //
  669. // Delete each memory allocation one at a time.
  670. // We would like to delete them all at once but
  671. // we can't be sure they are all vaild or related.
  672. //
  673. for ( Count=0;Count < Actual;Count ++ )
  674. {
  675. REGISTER VOID *Address = Array[ Count ];
  676. //
  677. // First try to optimize the delete and if that
  678. // fails then try the long path.
  679. //
  680. if
  681. (
  682. (ParentCache == ((CACHE*) GlobalRoot))
  683. ||
  684. (! Find -> Delete( Address,ParentCache ))
  685. )
  686. {
  687. Result =
  688. (
  689. Find -> Delete( Address,TopCache )
  690. &&
  691. Result
  692. );
  693. }
  694. }
  695. return Result;
  696. }
  697. else
  698. { return False; }
  699. }
  700. /********************************************************************/
  701. /* */
  702. /* Multiple memory allocations. */
  703. /* */
  704. /* We have been asked to allocate muliple memory blocks. We */
  705. /* we do this by using the cache and then claiming and addition */
  706. /* space from the heap as needed. */
  707. /* */
  708. /********************************************************************/
  709. BOOLEAN HEAP::MultipleNew
  710. (
  711. SBIT32 *Actual,
  712. VOID *Array[],
  713. SBIT32 Requested,
  714. SBIT32 Size,
  715. SBIT32 *Space,
  716. BOOLEAN Zero
  717. )
  718. {
  719. //
  720. // Although normally a class is never called before
  721. // its constructor. The heap is subject to some strange
  722. // behaviour so we check to make sure this is not the
  723. // case.
  724. //
  725. if ( Active )
  726. {
  727. AUTO SBIT32 Dummy;
  728. //
  729. // We allow the caller to omit the 'Actual' parameter.
  730. // I can see little reason for this but it is supported
  731. // anyway. Regardless we zero it.
  732. //
  733. if ( Actual == NULL )
  734. { Actual = & Dummy; }
  735. (*Actual) = 0;
  736. //
  737. // We need to be sure that the size requested is in the
  738. // range supported by the memory allocator. If not we
  739. // do a series of single allocations from the default
  740. // allocator.
  741. //
  742. if ( (Size > 0) && (Size <= MaxCacheSize) )
  743. {
  744. REGISTER CACHE *Cache = (FindCache( Size ));
  745. REGISTER SBIT32 NewSize = (Cache -> GetAllocationSize());
  746. //
  747. // Allocate memory from the appropriate
  748. // allocation bucket.
  749. //
  750. (VOID) Cache -> MultipleNew( Actual,Array,Requested );
  751. //
  752. // If needed return the actual amount
  753. // of space allocated for each element.
  754. //
  755. if ( Space != NULL )
  756. { (*Space) = NewSize; }
  757. #ifdef ENABLE_HEAP_STATISTICS
  758. //
  759. // Update the allocation statistics.
  760. //
  761. Statistics[ (Size-1) ] += Requested;
  762. #endif
  763. //
  764. // If needed zero each element that is
  765. // allocated.
  766. //
  767. if ( Zero )
  768. {
  769. REGISTER SBIT32 Count;
  770. for ( Count=((*Actual)-1);Count >= 0;Count -- )
  771. { ZeroMemory( Array[ Count ],NewSize ); }
  772. }
  773. return ((*Actual) == Requested);
  774. }
  775. else
  776. {
  777. //
  778. // If the allocation size is greater than
  779. // zero we create the allocations. If not
  780. // we fail the request.
  781. //
  782. if ( Size > 0 )
  783. {
  784. //
  785. // We have got a request for an element size
  786. // larger than the largest bucket size. So
  787. // we call the single allocation interface
  788. // as this supports large sizes.
  789. //
  790. for
  791. (
  792. /* void */;
  793. ((*Actual) < Requested)
  794. &&
  795. ((Array[ (*Actual) ] = New( Size )) != AllocationFailure);
  796. (*Actual) ++
  797. );
  798. //
  799. // If needed return the actual amount of space
  800. // allocated for each element.
  801. //
  802. if ( Space != NULL )
  803. { (*Space) = Size; }
  804. return ((*Actual) == Requested);
  805. }
  806. }
  807. }
  808. return False;
  809. }
  810. /********************************************************************/
  811. /* */
  812. /* Memory allocation. */
  813. /* */
  814. /* We have been asked to allocate some memory. Hopefully, */
  815. /* we will be able to do this out of the cache. If not we */
  816. /* will need to pass it along to the appropriate allocation */
  817. /* bucket. */
  818. /* */
  819. /********************************************************************/
  820. VOID *HEAP::New( SBIT32 Size,SBIT32 *Space,BOOLEAN Zero )
  821. {
  822. REGISTER VOID *NewMemory = ((VOID*) AllocationFailure);
  823. //
  824. // Although normally a class is never called before
  825. // its constructor. The heap is subject to some strange
  826. // behaviour so we check to make sure this is not the
  827. // case.
  828. //
  829. if ( Active )
  830. {
  831. //
  832. // We ensure the allocation size is in
  833. // the range supported by the heap.
  834. //
  835. if ( (Size > 0) && (Size <= MaxCacheSize) )
  836. {
  837. REGISTER CACHE *Cache = (FindCache( Size ));
  838. #ifdef ENABLE_HEAP_STATISTICS
  839. //
  840. // Update the allocation statistics.
  841. //
  842. Statistics[ (Size-1) ] ++;
  843. #endif
  844. //
  845. // Allocate memory from the appropriate
  846. // cache in the heap.
  847. //
  848. NewMemory = (Cache -> New());
  849. Size = (Cache -> GetAllocationSize());
  850. }
  851. else
  852. {
  853. //
  854. // If the allocation size is greater than
  855. // zero we create the allocation. If not
  856. // we fail the request.
  857. //
  858. if ( Size > 0 )
  859. {
  860. #ifdef ENABLE_HEAP_STATISTICS
  861. //
  862. // Update the allocation statistics.
  863. //
  864. if ( Size > MaxNewSize )
  865. { MaxNewSize = Size; }
  866. NewMisses ++;
  867. TotalNewSize += Size;
  868. #endif
  869. //
  870. // Allocate memory from a special
  871. // cache bucket which gets space
  872. // externally.
  873. //
  874. NewMemory = (ExternalCache -> New( False,Size ));
  875. }
  876. else
  877. { NewMemory = ((VOID*) AllocationFailure); }
  878. }
  879. //
  880. // We need to be sure that the allocation
  881. // request did not fail.
  882. //
  883. if ( NewMemory != ((VOID*) AllocationFailure) )
  884. {
  885. //
  886. // If needed return the actual amount of space
  887. // allocated for this request.
  888. //
  889. if ( Space != NULL )
  890. { (*Space) = Size; }
  891. //
  892. // Zero the memory if the needed.
  893. //
  894. if ( Zero )
  895. { ZeroMemory( NewMemory,Size ); }
  896. }
  897. }
  898. return NewMemory;
  899. }
  900. #ifdef ENABLE_HEAP_STATISTICS
  901. /********************************************************************/
  902. /* */
  903. /* Print statistics. */
  904. /* */
  905. /* We output the allocation statistics to the debug console. */
  906. /* */
  907. /********************************************************************/
  908. VOID HEAP::PrintDebugStatistics( VOID )
  909. {
  910. REGISTER HANDLE Semaphore;
  911. //
  912. // As we may have multiple heaps executing there
  913. // destructors at the same time we create a semaphore
  914. // to prevent multiple threads producing output at
  915. // the same time.
  916. //
  917. if ( (Semaphore = CreateSemaphore( NULL,1,MaxCpus,"Print" )) != NULL)
  918. {
  919. //
  920. // Wait for the global semaphore.
  921. //
  922. if
  923. (
  924. WaitForSingleObject( Semaphore,INFINITE )
  925. ==
  926. WAIT_OBJECT_0
  927. )
  928. {
  929. REGISTER SBIT32 Count;
  930. REGISTER SBIT32 CurrentSize = 0;
  931. REGISTER SBIT32 GrandTotal = 0;
  932. REGISTER SBIT32 HighWater = 0;
  933. REGISTER SBIT32 Total = 0;
  934. //
  935. // Output the titles to the debug console.
  936. //
  937. DebugPrint
  938. (
  939. "\n"
  940. " Original New Bucket High "
  941. " Cache Cache Partial Grand\n"
  942. " Size Allocs Size Water "
  943. " Fills Flushes Total Total\n"
  944. );
  945. //
  946. // Output details for every sample size.
  947. //
  948. for ( Count=0;Count < MaxCacheSize;Count ++ )
  949. {
  950. REGISTER SBIT32 Hits = Statistics[ Count ];
  951. //
  952. // Skip the sample if there are no hits.
  953. //
  954. if ( Hits > 0 )
  955. {
  956. REGISTER CACHE *Cache = FindCache( (Count+1) );
  957. REGISTER SBIT32 CacheSize = Cache -> GetAllocationSize();
  958. //
  959. // Zero the running totals at the end
  960. // of each bucket.
  961. //
  962. if ( CurrentSize != CacheSize )
  963. {
  964. CurrentSize = CacheSize;
  965. Total = 0;
  966. DebugPrint
  967. (
  968. "----------------------------------------"
  969. "--------------------------------------\n"
  970. );
  971. }
  972. //
  973. // Compute and output the totals.
  974. //
  975. if ( Total == 0)
  976. { HighWater += (Cache -> GetHighWater() * CacheSize); }
  977. Total += Hits;
  978. GrandTotal += Hits;
  979. DebugPrint
  980. (
  981. "%8d %8d %8d %8d %8d %8d %8d %8d\n",
  982. (Count + 1),
  983. Hits,
  984. CacheSize,
  985. Cache -> GetHighWater(),
  986. Cache -> GetCacheFills(),
  987. Cache -> GetCacheFlushes(),
  988. Total,
  989. GrandTotal
  990. );
  991. }
  992. }
  993. //
  994. // Print the hash table statistics.
  995. //
  996. DebugPrint( "\nHash Table Statistics" );
  997. DebugPrint( "\n---------------------\n" );
  998. DebugPrint
  999. (
  1000. "\t*** Cache ***\n"
  1001. "\tFills\t\t: %d\n\tHits\t\t: %d\n\tMisses\t\t: %d\n"
  1002. "\t*** Table ***\n"
  1003. "\tAverage\t\t: %d\n\tMax\t\t: %d\n\tScans\t\t: %d\n"
  1004. "\tMax Hash\t: %d\n\tMax LookAside\t: %d\n\tUsage\t\t: %d%%\n",
  1005. Find -> CacheFills(),
  1006. Find -> CacheHits(),
  1007. Find -> CacheMisses(),
  1008. Find -> AverageHashLength(),
  1009. Find -> MaxHashLength(),
  1010. Find -> TotalScans(),
  1011. Find -> MaxHashSize(),
  1012. Find -> MaxLookAsideSize(),
  1013. Find -> MaxUsage()
  1014. );
  1015. //
  1016. // Print the reallocation statistics.
  1017. //
  1018. DebugPrint( "\nOversize Statistics" );
  1019. DebugPrint( "\n-------------------\n" );
  1020. DebugPrint
  1021. (
  1022. "\tAverage Size\t: %d\n\tMax Size\t: %d\n\tMisses\t\t: %d\n",
  1023. (TotalNewSize / ((NewMisses > 0) ? NewMisses : 1)),
  1024. MaxNewSize,
  1025. NewMisses
  1026. );
  1027. //
  1028. // Print the reallocation statistics.
  1029. //
  1030. DebugPrint( "\nRealloc Statistics" );
  1031. DebugPrint( "\n------------------\n" );
  1032. DebugPrint
  1033. (
  1034. "\tAverage Copy\t: %d\n\tCalls\t\t: %d\n\tMax Copy\t: %d\n"
  1035. "\tTotal Copies\t: %d\n",
  1036. (TotalCopySize / ((CopyMisses > 0) ? CopyMisses : 1)),
  1037. Reallocations,
  1038. MaxCopySize,
  1039. CopyMisses
  1040. );
  1041. //
  1042. // Print the general statistics.
  1043. //
  1044. DebugPrint( "\nSummary Statistics" );
  1045. DebugPrint( "\n------------------\n" );
  1046. DebugPrint
  1047. (
  1048. "\tHigh Water\t: %d\n",
  1049. HighWater
  1050. );
  1051. }
  1052. else
  1053. { Failure( "Sleep failed in PrintDebugStatistics" ); }
  1054. //
  1055. // Release the global semaphore.
  1056. //
  1057. ReleaseSemaphore( Semaphore,1,NULL );
  1058. CloseHandle( Semaphore );
  1059. }
  1060. }
  1061. #endif
  1062. /********************************************************************/
  1063. /* */
  1064. /* Memory reallocation. */
  1065. /* */
  1066. /* We have been asked to reallocate some memory. Hopefully, */
  1067. /* we will be able to do this out of the cache. If not we */
  1068. /* will need to pass it along to the appropriate allocation */
  1069. /* bucket, do a copy and free the orginal allocation. */
  1070. /* */
  1071. /********************************************************************/
  1072. VOID *HEAP::Resize
  1073. (
  1074. VOID *Address,
  1075. SBIT32 NewSize,
  1076. SBIT32 Move,
  1077. SBIT32 *Space,
  1078. BOOLEAN NoDelete,
  1079. BOOLEAN Zero
  1080. )
  1081. {
  1082. //
  1083. // Although normally a class is never called before
  1084. // its constructor. The heap is subject to some strange
  1085. // behaviour so we check to make sure this is not the
  1086. // case.
  1087. //
  1088. if ( Active )
  1089. {
  1090. AUTO SBIT32 Size;
  1091. AUTO SBIT32 NewSpace;
  1092. //
  1093. // Find the details of the existing allocation.
  1094. // If there is no existing allocation then exit.
  1095. //
  1096. if ( Details( Address,& Size ) )
  1097. {
  1098. REGISTER VOID *NewMemory;
  1099. REGISTER SBIT32 Smallest = ((Size < NewSize) ? Size : NewSize);
  1100. //
  1101. // Make sure the sizes appear to make sense.
  1102. //
  1103. if ( Smallest > 0 )
  1104. {
  1105. #ifdef ENABLE_HEAP_STATISTICS
  1106. //
  1107. // Update the statistics.
  1108. //
  1109. Reallocations ++;
  1110. #endif
  1111. //
  1112. // When the new allocation allocation is
  1113. // standard heap allocation size we check
  1114. // for various optimizations.
  1115. //
  1116. if ( NewSize <= MaxCacheSize )
  1117. {
  1118. REGISTER CACHE *Cache = (FindCache( NewSize ));
  1119. REGISTER SBIT32 CacheSize = (Cache -> GetAllocationSize());
  1120. REGISTER SBIT32 Delta = (CacheSize - Size);
  1121. //
  1122. // We only need to reallocate if the new
  1123. // size is larger than the current bucket
  1124. // or the new size is smaller and we have
  1125. // been given permission to move the
  1126. // allocation.
  1127. //
  1128. if ( ResizeTest( Delta,Move ) )
  1129. {
  1130. //
  1131. // We need to allocate some more
  1132. // memory and copy the old data.
  1133. // into the new area.
  1134. //
  1135. NewMemory = (Cache -> New());
  1136. NewSpace = CacheSize;
  1137. #ifdef ENABLE_HEAP_STATISTICS
  1138. //
  1139. // Update the statistics.
  1140. //
  1141. Statistics[ (NewSize-1) ] ++;
  1142. #endif
  1143. }
  1144. else
  1145. {
  1146. //
  1147. // If the new size is unchanged or smaller
  1148. // then just return the current allocation.
  1149. // If the new size is larger then we must
  1150. // fail the call.
  1151. //
  1152. if ( Delta <= 0 )
  1153. {
  1154. //
  1155. // The amount of memory allocated for
  1156. // this request is unchanged so return
  1157. // the current size.
  1158. //
  1159. if ( Space != NULL )
  1160. { (*Space) = Size; }
  1161. return Address;
  1162. }
  1163. else
  1164. { return ((VOID*) AllocationFailure); }
  1165. }
  1166. }
  1167. else
  1168. {
  1169. REGISTER SBIT32 Delta = (NewSize - Size);
  1170. //
  1171. // We only need to reallocate if the new
  1172. // size is larger than the current bucket
  1173. // or the new size is smaller and we have
  1174. // been given permission to move the
  1175. // allocation.
  1176. //
  1177. if ( ResizeTest( Delta,Move ) )
  1178. {
  1179. //
  1180. // One of the sizes is not within the
  1181. // allocation range of the heap. So
  1182. // I have to punt and reallocate.
  1183. //
  1184. NewMemory =
  1185. (
  1186. ExternalCache -> New
  1187. (
  1188. False,
  1189. (NewSpace = NewSize)
  1190. )
  1191. );
  1192. #ifdef ENABLE_HEAP_STATISTICS
  1193. //
  1194. // Update the allocation statistics.
  1195. //
  1196. if ( NewSize > MaxNewSize )
  1197. { MaxNewSize = NewSize; }
  1198. NewMisses ++;
  1199. TotalNewSize += NewSize;
  1200. #endif
  1201. }
  1202. else
  1203. {
  1204. //
  1205. // If the new size is unchanged or smaller
  1206. // then just return the current allocation.
  1207. // If the new size is larger then we must
  1208. // fail the call.
  1209. //
  1210. if ( Delta <= 0 )
  1211. {
  1212. //
  1213. // The amount of memory allocated for
  1214. // this request is unchanged so return
  1215. // the current size.
  1216. //
  1217. if ( Space != NULL )
  1218. { (*Space) = Size; }
  1219. return Address;
  1220. }
  1221. else
  1222. { return ((VOID*) AllocationFailure); }
  1223. }
  1224. }
  1225. //
  1226. // We need to make sure we were able to allocate
  1227. // the new memory otherwise the copy will fail.
  1228. //
  1229. if ( NewMemory != ((VOID*) AllocationFailure) )
  1230. {
  1231. //
  1232. // Copy the contents of the old allocation
  1233. // to the new allocation.
  1234. //
  1235. memcpy
  1236. (
  1237. ((void*) NewMemory),
  1238. ((void*) Address),
  1239. ((int) Smallest)
  1240. );
  1241. //
  1242. // If needed return the actual amount of
  1243. // space allocated for this request.
  1244. //
  1245. if ( Space != NULL )
  1246. { (*Space) = NewSpace; }
  1247. //
  1248. // Delete the old allocation unless we
  1249. // need to keep it around.
  1250. //
  1251. if ( ! NoDelete )
  1252. {
  1253. //
  1254. // Delete the old allocation.
  1255. //
  1256. if ( ! Delete( Address,Size ) )
  1257. { Failure( "Deleting allocation in Resize" ); }
  1258. }
  1259. //
  1260. // Zero the memory if the needed.
  1261. //
  1262. if ( Zero )
  1263. {
  1264. REGISTER SBIT32 Difference = (NewSpace - Smallest);
  1265. //
  1266. // If the new size is larger than
  1267. // old size then zero the end of the
  1268. // new allocation.
  1269. //
  1270. if ( Difference > 0 )
  1271. {
  1272. REGISTER CHAR *Array = ((CHAR*) NewMemory);
  1273. ZeroMemory( & Array[ Smallest ],Difference );
  1274. }
  1275. }
  1276. #ifdef ENABLE_HEAP_STATISTICS
  1277. //
  1278. // Update the allocation statistics.
  1279. //
  1280. if ( Smallest > MaxCopySize )
  1281. { MaxCopySize = Smallest; }
  1282. CopyMisses ++;
  1283. TotalCopySize += Smallest;
  1284. #endif
  1285. }
  1286. return NewMemory;
  1287. }
  1288. }
  1289. }
  1290. return ((VOID*) AllocationFailure);
  1291. }
  1292. /********************************************************************/
  1293. /* */
  1294. /* Truncate the heap. */
  1295. /* */
  1296. /* We need to truncate the heap. This pretty much a do nothing */
  1297. /* as we do this automatically anyway. The only thing we can */
  1298. /* do is free any space the user suggested keeping earlier. */
  1299. /* */
  1300. /********************************************************************/
  1301. BOOLEAN HEAP::Truncate( SBIT32 MaxFreeSpace )
  1302. {
  1303. REGISTER BOOLEAN Result = True;
  1304. //
  1305. // Although normally a class is never called before
  1306. // its constructor. The heap is subject to some strange
  1307. // behaviour so we check to make sure this is not the
  1308. // case.
  1309. //
  1310. if ( Active )
  1311. {
  1312. REGISTER SBIT32 Count;
  1313. //
  1314. // Flush all the caches and to free up
  1315. // as much space as possible.
  1316. //
  1317. for ( Count=0;Count < CachesSize;Count ++ )
  1318. {
  1319. Result =
  1320. (
  1321. (Caches[ Count ] -> Truncate())
  1322. &&
  1323. (Result)
  1324. );
  1325. }
  1326. //
  1327. // We slave all available free space in the top
  1328. // bucket so force it to be released.
  1329. //
  1330. TopCache -> ReleaseSpace
  1331. (
  1332. (MaxFreeSpace / (TopCache -> GetAllocationSize()))
  1333. );
  1334. }
  1335. return Result;
  1336. }
  1337. /********************************************************************/
  1338. /* */
  1339. /* Release all the heap locks. */
  1340. /* */
  1341. /* We release the locks so others can use the heap. */
  1342. /* */
  1343. /********************************************************************/
  1344. VOID HEAP::UnlockAll( BOOLEAN Partial )
  1345. {
  1346. //
  1347. // Although normally a class is never called before
  1348. // its constructor. The heap is subject to some strange
  1349. // behaviour so we check to make sure this is not the
  1350. // case.
  1351. //
  1352. if ( Active )
  1353. {
  1354. //
  1355. // Decrement the per thread lock count.
  1356. //
  1357. Find -> DecrementLockCount();
  1358. //
  1359. // We release the locks only if we have claimed
  1360. // them earlier.
  1361. //
  1362. if ( (Find -> GetLockCount()) == 0 )
  1363. {
  1364. //
  1365. // Now release all the heap locks we claimed
  1366. // earlier and unfreeze the heap.
  1367. //
  1368. NewPage -> ReleaseNewPageLock();
  1369. Find -> ReleaseFindExclusiveLock();
  1370. //
  1371. // When we destroy the heap we hold on
  1372. // to the cache locks to prevent errors.
  1373. //
  1374. if ( ! Partial )
  1375. {
  1376. REGISTER SBIT32 Count;
  1377. //
  1378. // Now release all the cache locks we claimed
  1379. // earlier and unfreeze the cache.
  1380. //
  1381. for ( Count=0;Count < CachesSize;Count ++ )
  1382. { Caches[ Count ] -> ReleaseCacheLock(); }
  1383. }
  1384. }
  1385. }
  1386. }
  1387. /********************************************************************/
  1388. /* */
  1389. /* Verify of a memory allocation. */
  1390. /* */
  1391. /* We need to verify the details of a memory allocation. */
  1392. /* All we have is an address. We use this to find the largest */
  1393. /* allocation page this address is contained in and then */
  1394. /* navigate through the sub-divisions of this page until we */
  1395. /* find the allocation. Finally, we check that the element */
  1396. /* is not in the cache waiting to be allocated or freed. */
  1397. /* */
  1398. /********************************************************************/
  1399. BOOLEAN HEAP::Verify( VOID *Address,SBIT32 *Size )
  1400. {
  1401. //
  1402. // Although normally a class is never called before
  1403. // its constructor. The heap is subject to some strange
  1404. // behaviour so we check to make sure this is not the
  1405. // case.
  1406. //
  1407. if ( Active )
  1408. {
  1409. AUTO SEARCH_PAGE Details;
  1410. AUTO SBIT32 NewSize;
  1411. //
  1412. // We extract the size of the allocation and
  1413. // any associated allocation information.
  1414. // to see if it is present.
  1415. //
  1416. if ( Find -> Details( Address,& Details,TopCache,& NewSize ) )
  1417. {
  1418. //
  1419. // We need to be careful to make sure this
  1420. // element is actually allocated.
  1421. //
  1422. if ( Details.Found )
  1423. {
  1424. //
  1425. // We know that the element appears to be
  1426. // allocated but it may be in the cache
  1427. // somewhere so ensure this is not the case.
  1428. //
  1429. if ( (NewSize > 0) && (NewSize <= MaxCacheSize) )
  1430. {
  1431. if ( Details.Cache -> SearchCache( Address ) )
  1432. { return False; }
  1433. }
  1434. //
  1435. // We have shown that the element is active
  1436. // so return the size if requested.
  1437. //
  1438. if ( Size != NULL )
  1439. { (*Size) = NewSize; }
  1440. return True;
  1441. }
  1442. }
  1443. }
  1444. return False;
  1445. }
  1446. /********************************************************************/
  1447. /* */
  1448. /* Walk the heap. */
  1449. /* */
  1450. /* We have been asked to walk the heap. It is hard to know */
  1451. /* whay anybody might want to do this given the rest of the */
  1452. /* functionality available. Nonetheless, we just do what is */
  1453. /* required to keep everyone happy. */
  1454. /* */
  1455. /********************************************************************/
  1456. BOOLEAN HEAP::Walk
  1457. (
  1458. BOOLEAN *Active,
  1459. VOID **Address,
  1460. SBIT32 *Size
  1461. )
  1462. {
  1463. //
  1464. // Although normally a class is never called before
  1465. // its constructor. The heap is subject to some strange
  1466. // behaviour so we check to make sure this is not the
  1467. // case.
  1468. //
  1469. if ( Active )
  1470. {
  1471. //
  1472. // We walk the heap and find the next allocation
  1473. // along with some basic information.
  1474. //
  1475. if ( Find -> Walk( Active,Address,TopCache,Size ) )
  1476. {
  1477. //
  1478. // We know that the element appears to be
  1479. // allocated but it may be in the cache
  1480. // somewhere so ensure this is not the case.
  1481. //
  1482. if ( ((*Size) > 0) && ((*Size) <= MaxCacheSize) )
  1483. {
  1484. if ( FindCache( (*Size) ) -> SearchCache( (*Address) ) )
  1485. { (*Active) = False; }
  1486. }
  1487. return True;
  1488. }
  1489. }
  1490. return False;
  1491. }
  1492. /********************************************************************/
  1493. /* */
  1494. /* Class destructor. */
  1495. /* */
  1496. /* We would like to destroy the heap at the end of the run */
  1497. /* just to be tidy. However, to do this we need to know that */
  1498. /* all of the other destructors have been called and that the */
  1499. /* application will not request more memory or use any existing */
  1500. /* allocations. We can't know this without help from the */
  1501. /* compiler and OS. */
  1502. /* */
  1503. /********************************************************************/
  1504. HEAP::~HEAP( VOID )
  1505. {
  1506. REGISTER SBIT32 Count;
  1507. //
  1508. // We mark the heap as inactive.
  1509. //
  1510. Active = False;
  1511. //
  1512. // We claim all of the heap locks to freeze
  1513. // all new allocations or deletions.
  1514. //
  1515. LockAll();
  1516. //
  1517. // Now reset all the caches.
  1518. //
  1519. for ( Count=0;Count < CachesSize;Count ++ )
  1520. { Caches[ Count ] -> DeleteAll(); }
  1521. //
  1522. // Delete the heap.
  1523. //
  1524. NewPage -> DeleteAll( False );
  1525. //
  1526. // We release any of the shared locks we
  1527. // cliamed earlier.
  1528. //
  1529. UnlockAll( True );
  1530. #ifdef ENABLE_HEAP_STATISTICS
  1531. //
  1532. // Deal with heap statistics.
  1533. //
  1534. if ( Statistics != NULL )
  1535. {
  1536. //
  1537. // Print all the statistics.
  1538. //
  1539. PrintDebugStatistics();
  1540. //
  1541. // Deallocate the area.
  1542. //
  1543. Rockall -> DeleteArea
  1544. (
  1545. ((VOID*) Statistics),
  1546. (MaxCacheSize * sizeof(SBIT32)),
  1547. False
  1548. );
  1549. }
  1550. #endif
  1551. //
  1552. // Delete the heap mapping tables.
  1553. //
  1554. if ( SizeToCache1 != NULL )
  1555. {
  1556. //
  1557. // Deallocate the area.
  1558. //
  1559. Rockall -> DeleteArea
  1560. (
  1561. ((VOID*) SizeToCache1),
  1562. (MaxTable1 + MaxTable2),
  1563. False
  1564. );
  1565. }
  1566. }