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.

1680 lines
48 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 "InterfacePCH.hpp"
  25. #include "Cache.hpp"
  26. #include "Common.hpp"
  27. #include "Find.hpp"
  28. #include "Heap.hpp"
  29. #include "New.hpp"
  30. #include "NewPage.hpp"
  31. #include "Rockall.hpp"
  32. #include "Spinlock.hpp"
  33. /********************************************************************/
  34. /* */
  35. /* Constants local to the class. */
  36. /* */
  37. /* The constants supplied here try to make the layout of the */
  38. /* the caches easier to understand and update. */
  39. /* */
  40. /********************************************************************/
  41. CONST SBIT32 EnableLookAside = 0;
  42. CONST SBIT32 GlobalMask = (sizeof(SBIT64) - 1);
  43. CONST SBIT32 GlobalPaddedSize = (sizeof(FIND) + GlobalMask);
  44. CONST SBIT32 GlobalByteSize = (GlobalPaddedSize & ~GlobalMask);
  45. CONST SBIT32 GlobalWordSize = (GlobalByteSize / sizeof(SBIT64));
  46. /********************************************************************/
  47. /* */
  48. /* Static member initialization. */
  49. /* */
  50. /* Static member initialization sets the initial value for all */
  51. /* static members. */
  52. /* */
  53. /********************************************************************/
  54. STATIC SBIT64 GlobalFind[ GlobalWordSize ];
  55. STATIC SBIT32 ReferenceCount = 0;
  56. STATIC SPINLOCK Spinlock;
  57. /********************************************************************/
  58. /* */
  59. /* Class constructor. */
  60. /* */
  61. /* The interface default constructor creates a null heap for */
  62. /* internal use by selected classes. */
  63. /* */
  64. /********************************************************************/
  65. ROCKALL::ROCKALL( void )
  66. {
  67. //
  68. // A heap constructed by this constructor should
  69. // never be used. Hence, we zero key pointers to
  70. // ensure grave disorder will result if anyone tries.
  71. //
  72. Array = NULL;
  73. Caches = NULL;
  74. Find = NULL;
  75. Heap = NULL;
  76. NewPage = NULL;
  77. GlobalDelete = True;
  78. GuardWord = GuardValue;
  79. NumberOfCaches = 0;
  80. TotalSize = 0;
  81. }
  82. /********************************************************************/
  83. /* */
  84. /* Class constructor. */
  85. /* */
  86. /* The overall structure and layout of the heap is controlled */
  87. /* by the various constants and calls made in this function. */
  88. /* There is a significant amount of flexibility within heaps */
  89. /* leading to potentially dramatically different properties. */
  90. /* */
  91. /********************************************************************/
  92. ROCKALL::ROCKALL
  93. (
  94. CACHE_DETAILS *Caches1,
  95. CACHE_DETAILS *Caches2,
  96. int FindCacheSize,
  97. int FindCacheThreshold,
  98. int FindSize,
  99. int MaxFreeSpace,
  100. int *NewPageSizes,
  101. bool Recycle,
  102. bool SingleImage,
  103. int Stride1,
  104. int Stride2,
  105. bool ThreadSafe
  106. )
  107. {
  108. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  109. TRY
  110. #endif
  111. {
  112. REGISTER int AlignMask = ((int) (NaturalSize()-1));
  113. REGISTER int Stride = (sizeof(CACHE_DETAILS));
  114. REGISTER int Size1 = (ComputeSize( ((char*) Caches1),Stride ));
  115. REGISTER int Size2 = (ComputeSize( ((char*) Caches2),Stride ));
  116. REGISTER int Size3 = (ComputeSize( ((char*) NewPageSizes),sizeof(int) ));
  117. //
  118. // The interface pointer members are zeroed to
  119. // ensure they do not end up containing random
  120. // rubbish whatever happens.
  121. //
  122. Array = NULL;
  123. Caches = NULL;
  124. Find = NULL;
  125. Heap = NULL;
  126. NewPage = NULL;
  127. //
  128. // Set key flags and compute information about
  129. // the number of caches and the total amount of
  130. // space required for the low level heap structures.
  131. //
  132. GlobalDelete = SingleImage;
  133. GuardWord = GuardValue;
  134. NumberOfCaches = (Size1 + Size2);
  135. TotalSize =
  136. (
  137. (NumberOfCaches * sizeof(CACHE*))
  138. +
  139. (NumberOfCaches * sizeof(CACHE))
  140. +
  141. ((GlobalDelete) ? 0 : sizeof(FIND))
  142. +
  143. (sizeof(NEW_PAGE))
  144. +
  145. (sizeof(HEAP))
  146. );
  147. //
  148. // Ensure the alignment mask is valid and we have
  149. // at least four caches. If not the heap will be
  150. // worthless.
  151. //
  152. if
  153. (
  154. (COMMON::PowerOfTwo( ((SBIT32) (AlignMask+1)) ))
  155. &&
  156. ((Size1 >= 1) && (Size2 >= 3))
  157. &&
  158. ((Stride1 > 0) && (COMMON::PowerOfTwo( Stride1 )))
  159. &&
  160. ((Stride2 >= Stride1) && (COMMON::PowerOfTwo( Stride2 )))
  161. )
  162. {
  163. REGISTER CHAR *NewMemory =
  164. ((CHAR*) NewArea( ((SBIT32) AlignMask),TotalSize,False ));
  165. //
  166. // We check to make sure that we can allocate space
  167. // to store the low level heap control information.
  168. // If not we exit.
  169. //
  170. if ( NewMemory != NULL )
  171. {
  172. REGISTER SBIT32 Count;
  173. //
  174. // Build the caches.
  175. //
  176. // The first step in creating a heap is to
  177. // create all the caches and related buckets
  178. // requested by the user.
  179. //
  180. Caches = ((CACHE*) NewMemory);
  181. NewMemory += (NumberOfCaches * sizeof(CACHE));
  182. for ( Count=0;Count < Size1;Count ++ )
  183. {
  184. REGISTER CACHE_DETAILS *Current = & Caches1[ Count ];
  185. PLACEMENT_NEW( & Caches[ Count ],CACHE )
  186. (
  187. ((SBIT32) Current -> AllocationSize),
  188. ((SBIT32) Current -> CacheSize),
  189. ((SBIT32) Current -> ChunkSize),
  190. ((SBIT32) Current -> PageSize),
  191. ((BOOLEAN) Recycle),
  192. ((BOOLEAN) ThreadSafe)
  193. );
  194. }
  195. for ( Count=0;Count < Size2;Count ++ )
  196. {
  197. REGISTER CACHE_DETAILS *Current = & Caches2[ Count ];
  198. PLACEMENT_NEW( & Caches[ (Count + Size1) ],CACHE )
  199. (
  200. ((SBIT32) Current -> AllocationSize),
  201. ((SBIT32) Current -> CacheSize),
  202. ((SBIT32) Current -> ChunkSize),
  203. ((SBIT32) Current -> PageSize),
  204. ((BOOLEAN) Recycle),
  205. ((BOOLEAN) ThreadSafe)
  206. );
  207. }
  208. //
  209. // Build the cache array.
  210. //
  211. // After we have constructed all of the caches
  212. // we take the address of each cache and load
  213. // it into an array. This indirection allows
  214. // caches to be shared between heaps.
  215. //
  216. Array = (CACHE**) NewMemory;
  217. NewMemory += (NumberOfCaches * sizeof(CACHE*));
  218. for ( Count=0;Count < NumberOfCaches;Count ++ )
  219. { Array[ Count ] = & Caches[ Count ]; }
  220. //
  221. // Configuration of the find hash table.
  222. //
  223. // The find hash table maps addresses to page
  224. // descriptions and is a key part of the memory
  225. // deallocation mechanism. Here we specify
  226. // the size of the hash table. It is important
  227. // to size it based on the expected number of
  228. // memory allocations. Nonetheless, it will
  229. // automatically grow if the correct option is
  230. // set and it is clearly too small.
  231. //
  232. if ( GlobalDelete )
  233. {
  234. //
  235. // We claim a lock just in case there
  236. // are multiple threads.
  237. //
  238. Spinlock.ClaimLock();
  239. //
  240. // We create the global find hash table
  241. // if we are the first thread to create
  242. // a heap.
  243. //
  244. if ( (ReferenceCount ++) == 0 )
  245. {
  246. STATIC ROCKALL Rockall;
  247. //
  248. // Select the global find table
  249. // and call the constructor.
  250. //
  251. Find = ((FIND*) GlobalFind);
  252. PLACEMENT_NEW( Find,FIND )
  253. (
  254. ((SBIT32) FindSize),
  255. ((SBIT32) FindCacheSize),
  256. ((SBIT32) EnableLookAside),
  257. ((ROCKALL*) & Rockall),
  258. ((BOOLEAN) True),
  259. ((BOOLEAN) (GlobalDelete || ThreadSafe))
  260. );
  261. }
  262. else
  263. {
  264. //
  265. // A global find has table already
  266. // exists so just use it.
  267. //
  268. Find = ((FIND*) GlobalFind);
  269. }
  270. //
  271. // Release the lock now.
  272. //
  273. Spinlock.ReleaseLock();
  274. }
  275. else
  276. {
  277. Find = (FIND*) NewMemory;
  278. NewMemory += sizeof(FIND);
  279. //
  280. // We create a local find hash table
  281. // if we are do not need to provide
  282. // a single heap image.
  283. //
  284. PLACEMENT_NEW( Find,FIND )
  285. (
  286. ((SBIT32) FindSize),
  287. ((SBIT32) FindCacheSize),
  288. ((SBIT32) FindCacheThreshold),
  289. ((ROCKALL*) this),
  290. ((BOOLEAN) True),
  291. ((BOOLEAN) ThreadSafe)
  292. );
  293. }
  294. //
  295. // Configuration of the allocation overhead.
  296. //
  297. // The allocation overhead is controlled by
  298. // the size of the bit vectors used to keep
  299. // track of the allocations. There is a built
  300. // in limit of ((2^15)-1) elements in a single
  301. // bit vector.
  302. //
  303. NewPage = (NEW_PAGE*) NewMemory;
  304. NewMemory += sizeof(NEW_PAGE);
  305. PLACEMENT_NEW( NewPage,NEW_PAGE )
  306. (
  307. ((FIND*) Find),
  308. ((SBIT32*) NewPageSizes),
  309. ((ROCKALL*) this),
  310. ((SBIT32) Size3),
  311. ((BOOLEAN) ThreadSafe)
  312. );
  313. //
  314. // Create the heap.
  315. //
  316. // We can now create the heap. We do this
  317. // by passing pointers to all the parts of
  318. // the heap that we have just created.
  319. //
  320. //
  321. Heap = (HEAP*) NewMemory;
  322. PLACEMENT_NEW( Heap,HEAP )
  323. (
  324. ((CACHE**) & Array[0]),
  325. ((CACHE**) & Array[ Size1 ]),
  326. ((SBIT32) MaxFreeSpace),
  327. ((FIND*) Find),
  328. ((NEW_PAGE*) NewPage),
  329. ((ROCKALL*) this),
  330. ((SBIT32) Size1),
  331. ((SBIT32) Size2),
  332. ((SBIT32) Stride1),
  333. ((SBIT32) Stride2),
  334. ThreadSafe
  335. );
  336. }
  337. else
  338. { Failure( "Heap constructor failed in ROCKALL" ); }
  339. }
  340. else
  341. { Failure( "Cache size in constructor for ROCKALL" ); }
  342. }
  343. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  344. #ifdef DEBUGGING
  345. catch ( FAULT Message )
  346. {
  347. //
  348. // It looks like the heap is corrupt. So
  349. // lets just mark it as unusable, print a
  350. // suitable message and exit.
  351. //
  352. GuardWord = AllocationFailure;
  353. DebugPrint( "Exception caught: %s\n",(char*) Message );
  354. }
  355. #endif
  356. catch ( ... )
  357. {
  358. //
  359. // It looks like the heap is corrupt. So
  360. // lets just mark it as unusable and exit.
  361. //
  362. GuardWord = AllocationFailure;
  363. }
  364. #endif
  365. }
  366. /********************************************************************/
  367. /* */
  368. /* Compute the size of the caches. */
  369. /* */
  370. /* Compute the size of various data structures for internal */
  371. /* sizing purposes. */
  372. /* */
  373. /********************************************************************/
  374. int ROCKALL::ComputeSize( char *Array,int Stride )
  375. {
  376. register int Count;
  377. for
  378. (
  379. Count=0;
  380. ((*((int*) & Array[ Count ])) != 0);
  381. Count += Stride
  382. );
  383. return (Count / Stride);
  384. }
  385. /********************************************************************/
  386. /* */
  387. /* Memory deallocation. */
  388. /* */
  389. /* Lets start with some basic tests. If the address we have */
  390. /* been given is special, clearly wrong or the heap has not */
  391. /* been initialized then we fail and exit. */
  392. /* */
  393. /********************************************************************/
  394. bool ROCKALL::Delete( void *Address,int Size )
  395. {
  396. TRY
  397. {
  398. //
  399. // We verify that the parameters look
  400. // reasonable and the heap is not corrupt
  401. // and then try to delete the supplied
  402. // allocation.
  403. //
  404. if ( Available() )
  405. { return (Heap -> Delete( ((VOID*) Address),((SBIT32) Size) )); }
  406. }
  407. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  408. #ifdef DEBUGGING
  409. catch ( FAULT Message )
  410. {
  411. //
  412. // It looks like the heap is corrupt. So
  413. // lets just mark it as unusable, print a
  414. // suitable message and exit.
  415. //
  416. GuardWord = AllocationFailure;
  417. DebugPrint( "Exception caught: %s\n",(char*) Message );
  418. }
  419. #endif
  420. catch ( ... )
  421. {
  422. //
  423. // It looks like the heap is corrupt. So
  424. // lets just mark it as unusable and exit.
  425. //
  426. GuardWord = AllocationFailure;
  427. }
  428. #else
  429. __except ( EXCEPTION_EXECUTE_HANDLER )
  430. {
  431. //
  432. // It looks like the heap is corrupt. So
  433. // lets just mark it as unusable and exit.
  434. //
  435. GuardWord = AllocationFailure;
  436. }
  437. #endif
  438. return false;
  439. }
  440. /********************************************************************/
  441. /* */
  442. /* Delete all allocations. */
  443. /* */
  444. /* At certain places in am application we sometimes need to */
  445. /* delete a significant number of allocations. If all of */
  446. /* these allocations are placed into a single heap we can */
  447. /* delete them all using this call. */
  448. /* */
  449. /********************************************************************/
  450. void ROCKALL::DeleteAll( bool Recycle )
  451. {
  452. TRY
  453. {
  454. //
  455. // The call appears to be valid so if the
  456. // heap is not corrupt then pass it along
  457. // for processing.
  458. //
  459. if ( Available() )
  460. { Heap -> DeleteAll( (BOOLEAN) Recycle ); }
  461. }
  462. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  463. #ifdef DEBUGGING
  464. catch ( FAULT Message )
  465. {
  466. //
  467. // It looks like the heap is corrupt. So
  468. // lets just mark it as unusable, print a
  469. // suitable message and exit.
  470. //
  471. GuardWord = AllocationFailure;
  472. DebugPrint( "Exception caught: %s\n",(char*) Message );
  473. }
  474. #endif
  475. catch ( ... )
  476. {
  477. //
  478. // It looks like the heap is corrupt. So
  479. // lets just mark it as unusable and exit.
  480. //
  481. GuardWord = AllocationFailure;
  482. }
  483. #else
  484. __except ( EXCEPTION_EXECUTE_HANDLER )
  485. {
  486. //
  487. // It looks like the heap is corrupt. So
  488. // lets just mark it as unusable and exit.
  489. //
  490. GuardWord = AllocationFailure;
  491. }
  492. #endif
  493. }
  494. /********************************************************************/
  495. /* */
  496. /* Delete allocation area. */
  497. /* */
  498. /* All memory requests are eventually sent back to the external */
  499. /* deallocator. This function can be overloaded so that memory */
  500. /* can be provided from any source. The default is to send */
  501. /* the area back to the operating system. */
  502. /* */
  503. /********************************************************************/
  504. void ROCKALL::DeleteArea( void *Memory,int Size,bool User )
  505. {
  506. REGISTER DWORD NewSize = ((Size == 0) ? Size : 0);
  507. #ifdef DEBUGGING
  508. #ifdef ENABLE_ALLOCATION_STATISTICS
  509. //
  510. // When we are debugging print out trace information.
  511. //
  512. DebugPrint( "Delete\t 0x%08x %d bytes\n",Memory,Size );
  513. #endif
  514. #endif
  515. //
  516. // The NT 'VirtualFree' call requires the 'Size'
  517. // to be zero. This may not be true of all
  518. // deallocators so we pass the value and then
  519. // replace it with zero above.
  520. //
  521. if ( VirtualFree( Memory,NewSize,MEM_RELEASE ) == NULL )
  522. { Failure( "Delete fails in DeleteArea" ); }
  523. }
  524. /********************************************************************/
  525. /* */
  526. /* Memory allocation details. */
  527. /* */
  528. /* Lets start with some basic tests. If the address we have */
  529. /* been given is special, clearly wrong or the heap has not */
  530. /* been initialized then we fail the call appropriately. */
  531. /* */
  532. /********************************************************************/
  533. bool ROCKALL::Details( void *Address,int *Space )
  534. {
  535. TRY
  536. {
  537. //
  538. // The call appears to be valid so if the
  539. // heap is not corrupt then pass it along
  540. // for processing.
  541. //
  542. if ( Available() )
  543. { return (Heap -> Details( ((VOID*) Address),((SBIT32*) Space) )); }
  544. }
  545. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  546. #ifdef DEBUGGING
  547. catch ( FAULT Message )
  548. {
  549. //
  550. // It looks like the heap is corrupt. So
  551. // lets just mark it as unusable, print a
  552. // suitable message and exit.
  553. //
  554. GuardWord = AllocationFailure;
  555. DebugPrint( "Exception caught: %s\n",(char*) Message );
  556. }
  557. #endif
  558. catch ( ... )
  559. {
  560. //
  561. // It looks like the heap is corrupt. So
  562. // lets just mark it as unusable and exit.
  563. //
  564. GuardWord = AllocationFailure;
  565. }
  566. #else
  567. __except ( EXCEPTION_EXECUTE_HANDLER )
  568. {
  569. //
  570. // It looks like the heap is corrupt. So
  571. // lets just mark it as unusable and exit.
  572. //
  573. GuardWord = AllocationFailure;
  574. }
  575. #endif
  576. return false;
  577. }
  578. /********************************************************************/
  579. /* */
  580. /* A known area. */
  581. /* */
  582. /* We have an address and don't have a clue which heap */
  583. /* owns the space. Here we take a look at the address */
  584. /* and figure out it it belongs to the current heap. */
  585. /* */
  586. /********************************************************************/
  587. bool ROCKALL::KnownArea( void *Address )
  588. {
  589. TRY
  590. {
  591. //
  592. // The call appears to be valid so if the
  593. // heap is not corrupt then pass it along
  594. // for processing.
  595. //
  596. if ( Available() )
  597. {
  598. return ( Heap -> KnownArea( ((VOID*) Address) ) );
  599. }
  600. }
  601. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  602. #ifdef DEBUGGING
  603. catch ( FAULT Message )
  604. {
  605. //
  606. // It looks like the heap is corrupt. So
  607. // lets just mark it as unusable, print a
  608. // suitable message and exit.
  609. //
  610. GuardWord = AllocationFailure;
  611. DebugPrint( "Exception caught: %s\n",(char*) Message );
  612. }
  613. #endif
  614. catch ( ... )
  615. {
  616. //
  617. // It looks like the heap is corrupt. So
  618. // lets just mark it as unusable and exit.
  619. //
  620. GuardWord = AllocationFailure;
  621. }
  622. #else
  623. __except ( EXCEPTION_EXECUTE_HANDLER )
  624. {
  625. //
  626. // It looks like the heap is corrupt. So
  627. // lets just mark it as unusable and exit.
  628. //
  629. GuardWord = AllocationFailure;
  630. }
  631. #endif
  632. return false;
  633. }
  634. /********************************************************************/
  635. /* */
  636. /* Claim all the heap locks. */
  637. /* */
  638. /* Lets start with some basic tests. If the address we have */
  639. /* been given is special, clearly wrong or the heap has not */
  640. /* been initialized then we fail and exit. */
  641. /* */
  642. /********************************************************************/
  643. void ROCKALL::LockAll( VOID )
  644. {
  645. TRY
  646. {
  647. //
  648. // The call appears to be valid so if the
  649. // heap is not corrupt then pass it along
  650. // for processing.
  651. //
  652. if ( Available() )
  653. { Heap -> LockAll(); }
  654. }
  655. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  656. #ifdef DEBUGGING
  657. catch ( FAULT Message )
  658. {
  659. //
  660. // It looks like the heap is corrupt. So
  661. // lets just mark it as unusable, print a
  662. // suitable message and exit.
  663. //
  664. GuardWord = AllocationFailure;
  665. DebugPrint( "Exception caught: %s\n",(char*) Message );
  666. }
  667. #endif
  668. catch ( ... )
  669. {
  670. //
  671. // It looks like the heap is corrupt. So
  672. // lets just mark it as unusable and exit.
  673. //
  674. GuardWord = AllocationFailure;
  675. }
  676. #else
  677. __except ( EXCEPTION_EXECUTE_HANDLER )
  678. {
  679. //
  680. // It looks like the heap is corrupt. So
  681. // lets just mark it as unusable and exit.
  682. //
  683. GuardWord = AllocationFailure;
  684. }
  685. #endif
  686. }
  687. /********************************************************************/
  688. /* */
  689. /* Multiple memory deallocations. */
  690. /* */
  691. /* Lets start with some basic tests. If the address we have */
  692. /* been given is special, clearly wrong or the heap has not */
  693. /* been initialized then we fail and exit. */
  694. /* */
  695. /********************************************************************/
  696. bool ROCKALL::MultipleDelete
  697. (
  698. int Actual,
  699. void *Array[],
  700. int Size
  701. )
  702. {
  703. TRY
  704. {
  705. //
  706. // We verify that the parameters look
  707. // reasonable and the heap is not corrupt
  708. // and then try to delete the supplied
  709. // allocations.
  710. //
  711. if ( (Actual > 0) && (Array != NULL) && (Available()) )
  712. {
  713. return
  714. (
  715. Heap -> MultipleDelete
  716. (
  717. ((SBIT32) Actual),
  718. ((VOID**) Array),
  719. ((SBIT32) Size)
  720. )
  721. );
  722. }
  723. }
  724. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  725. #ifdef DEBUGGING
  726. catch ( FAULT Message )
  727. {
  728. //
  729. // It looks like the heap is corrupt. So
  730. // lets just mark it as unusable, print a
  731. // suitable message and exit.
  732. //
  733. GuardWord = AllocationFailure;
  734. DebugPrint( "Exception caught: %s\n",(char*) Message );
  735. }
  736. #endif
  737. catch ( ... )
  738. {
  739. //
  740. // It looks like the heap is corrupt. So
  741. // lets just mark it as unusable and exit.
  742. //
  743. GuardWord = AllocationFailure;
  744. }
  745. #else
  746. __except ( EXCEPTION_EXECUTE_HANDLER )
  747. {
  748. //
  749. // It looks like the heap is corrupt. So
  750. // lets just mark it as unusable and exit.
  751. //
  752. GuardWord = AllocationFailure;
  753. }
  754. #endif
  755. return false;
  756. }
  757. /********************************************************************/
  758. /* */
  759. /* Multiple memory allocations. */
  760. /* */
  761. /* Lets start with some basic tests. If the address we have */
  762. /* been given is special, clearly wrong or the heap has not */
  763. /* been initialized then we fail and exit. */
  764. /* */
  765. /********************************************************************/
  766. bool ROCKALL::MultipleNew
  767. (
  768. int *Actual,
  769. void *Array[],
  770. int Requested,
  771. int Size,
  772. int *Space,
  773. bool Zero
  774. )
  775. {
  776. TRY
  777. {
  778. //
  779. // We verify that the parameters look
  780. // reasonable and the heap is not corrupt
  781. // and then try to create the requested
  782. // allocation.
  783. //
  784. if
  785. (
  786. ((Array != NULL) && (Available()))
  787. &&
  788. ((Requested > 0) && (Size >= 0))
  789. )
  790. {
  791. return
  792. (
  793. Heap -> MultipleNew
  794. (
  795. ((SBIT32*) Actual),
  796. ((VOID**) Array),
  797. ((SBIT32) Requested),
  798. ((SBIT32) ((Size > 0) ? Size : 1)),
  799. ((SBIT32*) Space),
  800. ((BOOLEAN) Zero)
  801. )
  802. );
  803. }
  804. }
  805. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  806. #ifdef DEBUGGING
  807. catch ( FAULT Message )
  808. {
  809. //
  810. // It looks like the heap is corrupt. So
  811. // lets just mark it as unusable, print a
  812. // suitable message and exit.
  813. //
  814. GuardWord = AllocationFailure;
  815. DebugPrint( "Exception caught: %s\n",(char*) Message );
  816. }
  817. #endif
  818. catch ( ... )
  819. {
  820. //
  821. // It looks like the heap is corrupt. So
  822. // lets just mark it as unusable and exit.
  823. //
  824. GuardWord = AllocationFailure;
  825. }
  826. #else
  827. __except ( EXCEPTION_EXECUTE_HANDLER )
  828. {
  829. //
  830. // It looks like the heap is corrupt. So
  831. // lets just mark it as unusable and exit.
  832. //
  833. GuardWord = AllocationFailure;
  834. }
  835. #endif
  836. return false;
  837. }
  838. /********************************************************************/
  839. /* */
  840. /* The natural allocation size. */
  841. /* */
  842. /* We would like to know a good default size for allocations. */
  843. /* The default is to ask the operating system for the */
  844. /* allocation granularity. */
  845. /* */
  846. /********************************************************************/
  847. int ROCKALL::NaturalSize( void )
  848. {
  849. STATIC SBIT32 AllocationSize = 0;
  850. //
  851. // Ask the operation system for the allocation
  852. // granularity.
  853. //
  854. if ( AllocationSize <= 0 )
  855. {
  856. AUTO SYSTEM_INFO SystemInformation;
  857. GetSystemInfo( & SystemInformation );
  858. AllocationSize = (SBIT32) SystemInformation.dwAllocationGranularity;
  859. }
  860. return ((int) AllocationSize);
  861. }
  862. /********************************************************************/
  863. /* */
  864. /* Memory allocation. */
  865. /* */
  866. /* Lets start with some basic tests. If the address we have */
  867. /* been given is special, clearly wrong or the heap has not */
  868. /* been initialized then we fail and exit. */
  869. /* */
  870. /********************************************************************/
  871. void *ROCKALL::New( int Size,int *Space,bool Zero )
  872. {
  873. TRY
  874. {
  875. //
  876. // We verify that the parameters look
  877. // reasonable and the heap is not corrupt
  878. // and then try to create the requested
  879. // allocation.
  880. //
  881. if ( (Available()) && (Size >= 0) )
  882. {
  883. return
  884. (
  885. Heap -> New
  886. (
  887. ((SBIT32) ((Size > 0) ? Size : 1)),
  888. ((SBIT32*) Space),
  889. ((BOOLEAN) Zero)
  890. )
  891. );
  892. }
  893. }
  894. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  895. #ifdef DEBUGGING
  896. catch ( FAULT Message )
  897. {
  898. //
  899. // It looks like the heap is corrupt. So
  900. // lets just mark it as unusable, print a
  901. // suitable message and exit.
  902. //
  903. GuardWord = AllocationFailure;
  904. DebugPrint( "Exception caught: %s\n",(char*) Message );
  905. }
  906. #endif
  907. catch ( ... )
  908. {
  909. //
  910. // It looks like the heap is corrupt. So
  911. // lets just mark it as unusable and exit.
  912. //
  913. GuardWord = AllocationFailure;
  914. }
  915. #else
  916. __except ( EXCEPTION_EXECUTE_HANDLER )
  917. {
  918. //
  919. // It looks like the heap is corrupt. So
  920. // lets just mark it as unusable and exit.
  921. //
  922. GuardWord = AllocationFailure;
  923. }
  924. #endif
  925. return ((void*) AllocationFailure);
  926. }
  927. /********************************************************************/
  928. /* */
  929. /* New allocation area. */
  930. /* */
  931. /* All memory requests are eventually sent to the new external */
  932. /* allocator. This function can be overloaded so that memory */
  933. /* can be provided from any source. The default is to get */
  934. /* new memory from the operating system. */
  935. /* */
  936. /********************************************************************/
  937. void *ROCKALL::NewArea( int AlignMask,int Size,bool User )
  938. {
  939. //
  940. // When there is an alignment requirement greater
  941. // than the natural alignment provided by the
  942. // operating system we have to play various tricks
  943. // to allocate a suitable block. If not then we
  944. // just do a normal allocation call.
  945. //
  946. if ( AlignMask > NaturalSize() )
  947. {
  948. REGISTER SBIT32 NewSize = (AlignMask + Size);
  949. //
  950. // We need to allocate a block with an
  951. // alignment requirement greater than
  952. // the operating system default. So we
  953. // allocate a much larger block and
  954. // release the parts we don't need.
  955. //
  956. while ( True )
  957. {
  958. REGISTER VOID *Reserved =
  959. (
  960. VirtualAlloc
  961. (
  962. NULL,
  963. ((DWORD) NewSize),
  964. MEM_RESERVE,
  965. PAGE_READWRITE
  966. )
  967. );
  968. //
  969. // Lets ensure we were able to find a suitable
  970. // memory block. If not then we exit.
  971. //
  972. if ( Reserved != NULL )
  973. {
  974. //
  975. // We just want to return the parts of
  976. // the block we don't need but 'NT' is
  977. // not smart enough. So we free the
  978. // entire block.
  979. //
  980. if ( VirtualFree( Reserved,0,MEM_RELEASE ) )
  981. {
  982. REGISTER LONG Address = ((LONG) Reserved);
  983. REGISTER VOID *NewMemory;
  984. //
  985. // Compute the base address of the part
  986. // of the block we really want to allocate.
  987. //
  988. Address = ((Address + AlignMask) & ~AlignMask);
  989. //
  990. // Finally, lets reallocate the part of
  991. // the block we wanted but just released
  992. // and hope that nobody else got it before
  993. // us.
  994. //
  995. NewMemory =
  996. (
  997. VirtualAlloc
  998. (
  999. ((LPVOID) Address),
  1000. ((DWORD) Size),
  1001. (MEM_RESERVE | MEM_COMMIT),
  1002. PAGE_READWRITE
  1003. )
  1004. );
  1005. //
  1006. // If it all worked we can exit.
  1007. //
  1008. if ( NewMemory != NULL )
  1009. {
  1010. #ifdef DEBUGGING
  1011. #ifdef ENABLE_ALLOCATION_STATISTICS
  1012. //
  1013. // When we are debugging output
  1014. // out trace information.
  1015. //
  1016. DebugPrint
  1017. (
  1018. "New\t\t 0x%08x %d bytes\n",
  1019. NewMemory,
  1020. Size
  1021. );
  1022. #endif
  1023. #endif
  1024. return ((void*) NewMemory);
  1025. }
  1026. }
  1027. else
  1028. { return ((void*) AllocationFailure); }
  1029. }
  1030. else
  1031. { return ((void*) AllocationFailure); }
  1032. }
  1033. }
  1034. else
  1035. {
  1036. REGISTER VOID *NewMemory;
  1037. //
  1038. // We can allocate directly from the operating
  1039. // system as the default alignment requirement
  1040. // is enough for this case.
  1041. //
  1042. NewMemory =
  1043. (
  1044. VirtualAlloc
  1045. (
  1046. NULL,
  1047. ((DWORD) Size),
  1048. MEM_COMMIT,
  1049. PAGE_READWRITE
  1050. )
  1051. );
  1052. #ifdef DEBUGGING
  1053. #ifdef ENABLE_ALLOCATION_STATISTICS
  1054. if ( NewMemory != NULL )
  1055. {
  1056. //
  1057. // When we are debugging output out trace
  1058. // information.
  1059. //
  1060. DebugPrint( "New\t\t 0x%08x %d bytes\n",NewMemory,Size );
  1061. }
  1062. #endif
  1063. #endif
  1064. return ((void*) NewMemory);
  1065. }
  1066. }
  1067. /********************************************************************/
  1068. /* */
  1069. /* Memory reallocation. */
  1070. /* */
  1071. /* Lets start with some basic tests. If the address we have */
  1072. /* been given is special, clearly wrong or the heap has not */
  1073. /* been initialized then we fail and exit. */
  1074. /* */
  1075. /********************************************************************/
  1076. void *ROCKALL::Resize
  1077. (
  1078. void *Address,
  1079. int NewSize,
  1080. int Move,
  1081. int *Space,
  1082. bool NoDelete,
  1083. bool Zero
  1084. )
  1085. {
  1086. TRY
  1087. {
  1088. //
  1089. // A well known practice is to try to
  1090. // resize a null pointer. This is really
  1091. // a very poor style but we support it
  1092. // in any case.
  1093. //
  1094. if ( Address != ((void*) AllocationFailure) )
  1095. {
  1096. //
  1097. // We verify that the parameters look
  1098. // reasonable and the heap is not corrupt
  1099. // and then try to resize the supplied
  1100. // allocation.
  1101. //
  1102. if ( (Available()) && (NewSize >= 0) )
  1103. {
  1104. return
  1105. (
  1106. Heap -> Resize
  1107. (
  1108. ((VOID*) Address),
  1109. ((SBIT32) ((NewSize > 0) ? NewSize : 1)),
  1110. ((SBIT32) Move),
  1111. ((SBIT32*) Space),
  1112. ((BOOLEAN) NoDelete),
  1113. ((BOOLEAN) Zero)
  1114. )
  1115. );
  1116. }
  1117. }
  1118. else
  1119. { return (New( NewSize,Space,Zero )); }
  1120. }
  1121. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  1122. #ifdef DEBUGGING
  1123. catch ( FAULT Message )
  1124. {
  1125. //
  1126. // It looks like the heap is corrupt. So
  1127. // lets just mark it as unusable, print a
  1128. // suitable message and exit.
  1129. //
  1130. GuardWord = AllocationFailure;
  1131. DebugPrint( "Exception caught: %s\n",(char*) Message );
  1132. }
  1133. #endif
  1134. catch ( ... )
  1135. {
  1136. //
  1137. // It looks like the heap is corrupt. So
  1138. // lets just mark it as unusable and exit.
  1139. //
  1140. GuardWord = AllocationFailure;
  1141. }
  1142. #else
  1143. __except ( EXCEPTION_EXECUTE_HANDLER )
  1144. {
  1145. //
  1146. // It looks like the heap is corrupt. So
  1147. // lets just mark it as unusable and exit.
  1148. //
  1149. GuardWord = AllocationFailure;
  1150. }
  1151. #endif
  1152. return ((void*) AllocationFailure);
  1153. }
  1154. /********************************************************************/
  1155. /* */
  1156. /* Special memory allocation. */
  1157. /* */
  1158. /* We sometimes need to allocate some memory from the internal */
  1159. /* memory allocator which lives for the lifetime of the heap. */
  1160. /* */
  1161. /********************************************************************/
  1162. void *ROCKALL::SpecialNew( int Size )
  1163. {
  1164. TRY
  1165. {
  1166. //
  1167. // We verify that the parameters look
  1168. // reasonable and the heap is not corrupt
  1169. // and then try to create the requested
  1170. // allocation.
  1171. //
  1172. if ( (Available()) && (Size > 0) )
  1173. { return (Heap -> SpecialNew( ((SBIT32) Size) )); }
  1174. }
  1175. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  1176. #ifdef DEBUGGING
  1177. catch ( FAULT Message )
  1178. {
  1179. //
  1180. // It looks like the heap is corrupt. So
  1181. // lets just mark it as unusable, print a
  1182. // suitable message and exit.
  1183. //
  1184. GuardWord = AllocationFailure;
  1185. DebugPrint( "Exception caught: %s\n",(char*) Message );
  1186. }
  1187. #endif
  1188. catch ( ... )
  1189. {
  1190. //
  1191. // It looks like the heap is corrupt. So
  1192. // lets just mark it as unusable and exit.
  1193. //
  1194. GuardWord = AllocationFailure;
  1195. }
  1196. #else
  1197. __except ( EXCEPTION_EXECUTE_HANDLER )
  1198. {
  1199. //
  1200. // It looks like the heap is corrupt. So
  1201. // lets just mark it as unusable and exit.
  1202. //
  1203. GuardWord = AllocationFailure;
  1204. }
  1205. #endif
  1206. return ((void*) AllocationFailure);
  1207. }
  1208. /********************************************************************/
  1209. /* */
  1210. /* Truncate the heap. */
  1211. /* */
  1212. /* We need to truncate the heap. This is pretty much a null */
  1213. /* call as we do this as we go along anyway. The only thing we */
  1214. /* can do is free any space the user suggested keeping earlier. */
  1215. /* */
  1216. /********************************************************************/
  1217. bool ROCKALL::Truncate( int MaxFreeSpace )
  1218. {
  1219. TRY
  1220. {
  1221. //
  1222. // The call appears to be valid so if the
  1223. // heap is not corrupt then pass it along
  1224. // for processing.
  1225. //
  1226. if ( Available() )
  1227. { return (Heap -> Truncate( (SBIT32) MaxFreeSpace )); }
  1228. }
  1229. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  1230. #ifdef DEBUGGING
  1231. catch ( FAULT Message )
  1232. {
  1233. //
  1234. // It looks like the heap is corrupt. So
  1235. // lets just mark it as unusable, print a
  1236. // suitable message and exit.
  1237. //
  1238. GuardWord = AllocationFailure;
  1239. DebugPrint( "Exception caught: %s\n",(char*) Message );
  1240. }
  1241. #endif
  1242. catch ( ... )
  1243. {
  1244. //
  1245. // It looks like the heap is corrupt. So
  1246. // lets just mark it as unusable and exit.
  1247. //
  1248. GuardWord = AllocationFailure;
  1249. }
  1250. #else
  1251. __except ( EXCEPTION_EXECUTE_HANDLER )
  1252. {
  1253. //
  1254. // It looks like the heap is corrupt. So
  1255. // lets just mark it as unusable and exit.
  1256. //
  1257. GuardWord = AllocationFailure;
  1258. }
  1259. #endif
  1260. return false;
  1261. }
  1262. /********************************************************************/
  1263. /* */
  1264. /* Release all the heap locks. */
  1265. /* */
  1266. /* Lets start with some basic tests. If the address we have */
  1267. /* been given is special, clearly wrong or the heap has not */
  1268. /* been initialized then we fail and exit. */
  1269. /* */
  1270. /********************************************************************/
  1271. void ROCKALL::UnlockAll( VOID )
  1272. {
  1273. TRY
  1274. {
  1275. //
  1276. // The call appears to be valid so if the
  1277. // heap is not corrupt then pass it along
  1278. // for processing.
  1279. //
  1280. if ( Available() )
  1281. { Heap -> UnlockAll(); }
  1282. }
  1283. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  1284. #ifdef DEBUGGING
  1285. catch ( FAULT Message )
  1286. {
  1287. //
  1288. // It looks like the heap is corrupt. So
  1289. // lets just mark it as unusable, print a
  1290. // suitable message and exit.
  1291. //
  1292. GuardWord = AllocationFailure;
  1293. DebugPrint( "Exception caught: %s\n",(char*) Message );
  1294. }
  1295. #endif
  1296. catch ( ... )
  1297. {
  1298. //
  1299. // It looks like the heap is corrupt. So
  1300. // lets just mark it as unusable and exit.
  1301. //
  1302. GuardWord = AllocationFailure;
  1303. }
  1304. #else
  1305. __except ( EXCEPTION_EXECUTE_HANDLER )
  1306. {
  1307. //
  1308. // It looks like the heap is corrupt. So
  1309. // lets just mark it as unusable and exit.
  1310. //
  1311. GuardWord = AllocationFailure;
  1312. }
  1313. #endif
  1314. }
  1315. /********************************************************************/
  1316. /* */
  1317. /* Verify a memory allocation details. */
  1318. /* */
  1319. /* Lets start with some basic tests. If the address we have */
  1320. /* been given is special, clearly wrong or the heap has not */
  1321. /* been initialized then we fail the call appropriately. */
  1322. /* */
  1323. /********************************************************************/
  1324. bool ROCKALL::Verify( void *Address,int *Space )
  1325. {
  1326. TRY
  1327. {
  1328. //
  1329. // The call appears to be valid so if the
  1330. // heap is not corrupt then pass it along
  1331. // for processing.
  1332. //
  1333. if ( Available() )
  1334. {
  1335. return
  1336. (
  1337. (Address == ((void*) AllocationFailure))
  1338. ||
  1339. (Heap -> Verify( ((VOID*) Address),((SBIT32*) Space) ))
  1340. );
  1341. }
  1342. }
  1343. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  1344. #ifdef DEBUGGING
  1345. catch ( FAULT Message )
  1346. {
  1347. //
  1348. // It looks like the heap is corrupt. So
  1349. // lets just mark it as unusable, print a
  1350. // suitable message and exit.
  1351. //
  1352. GuardWord = AllocationFailure;
  1353. DebugPrint( "Exception caught: %s\n",(char*) Message );
  1354. }
  1355. #endif
  1356. catch ( ... )
  1357. {
  1358. //
  1359. // It looks like the heap is corrupt. So
  1360. // lets just mark it as unusable and exit.
  1361. //
  1362. GuardWord = AllocationFailure;
  1363. }
  1364. #else
  1365. __except ( EXCEPTION_EXECUTE_HANDLER )
  1366. {
  1367. //
  1368. // It looks like the heap is corrupt. So
  1369. // lets just mark it as unusable and exit.
  1370. //
  1371. GuardWord = AllocationFailure;
  1372. }
  1373. #endif
  1374. return false;
  1375. }
  1376. /********************************************************************/
  1377. /* */
  1378. /* Walk the heap. */
  1379. /* */
  1380. /* We have been asked to walk the heap. It is hard to know */
  1381. /* why anybody might want to do this given the rest of the */
  1382. /* functionality available. Nonetheless, we just do what is */
  1383. /* required to keep everyone happy. */
  1384. /* */
  1385. /********************************************************************/
  1386. bool ROCKALL::Walk( bool *Active,void **Address,int *Space )
  1387. {
  1388. TRY
  1389. {
  1390. //
  1391. // The call appears to be valid so if the
  1392. // heap is not corrupt then pass it along
  1393. // for processing.
  1394. //
  1395. if ( Available() )
  1396. {
  1397. AUTO BOOLEAN NewActive;
  1398. //
  1399. // Walk the active heap.
  1400. //
  1401. if
  1402. (
  1403. Heap -> Walk
  1404. (
  1405. ((BOOLEAN*) & NewActive),
  1406. ((VOID**) Address),
  1407. ((SBIT32*) Space)
  1408. )
  1409. )
  1410. {
  1411. (*Active) = (NewActive != False);
  1412. return true;
  1413. }
  1414. }
  1415. }
  1416. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  1417. #ifdef DEBUGGING
  1418. catch ( FAULT Message )
  1419. {
  1420. //
  1421. // It looks like the heap is corrupt. So
  1422. // lets just mark it as unusable, print a
  1423. // suitable message and exit.
  1424. //
  1425. GuardWord = AllocationFailure;
  1426. DebugPrint( "Exception caught: %s\n",(char*) Message );
  1427. }
  1428. #endif
  1429. catch ( ... )
  1430. {
  1431. //
  1432. // It looks like the heap is corrupt. So
  1433. // lets just mark it as unusable and exit.
  1434. //
  1435. GuardWord = AllocationFailure;
  1436. }
  1437. #else
  1438. __except ( EXCEPTION_EXECUTE_HANDLER )
  1439. {
  1440. //
  1441. // It looks like the heap is corrupt. So
  1442. // lets just mark it as unusable and exit.
  1443. //
  1444. GuardWord = AllocationFailure;
  1445. }
  1446. #endif
  1447. return false;
  1448. }
  1449. /********************************************************************/
  1450. /* */
  1451. /* Class destructor. */
  1452. /* */
  1453. /* Destory the current heap. */
  1454. /* */
  1455. /********************************************************************/
  1456. ROCKALL::~ROCKALL( void )
  1457. {
  1458. TRY
  1459. {
  1460. //
  1461. // We are about to destroy a heap but before we
  1462. // start we make sure that the heap is not corrupt
  1463. // and seems to be in reasonable shape. If not we
  1464. // leave it alone to avoid possible trouble.
  1465. //
  1466. if ( (Available()) && (NumberOfCaches > 0) && (TotalSize > 0) )
  1467. {
  1468. REGISTER SBIT32 Count;
  1469. //
  1470. // Execute the heap destructor.
  1471. //
  1472. PLACEMENT_DELETE( Heap,HEAP );
  1473. //
  1474. // Execute the new page destructor.
  1475. //
  1476. PLACEMENT_DELETE( NewPage,NEW_PAGE );
  1477. //
  1478. // Execute the find hash table destructor.
  1479. //
  1480. if ( GlobalDelete )
  1481. {
  1482. //
  1483. // We only delete the global find hash
  1484. // table if the reference count is zero.
  1485. //
  1486. Spinlock.ClaimLock();
  1487. if ( (-- ReferenceCount) == 0 )
  1488. { PLACEMENT_DELETE( Find,FIND ); }
  1489. Spinlock.ReleaseLock();
  1490. }
  1491. else
  1492. { PLACEMENT_DELETE( Find,FIND ); }
  1493. //
  1494. // Execute the cache destructors.
  1495. //
  1496. for ( Count=0;Count < NumberOfCaches;Count ++ )
  1497. { PLACEMENT_DELETE( & Caches[ Count ],CACHE ); }
  1498. //
  1499. // Deallocate the heap structures.
  1500. //
  1501. DeleteArea( ((VOID*) Caches),TotalSize,False );
  1502. //
  1503. // Finally, zero any remaining members.
  1504. // We really do not need to do this but
  1505. // just want to be sure that any following
  1506. // calls will clearly fail.
  1507. //
  1508. TotalSize = 0;
  1509. NumberOfCaches = 0;
  1510. GuardWord = 0;
  1511. GlobalDelete = False;
  1512. NewPage = NULL;
  1513. Heap = NULL;
  1514. Find = NULL;
  1515. Caches = NULL;
  1516. Array = NULL;
  1517. }
  1518. }
  1519. #ifdef DISABLE_STRUCTURED_EXCEPTIONS
  1520. #ifdef DEBUGGING
  1521. catch ( FAULT Message )
  1522. {
  1523. //
  1524. // It looks like the heap is corrupt. So
  1525. // lets just mark it as unusable, print a
  1526. // suitable message and exit.
  1527. //
  1528. GuardWord = AllocationFailure;
  1529. DebugPrint( "Exception caught: %s\n",(char*) Message );
  1530. }
  1531. #endif
  1532. catch ( ... )
  1533. {
  1534. //
  1535. // It looks like the heap is corrupt. So
  1536. // lets just mark it as unusable and exit.
  1537. //
  1538. GuardWord = AllocationFailure;
  1539. }
  1540. #else
  1541. __except ( EXCEPTION_EXECUTE_HANDLER )
  1542. {
  1543. //
  1544. // It looks like the heap is corrupt. So
  1545. // lets just mark it as unusable and exit.
  1546. //
  1547. GuardWord = AllocationFailure;
  1548. }
  1549. #endif
  1550. }