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.

920 lines
28 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 "DynamicDebugHeap.hpp"
  26. #include "List.hpp"
  27. #include "New.hpp"
  28. #include "Sharelock.hpp"
  29. /********************************************************************/
  30. /* */
  31. /* Structures local to the class. */
  32. /* */
  33. /* The structures supplied here describe the layout of the */
  34. /* private per thread heap structures. */
  35. /* */
  36. /********************************************************************/
  37. typedef struct DYNAMIC_HEAP : public LIST
  38. {
  39. ROCKALL_FRONT_END *Heap;
  40. }
  41. DYNAMIC_HEAP;
  42. /********************************************************************/
  43. /* */
  44. /* Static data structures. */
  45. /* */
  46. /* The static data structures are initialized and prepared for */
  47. /* use here. */
  48. /* */
  49. /********************************************************************/
  50. STATIC SHARELOCK Sharelock;
  51. /********************************************************************/
  52. /* */
  53. /* Class constructor. */
  54. /* */
  55. /* The overall structure and layout of the heap is controlled */
  56. /* by the various constants and calls made in this function. */
  57. /* There is a significant amount of flexibility available to */
  58. /* a heap which can lead to them having dramatically different */
  59. /* properties. */
  60. /* */
  61. /********************************************************************/
  62. DYNAMIC_DEBUG_HEAP::DYNAMIC_DEBUG_HEAP
  63. (
  64. int MaxFreeSpace,
  65. bool Recycle,
  66. bool SingleImage,
  67. bool ThreadSafe,
  68. //
  69. // Additional debug flags.
  70. //
  71. bool FunctionTrace,
  72. int PercentToDebug,
  73. int PercentToPage,
  74. bool TrapOnUserError
  75. ) :
  76. //
  77. // Call the constructors for the contained classes.
  78. //
  79. DebugHeap( 0,false,false,ThreadSafe,FunctionTrace,TrapOnUserError ),
  80. FastHeap( MaxFreeSpace,Recycle,false,ThreadSafe ),
  81. PageHeap( 0,false,false,ThreadSafe,FunctionTrace,TrapOnUserError )
  82. {
  83. //
  84. // Setup various control variables.
  85. //
  86. Active = false;
  87. //
  88. // Create the linked list header and zero
  89. // any other variables.
  90. //
  91. AllHeaps = ((LIST*) SMALL_HEAP::New( sizeof(LIST) ));
  92. Array = ((DYNAMIC_HEAP*) SMALL_HEAP::New( (sizeof(DYNAMIC_HEAP) * 3) ));
  93. HeapWalk = NULL;
  94. PercentDebug = PercentToDebug;
  95. PercentPage = PercentToPage;
  96. //
  97. // We can only activate the the heap if we manage
  98. // to allocate the space we requested.
  99. //
  100. if ( (AllHeaps != NULL) && (Array != NULL))
  101. {
  102. //
  103. // Execute the constructors for each linked list
  104. // and for the thread local store.
  105. //
  106. PLACEMENT_NEW( AllHeaps,LIST );
  107. //
  108. // Setup each linked list element.
  109. //
  110. PLACEMENT_NEW( & Array[0],DYNAMIC_HEAP );
  111. PLACEMENT_NEW( & Array[1],DYNAMIC_HEAP );
  112. PLACEMENT_NEW( & Array[2],DYNAMIC_HEAP );
  113. //
  114. // Setup the heap for each linked list
  115. // element and store the pointer.
  116. //
  117. Array[0].Heap = & DebugHeap;
  118. Array[1].Heap = & FastHeap;
  119. Array[2].Heap = & PageHeap;
  120. //
  121. // Insert each linked list element into
  122. // the list of heaps.
  123. //
  124. Array[0].Insert( AllHeaps );
  125. Array[1].Insert( AllHeaps );
  126. Array[2].Insert( AllHeaps );
  127. //
  128. // Activate the heap.
  129. //
  130. Active = true;
  131. }
  132. }
  133. /********************************************************************/
  134. /* */
  135. /* Memory deallocation. */
  136. /* */
  137. /* When we delete an allocation we try to each heap in turn */
  138. /* until we find the correct one to use. */
  139. /* */
  140. /********************************************************************/
  141. bool DYNAMIC_DEBUG_HEAP::Delete( void *Address,int Size )
  142. {
  143. //
  144. // Although it is very rare there is a chance
  145. // that we failed to build the basic heap structures.
  146. //
  147. if ( Active )
  148. {
  149. //
  150. // We try the fastest heap as we are betting
  151. // it is the most common.
  152. //
  153. if ( FastHeap.KnownArea( Address ) )
  154. { return (FastHeap.Delete( Address,Size )); }
  155. else
  156. {
  157. //
  158. // Next we try the debug heap.
  159. //
  160. if ( DebugHeap.KnownArea( Address ) )
  161. { return (DebugHeap.Delete( Address,Size )); }
  162. else
  163. {
  164. //
  165. // Finally we try the page heap.
  166. //
  167. if ( PageHeap.KnownArea( Address ) )
  168. { return (PageHeap.Delete( Address,Size )); }
  169. }
  170. }
  171. }
  172. return false;
  173. }
  174. /********************************************************************/
  175. /* */
  176. /* Delete all allocations. */
  177. /* */
  178. /* We walk the list of all the heaps and instruct each heap */
  179. /* to delete everything. */
  180. /* */
  181. /********************************************************************/
  182. void DYNAMIC_DEBUG_HEAP::DeleteAll( bool Recycle )
  183. {
  184. //
  185. // Although it is very rare there is a chance
  186. // that we failed to build the basic heap structures.
  187. //
  188. if ( Active )
  189. {
  190. REGISTER DYNAMIC_HEAP *Current;
  191. //
  192. // Claim a process wide shared lock
  193. // to ensure the list of heaps does
  194. // not change until we have finished.
  195. //
  196. Sharelock.ClaimShareLock();
  197. //
  198. // You just have to hope the user knows
  199. // what they are doing as everything gets
  200. // blown away.
  201. //
  202. for
  203. (
  204. Current = ((DYNAMIC_HEAP*) AllHeaps -> First());
  205. (Current != NULL);
  206. Current = ((DYNAMIC_HEAP*) Current -> Next())
  207. )
  208. { Current -> Heap -> DeleteAll( Recycle ); }
  209. //
  210. // Release the lock.
  211. //
  212. Sharelock.ReleaseShareLock();
  213. }
  214. }
  215. /********************************************************************/
  216. /* */
  217. /* Memory allocation details. */
  218. /* */
  219. /* When we are asked for details we try to each heap in turn */
  220. /* until we find the correct one to use. */
  221. /* */
  222. /********************************************************************/
  223. bool DYNAMIC_DEBUG_HEAP::Details( void *Address,int *Space )
  224. { return Verify( Address,Space ); }
  225. /********************************************************************/
  226. /* */
  227. /* Print a list of heap leaks. */
  228. /* */
  229. /* We walk the heap and output a list of active heap */
  230. /* allocations to the debug window, */
  231. /* */
  232. /********************************************************************/
  233. void DYNAMIC_DEBUG_HEAP::HeapLeaks( void )
  234. {
  235. //
  236. // We call heap leaks for each heap
  237. // that supports the interface.
  238. //
  239. DebugHeap.HeapLeaks();
  240. PageHeap.HeapLeaks();
  241. }
  242. /********************************************************************/
  243. /* */
  244. /* A known area. */
  245. /* */
  246. /* When we are asked about an address we try to each heap in */
  247. /* turn until we find the correct one to use. */
  248. /* */
  249. /********************************************************************/
  250. bool DYNAMIC_DEBUG_HEAP::KnownArea( void *Address )
  251. {
  252. //
  253. // Although it is very rare there is a chance
  254. // that we failed to build the basic heap structures.
  255. //
  256. if ( Active )
  257. {
  258. //
  259. // We try the fastest heap as we are betting
  260. // it is the most common, followed by the
  261. // degug and the page heaps.
  262. //
  263. return
  264. (
  265. FastHeap.KnownArea( Address )
  266. ||
  267. DebugHeap.KnownArea( Address )
  268. ||
  269. PageHeap.KnownArea( Address )
  270. );
  271. }
  272. else
  273. { return false; }
  274. }
  275. /********************************************************************/
  276. /* */
  277. /* Claim all the heap locks. */
  278. /* */
  279. /* We claim all of the heap locks so that it is safe to do */
  280. /* operations like walking all of the heaps. */
  281. /* */
  282. /********************************************************************/
  283. void DYNAMIC_DEBUG_HEAP::LockAll( VOID )
  284. {
  285. //
  286. // Although it is very rare there is a chance
  287. // that we failed to build the basic heap structures.
  288. //
  289. if ( Active )
  290. {
  291. REGISTER DYNAMIC_HEAP *Current;
  292. //
  293. // Claim a process wide shared lock
  294. // to ensure the list of heaps does
  295. // not change until we have finished.
  296. //
  297. Sharelock.ClaimShareLock();
  298. //
  299. // You just have to hope the user knows
  300. // what they are doing as we claim all
  301. // of the heap locks.
  302. //
  303. for
  304. (
  305. Current = ((DYNAMIC_HEAP*) AllHeaps -> First());
  306. (Current != NULL);
  307. Current = ((DYNAMIC_HEAP*) Current -> Next())
  308. )
  309. { Current -> Heap -> LockAll(); }
  310. //
  311. // Release the lock.
  312. //
  313. Sharelock.ReleaseShareLock();
  314. }
  315. }
  316. /********************************************************************/
  317. /* */
  318. /* Multiple memory deallocations. */
  319. /* */
  320. /* When we delete multiple allocations we simply delete each */
  321. /* allocation one at a time. */
  322. /* */
  323. /********************************************************************/
  324. bool DYNAMIC_DEBUG_HEAP::MultipleDelete
  325. (
  326. int Actual,
  327. void *Array[],
  328. int Size
  329. )
  330. {
  331. REGISTER bool Result = true;
  332. REGISTER SBIT32 Count;
  333. //
  334. // We would realy like to use the multiple
  335. // delete functionality of Rockall here but
  336. // it is too much effort. So we simply call
  337. // the standard delete on each entry in the
  338. // array. Although this is not as fast it
  339. // does give more transparent results.
  340. //
  341. for ( Count=0;Count < Actual;Count ++ )
  342. {
  343. //
  344. // Delete each memory allocation after
  345. // carefully checking it.
  346. //
  347. if ( ! Delete( Array[ Count ],Size ) )
  348. { Result = false; }
  349. }
  350. return Result;
  351. }
  352. /********************************************************************/
  353. /* */
  354. /* Multiple memory allocations. */
  355. /* */
  356. /* When we do multiple allocations we simply allocate each */
  357. /* piece of memory one at a time. */
  358. /* */
  359. /********************************************************************/
  360. bool DYNAMIC_DEBUG_HEAP::MultipleNew
  361. (
  362. int *Actual,
  363. void *Array[],
  364. int Requested,
  365. int Size,
  366. int *Space,
  367. bool Zero
  368. )
  369. {
  370. //
  371. // Although it is very rare there is a chance
  372. // that we failed to build the basic heap structures.
  373. //
  374. if ( Active )
  375. {
  376. REGISTER int Random = (RandomNumber() % 100);
  377. //
  378. // We do all the page heap allocations
  379. // in accordance with the supplied ratios.
  380. //
  381. if ( Random <= PercentPage )
  382. {
  383. return
  384. (
  385. PageHeap.MultipleNew
  386. (
  387. Actual,
  388. Array,
  389. Requested,
  390. Size,
  391. Space,
  392. Zero
  393. )
  394. );
  395. }
  396. else
  397. {
  398. //
  399. // Next we do all the debug allocations
  400. // in accordance with the supplied ratios.
  401. //
  402. if ( Random <= (PercentPage + PercentDebug) )
  403. {
  404. return
  405. (
  406. DebugHeap.MultipleNew
  407. (
  408. Actual,
  409. Array,
  410. Requested,
  411. Size,
  412. Space,
  413. Zero
  414. )
  415. );
  416. }
  417. else
  418. {
  419. return
  420. (
  421. FastHeap.MultipleNew
  422. (
  423. Actual,
  424. Array,
  425. Requested,
  426. Size,
  427. Space,
  428. Zero
  429. )
  430. );
  431. }
  432. }
  433. }
  434. else
  435. {
  436. (*Actual) = 0;
  437. return false;
  438. }
  439. }
  440. /********************************************************************/
  441. /* */
  442. /* Memory allocation. */
  443. /* */
  444. /* We allocate from each heap in proportion to the ratios */
  445. /* supplied by the user. */
  446. /* */
  447. /********************************************************************/
  448. void *DYNAMIC_DEBUG_HEAP::New( int Size,int *Space,bool Zero )
  449. {
  450. //
  451. // Although it is very rare there is a chance
  452. // that we failed to build the basic heap structures.
  453. //
  454. if ( Active )
  455. {
  456. REGISTER int Random = (RandomNumber() % 100);
  457. //
  458. // We do all the page heap allocations
  459. // in accordance with the supplied ratios.
  460. //
  461. if ( Random <= PercentPage )
  462. { return PageHeap.New( Size,Space,Zero ); }
  463. else
  464. {
  465. //
  466. // Next we do all the debug allocations
  467. // in accordance with the supplied ratios.
  468. //
  469. if ( Random <= (PercentPage + PercentDebug) )
  470. { return DebugHeap.New( Size,Space,Zero ); }
  471. else
  472. { return FastHeap.New( Size,Space,Zero ); }
  473. }
  474. }
  475. else
  476. { return NULL; }
  477. }
  478. /********************************************************************/
  479. /* */
  480. /* Compute a random number. */
  481. /* */
  482. /* Compute a random number and return it. */
  483. /* */
  484. /********************************************************************/
  485. int DYNAMIC_DEBUG_HEAP::RandomNumber( VOID )
  486. {
  487. STATIC int RandomSeed = 1;
  488. //
  489. // Compute a new random seed value.
  490. //
  491. RandomSeed =
  492. (
  493. ((RandomSeed >> 32) * 2964557531)
  494. +
  495. ((RandomSeed & 0xffff) * 2964557531)
  496. +
  497. 1
  498. );
  499. //
  500. // The new random seed is returned.
  501. //
  502. return (RandomSeed >> 1);
  503. }
  504. /********************************************************************/
  505. /* */
  506. /* Memory reallocation. */
  507. /* */
  508. /* We reallocate space for an allocation on the original heap */
  509. /* to make sure this case is well tested. */
  510. /* */
  511. /********************************************************************/
  512. void *DYNAMIC_DEBUG_HEAP::Resize
  513. (
  514. void *Address,
  515. int NewSize,
  516. int Move,
  517. int *Space,
  518. bool NoDelete,
  519. bool Zero
  520. )
  521. {
  522. //
  523. // Although it is very rare there is a chance
  524. // that we failed to build the basic heap structures.
  525. //
  526. if ( Active )
  527. {
  528. //
  529. // We try the fastest heap as we are betting
  530. // it is the most common.
  531. //
  532. if ( FastHeap.KnownArea( Address ) )
  533. {
  534. //
  535. // Reallocate the memory as requested.
  536. //
  537. return
  538. (
  539. FastHeap.Resize
  540. (
  541. Address,
  542. NewSize,
  543. Move,
  544. Space,
  545. NoDelete,
  546. Zero
  547. )
  548. );
  549. }
  550. else
  551. {
  552. //
  553. // Next we try the debug heap.
  554. //
  555. if ( DebugHeap.KnownArea( Address ) )
  556. {
  557. //
  558. // Reallocate the memory as requested.
  559. //
  560. return
  561. (
  562. DebugHeap.Resize
  563. (
  564. Address,
  565. NewSize,
  566. Move,
  567. Space,
  568. NoDelete,
  569. Zero
  570. )
  571. );
  572. }
  573. else
  574. {
  575. //
  576. // Finally we try the page heap.
  577. //
  578. if ( PageHeap.KnownArea( Address ) )
  579. {
  580. //
  581. // Reallocate the memory as requested.
  582. //
  583. return
  584. (
  585. PageHeap.Resize
  586. (
  587. Address,
  588. NewSize,
  589. Move,
  590. Space,
  591. NoDelete,
  592. Zero
  593. )
  594. );
  595. }
  596. }
  597. }
  598. }
  599. return NULL;
  600. }
  601. /********************************************************************/
  602. /* */
  603. /* Special memory allocation. */
  604. /* */
  605. /* We sometimes need to allocate some memory from the internal */
  606. /* memory allocator which lives for the lifetime of the heap. */
  607. /* */
  608. /********************************************************************/
  609. void *DYNAMIC_DEBUG_HEAP::SpecialNew( int Size )
  610. { return FastHeap.New( Size ); }
  611. /********************************************************************/
  612. /* */
  613. /* Truncate the heap. */
  614. /* */
  615. /* We need to truncate the heap. This is pretty much a null */
  616. /* call as we do this as we go along anyway. The only thing we */
  617. /* can do is free any space the user suggested keeping earlier. */
  618. /* */
  619. /********************************************************************/
  620. bool DYNAMIC_DEBUG_HEAP::Truncate( int MaxFreeSpace )
  621. {
  622. REGISTER bool Result = true;
  623. //
  624. // Although it is very rare there is a chance
  625. // that we failed to build the basic heap structures.
  626. //
  627. if ( Active )
  628. {
  629. REGISTER DYNAMIC_HEAP *Current;
  630. //
  631. // Claim a process wide shared lock
  632. // to ensure the list of heaps does
  633. // not change until we have finished.
  634. //
  635. Sharelock.ClaimShareLock();
  636. //
  637. // You just have to hope the user knows
  638. // what they are doing as we are truncating
  639. // all of the heaps.
  640. //
  641. for
  642. (
  643. Current = ((DYNAMIC_HEAP*) AllHeaps -> First());
  644. (Current != NULL);
  645. Current = ((DYNAMIC_HEAP*) Current -> Next())
  646. )
  647. {
  648. //
  649. // If faulty delete is noted during the
  650. // cache flushes then exit with the
  651. // correct status.
  652. //
  653. if ( ! Current -> Heap -> Truncate( MaxFreeSpace ) )
  654. { Result = false; }
  655. }
  656. //
  657. // Release the lock.
  658. //
  659. Sharelock.ReleaseShareLock();
  660. }
  661. return Result;
  662. }
  663. /********************************************************************/
  664. /* */
  665. /* Release all the heap locks. */
  666. /* */
  667. /* We unlock all of the heap locks so normal processing can */
  668. /* continue on the heaps. */
  669. /* */
  670. /********************************************************************/
  671. void DYNAMIC_DEBUG_HEAP::UnlockAll( VOID )
  672. {
  673. //
  674. // Although it is very rare there is a chance
  675. // that we failed to build the basic heap structures.
  676. //
  677. if ( Active )
  678. {
  679. REGISTER DYNAMIC_HEAP *Current;
  680. //
  681. // Claim a process wide shared lock
  682. // to ensure the list of heaps does
  683. // not change until we have finished.
  684. //
  685. Sharelock.ClaimShareLock();
  686. //
  687. // You just have to hope the user knows
  688. // what they are doing as we claim all
  689. // of the heap locks.
  690. //
  691. for
  692. (
  693. Current = ((DYNAMIC_HEAP*) AllHeaps -> First());
  694. (Current != NULL);
  695. Current = ((DYNAMIC_HEAP*) Current -> Next())
  696. )
  697. { Current -> Heap -> UnlockAll(); }
  698. //
  699. // Release the lock.
  700. //
  701. Sharelock.ReleaseShareLock();
  702. }
  703. }
  704. /********************************************************************/
  705. /* */
  706. /* Verify a memory allocation details. */
  707. /* */
  708. /* When we verify an allocation we try to each heap in turn */
  709. /* until we find the correct one to use. */
  710. /* */
  711. /********************************************************************/
  712. bool DYNAMIC_DEBUG_HEAP::Verify( void *Address,int *Space )
  713. {
  714. //
  715. // Although it is very rare there is a chance
  716. // that we failed to build the basic heap structures.
  717. //
  718. if ( Active )
  719. {
  720. //
  721. // We try the fastest heap as we are betting
  722. // it is the most common.
  723. //
  724. if ( FastHeap.KnownArea( Address ) )
  725. { return (FastHeap.Verify( Address,Space )); }
  726. else
  727. {
  728. //
  729. // Next we try the debug heap.
  730. //
  731. if ( DebugHeap.KnownArea( Address ) )
  732. { return (DebugHeap.Verify( Address,Space )); }
  733. else
  734. {
  735. //
  736. // Finally we try the page heap.
  737. //
  738. if ( PageHeap.KnownArea( Address ) )
  739. { return (PageHeap.Verify( Address,Space )); }
  740. }
  741. }
  742. }
  743. return false;
  744. }
  745. /********************************************************************/
  746. /* */
  747. /* Walk the heap. */
  748. /* */
  749. /* We have been asked to walk the heap. It is hard to know */
  750. /* why anybody might want to do this given the rest of the */
  751. /* functionality available. Nonetheless, we just do what is */
  752. /* required to keep everyone happy. */
  753. /* */
  754. /********************************************************************/
  755. bool DYNAMIC_DEBUG_HEAP::Walk( bool *Activity,void **Address,int *Space )
  756. {
  757. //
  758. // Claim a process wide shared lock
  759. // to ensure the list of heaps does
  760. // not change until we have finished.
  761. //
  762. Sharelock.ClaimShareLock();
  763. //
  764. // Nasty, in 'DYNAMIC_DEBUG_HEAP' we have multiple heaps
  765. // to walk so if we don't have a current heap
  766. // then just select the first available.
  767. //
  768. if ( ((*Address) == NULL) || (HeapWalk == NULL) )
  769. { HeapWalk = ((DYNAMIC_HEAP*) AllHeaps -> First()); }
  770. //
  771. // Walk the heap. When we come to the end of
  772. // the current heap then move on to the next
  773. // heap.
  774. //
  775. while
  776. (
  777. (HeapWalk != NULL)
  778. &&
  779. (! HeapWalk -> Heap -> Walk( Activity,Address,Space ))
  780. )
  781. { HeapWalk = ((DYNAMIC_HEAP*) HeapWalk -> Next()); }
  782. //
  783. // Release the lock.
  784. //
  785. Sharelock.ReleaseShareLock();
  786. return (HeapWalk != NULL);
  787. }
  788. /********************************************************************/
  789. /* */
  790. /* Class destructor. */
  791. /* */
  792. /* Destory the heap. */
  793. /* */
  794. /********************************************************************/
  795. DYNAMIC_DEBUG_HEAP::~DYNAMIC_DEBUG_HEAP( void )
  796. {
  797. //
  798. // Although it is very rare there is a chance
  799. // that we failed to build the basic heap structures.
  800. //
  801. if ( Active )
  802. {
  803. //
  804. // Deactivate the heap.
  805. //
  806. Active = false;
  807. //
  808. // Delete each linked list element into
  809. // the list of heaps.
  810. //
  811. Array[2].Delete( AllHeaps );
  812. Array[1].Delete( AllHeaps );
  813. Array[0].Delete( AllHeaps );
  814. //
  815. // Delete each linked list element.
  816. //
  817. PLACEMENT_DELETE( & Array[2],DYNAMIC_HEAP );
  818. PLACEMENT_DELETE( & Array[1],DYNAMIC_HEAP );
  819. PLACEMENT_DELETE( & Array[0],DYNAMIC_HEAP );
  820. //
  821. // Call the list and TLS destructors.
  822. //
  823. PLACEMENT_DELETE( AllHeaps,LIST );
  824. //
  825. // Delete the space.
  826. //
  827. SMALL_HEAP::Delete( Array );
  828. SMALL_HEAP::Delete( AllHeaps );
  829. //
  830. // Zero the pointers just to be tidy.
  831. //
  832. HeapWalk = NULL;
  833. Array = NULL;
  834. AllHeaps = NULL;
  835. }
  836. }