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.

1328 lines
41 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 "Common.hpp"
  26. #include "List.hpp"
  27. #include "New.hpp"
  28. #include "Prefetch.hpp"
  29. #include "Sharelock.hpp"
  30. #include "SmpHeap.hpp"
  31. #include "Tls.hpp"
  32. /********************************************************************/
  33. /* */
  34. /* Constants local to the class. */
  35. /* */
  36. /* The constants supplied here try to make the layout of the */
  37. /* the caches easier to understand and update. */
  38. /* */
  39. /********************************************************************/
  40. CONST SBIT32 FindCacheSize = 8192;
  41. CONST SBIT32 FindCacheThreshold = 0;
  42. CONST SBIT32 FindSize = 4096;
  43. CONST SBIT32 MinThreadStack = 4;
  44. CONST SBIT32 Stride1 = 4;
  45. CONST SBIT32 Stride2 = 1024;
  46. /********************************************************************/
  47. /* */
  48. /* Structures local to the class. */
  49. /* */
  50. /* The structures supplied here describe the layout of the */
  51. /* per thread caches. */
  52. /* */
  53. /********************************************************************/
  54. typedef struct CACHE_STACK
  55. {
  56. BOOLEAN Active;
  57. SBIT32 MaxSize;
  58. SBIT32 FillSize;
  59. SBIT32 Space;
  60. SBIT32 Top;
  61. VOID **Stack;
  62. }
  63. CACHE_STACK;
  64. typedef struct THREAD_CACHE : public LIST
  65. {
  66. BOOLEAN Flush;
  67. CACHE_STACK *Caches;
  68. CACHE_STACK **SizeToCache1;
  69. CACHE_STACK **SizeToCache2;
  70. }
  71. THREAD_CACHE;
  72. /********************************************************************/
  73. /* */
  74. /* The description of the heap. */
  75. /* */
  76. /* A heap is a collection of fixed sized allocation caches. */
  77. /* An allocation cache consists of an allocation size, the */
  78. /* number of pre-built allocations to cache, a chunk size and */
  79. /* a parent page size which is sub-divided to create elements */
  80. /* for this cache. A heap consists of two arrays of caches. */
  81. /* Each of these arrays has a stride (i.e. 'Stride1' and */
  82. /* 'Stride2') which is typically the smallest common factor of */
  83. /* all the allocation sizes in the array. */
  84. /* */
  85. /********************************************************************/
  86. STATIC ROCKALL::CACHE_DETAILS Caches1[] =
  87. {
  88. //
  89. // Bucket Size Of Bucket Parent
  90. // Size Cache Chunks Page Size
  91. //
  92. { 4, 256, 32, 4096 },
  93. { 8, 128, 32, 4096 },
  94. { 12, 128, 64, 4096 },
  95. { 16, 128, 64, 4096 },
  96. { 20, 64, 64, 4096 },
  97. { 24, 64, 96, 4096 },
  98. { 32, 64, 128, 4096 },
  99. { 40, 64, 128, 4096 },
  100. { 48, 64, 256, 4096 },
  101. { 64, 64, 256, 4096 },
  102. { 80, 64, 512, 4096 },
  103. { 96, 64, 512, 4096 },
  104. { 128, 32, 4096, 4096 },
  105. { 160, 32, 4096, 4096 },
  106. { 192, 32, 4096, 4096 },
  107. { 224, 32, 4096, 4096 },
  108. { 256, 32, 4096, 4096 },
  109. { 320, 16, 4096, 4096 },
  110. { 384, 16, 4096, 4096 },
  111. { 448, 16, 4096, 4096 },
  112. { 512, 16, 4096, 4096 },
  113. { 576, 8, 4096, 4096 },
  114. { 640, 8, 8192, 8192 },
  115. { 704, 8, 4096, 4096 },
  116. { 768, 8, 4096, 4096 },
  117. { 832, 8, 8192, 8192 },
  118. { 896, 8, 8192, 8192 },
  119. { 960, 8, 4096, 4096 },
  120. { 0,0,0,0 }
  121. };
  122. STATIC ROCKALL::CACHE_DETAILS Caches2[] =
  123. {
  124. //
  125. // Bucket Size Of Bucket Parent
  126. // Size Cache Chunks Page Size
  127. //
  128. { 1024, 16, 4096, 4096 },
  129. { 2048, 16, 4096, 4096 },
  130. { 3072, 4, 65536, 65536 },
  131. { 4096, 8, 65536, 65536 },
  132. { 5120, 4, 65536, 65536 },
  133. { 6144, 4, 65536, 65536 },
  134. { 7168, 4, 65536, 65536 },
  135. { 8192, 8, 65536, 65536 },
  136. { 9216, 0, 65536, 65536 },
  137. { 10240, 0, 65536, 65536 },
  138. { 12288, 0, 65536, 65536 },
  139. { 16384, 2, 65536, 65536 },
  140. { 21504, 0, 65536, 65536 },
  141. { 32768, 0, 65536, 65536 },
  142. { 65536, 0, 65536, 65536 },
  143. { 65536, 0, 65536, 65536 },
  144. { 0,0,0,0 }
  145. };
  146. /********************************************************************/
  147. /* */
  148. /* The description bit vectors. */
  149. /* */
  150. /* All heaps keep track of allocations using bit vectors. An */
  151. /* allocation requires 2 bits to keep track of its state. The */
  152. /* following array supplies the size of the available bit */
  153. /* vectors measured in 32 bit words. */
  154. /* */
  155. /********************************************************************/
  156. STATIC int NewPageSizes[] = { 1,4,16,64,0 };
  157. /********************************************************************/
  158. /* */
  159. /* Static data structures. */
  160. /* */
  161. /* The static data structures are initialized and prepared for */
  162. /* use here. */
  163. /* */
  164. /********************************************************************/
  165. STATIC PREFETCH Prefetch;
  166. STATIC SHARELOCK Sharelock;
  167. /********************************************************************/
  168. /* */
  169. /* Class constructor. */
  170. /* */
  171. /* The overall structure and layout of the heap is controlled */
  172. /* by the various constants and calls made in this function. */
  173. /* There is a significant amount of flexibility available to */
  174. /* a heap which can lead to them having dramatically different */
  175. /* properties. */
  176. /* */
  177. /********************************************************************/
  178. SMP_HEAP::SMP_HEAP
  179. (
  180. int MaxFreeSpace,
  181. bool Recycle,
  182. bool SingleImage,
  183. bool ThreadSafe
  184. ) :
  185. //
  186. // Call the constructors for the contained classes.
  187. //
  188. ROCKALL
  189. (
  190. Caches1,
  191. Caches2,
  192. FindCacheSize,
  193. FindCacheThreshold,
  194. FindSize,
  195. MaxFreeSpace,
  196. NewPageSizes,
  197. False, // Recycle forced off.
  198. SingleImage,
  199. Stride1,
  200. Stride2,
  201. True // Locking forced on.
  202. )
  203. {
  204. //
  205. // Compute the number of cache descriptions
  206. // and the largest allocation size for each
  207. // cache description table.
  208. //
  209. MaxCaches1 = (ComputeSize( ((CHAR*) Caches1),sizeof(CACHE_DETAILS) ));
  210. MaxCaches2 = (ComputeSize( ((CHAR*) Caches2),sizeof(CACHE_DETAILS) ));
  211. MaxSize1 = Caches1[ (MaxCaches1-1) ].AllocationSize;
  212. MaxSize2 = Caches2[ (MaxCaches2-1) ].AllocationSize;
  213. //
  214. // Create the linked list headers and a thread
  215. // local store variable to point at each threads
  216. // private cache.
  217. //
  218. ActiveList = ((LIST*) SpecialNew( sizeof(LIST) ));
  219. FreeList = ((LIST*) SpecialNew( sizeof(LIST) ));
  220. Tls = ((THREAD_LOCAL_STORE*) SpecialNew( sizeof(THREAD_LOCAL_STORE) ));
  221. //
  222. // We may only activate the the heap if we manage
  223. // to allocate space we requested and the stride
  224. // size of the cache descriptions is a power of two.
  225. //
  226. if
  227. (
  228. (ActiveList != NULL)
  229. &&
  230. (COMMON::ConvertDivideToShift( Stride1,((SBIT32*) & ShiftSize1) ))
  231. &&
  232. (COMMON::ConvertDivideToShift( Stride2,((SBIT32*) & ShiftSize2) ))
  233. &&
  234. (FreeList != NULL)
  235. &&
  236. (Tls != NULL)
  237. )
  238. {
  239. //
  240. // Activate the heap.
  241. //
  242. Active = True;
  243. //
  244. // Execute the constructors for each linked list
  245. // and for the thread local store.
  246. //
  247. PLACEMENT_NEW( ActiveList,LIST );
  248. PLACEMENT_NEW( FreeList,LIST );
  249. PLACEMENT_NEW( Tls,THREAD_LOCAL_STORE );
  250. }
  251. else
  252. { Active = False; }
  253. }
  254. /********************************************************************/
  255. /* */
  256. /* Create new thread cache. */
  257. /* */
  258. /* Create a new thread cache to store all the cache stacks. */
  259. /* Each thread cache is private to a thread and is accessed */
  260. /* without taking locks. */
  261. /* */
  262. /********************************************************************/
  263. void SMP_HEAP::CreateThreadCache( void )
  264. {
  265. REGISTER THREAD_CACHE *ThreadCache = NULL;
  266. //
  267. // We need to have a look in the free list
  268. // in the vain hope we will find a prebuilt
  269. // thread cache ready for use.
  270. //
  271. Sharelock.ClaimExclusiveLock();
  272. if ( ! FreeList -> EndOfList() )
  273. {
  274. //
  275. // We have found a free one.
  276. //
  277. ThreadCache = ((THREAD_CACHE*) FreeList -> First());
  278. //
  279. // Unlink it from the free list and put
  280. // it back in the active list.
  281. //
  282. ThreadCache -> Delete( FreeList );
  283. ThreadCache -> Insert( ActiveList );
  284. }
  285. Sharelock.ReleaseExclusiveLock();
  286. //
  287. // If we could not find a free thread cache
  288. // then we have allocate the space and build
  289. // a new one. This requires quite a bit of
  290. // effort so we try to avoid this as far as
  291. // we are able.
  292. //
  293. if ( ThreadCache == NULL )
  294. {
  295. REGISTER SBIT32 MaxCaches = (MaxCaches1 + MaxCaches2);
  296. REGISTER SBIT32 MaxSizeToCache1 = (MaxSize1 / Stride1);
  297. REGISTER SBIT32 MaxSizeToCache2 = (MaxSize2 / Stride2);
  298. //
  299. // Create the space for a new thread
  300. // cache from the heaps special memory
  301. // area.
  302. //
  303. ThreadCache =
  304. (
  305. (THREAD_CACHE*) SpecialNew
  306. (
  307. sizeof(THREAD_CACHE)
  308. +
  309. (MaxCaches * sizeof(CACHE_STACK))
  310. +
  311. (MaxSizeToCache1 * sizeof(CACHE_STACK*))
  312. +
  313. (MaxSizeToCache2 * sizeof(CACHE_STACK*))
  314. )
  315. );
  316. //
  317. // Clearly, if we are unable to allocate the
  318. // required space we have big problems. All
  319. // we can do is exit and continue without a
  320. // cache.
  321. //
  322. if ( ThreadCache != NULL )
  323. {
  324. REGISTER SBIT32 Count1;
  325. REGISTER SBIT32 Count2;
  326. //
  327. // Setup the thread cache flags.
  328. //
  329. ThreadCache -> Flush = False;
  330. //
  331. // Setup the thread cache tables.
  332. //
  333. ThreadCache -> SizeToCache1 =
  334. ((CACHE_STACK**) & ThreadCache[1]);
  335. ThreadCache -> SizeToCache2 =
  336. ((CACHE_STACK**) & ThreadCache -> SizeToCache1[ MaxSizeToCache1 ]);
  337. ThreadCache -> Caches =
  338. ((CACHE_STACK*) & ThreadCache -> SizeToCache2[ MaxSizeToCache2 ]);
  339. //
  340. // Create a mapping from each allocation size
  341. // to the associated cache stack for the first
  342. // cache description table.
  343. //
  344. for ( Count1=0,Count2=0;Count1 < MaxSizeToCache1;Count1 ++ )
  345. {
  346. //
  347. // We make sure that the current cache size
  348. // is large enough to hold an element of the
  349. // given size. If not we move on to the next
  350. // cache.
  351. //
  352. if
  353. (
  354. ((Count1 + 1) * Stride1)
  355. >
  356. (Caches1[ Count2 ].AllocationSize)
  357. )
  358. { Count2 ++; }
  359. //
  360. // Store a pointer so that a request for
  361. // this size of allocation goes directly
  362. // to the correct cache.
  363. //
  364. ThreadCache -> SizeToCache1[ Count1 ] =
  365. & ThreadCache -> Caches[ Count2 ];
  366. }
  367. //
  368. // Create a mapping from each allocation size
  369. // to the associated cache stack for the second
  370. // cache description table.
  371. //
  372. for ( Count1=0,Count2=0;Count1 < MaxSizeToCache2;Count1 ++ )
  373. {
  374. //
  375. // We make sure that the current cache size
  376. // is large enough to hold an element of the
  377. // given size. If not we move on to the next
  378. // cache.
  379. //
  380. if
  381. (
  382. ((Count1 + 1) * Stride2)
  383. >
  384. (Caches2[ Count2 ].AllocationSize)
  385. )
  386. { Count2 ++; }
  387. //
  388. // Store a pointer so that a request for
  389. // this size of allocation goes directly
  390. // to the correct cache.
  391. //
  392. ThreadCache -> SizeToCache2[ Count1 ] =
  393. & ThreadCache -> Caches[ (MaxCaches1 + Count2) ];
  394. }
  395. //
  396. // When we setup each cache stack it is
  397. // not active but will load in details
  398. // about is maximum size, the size of
  399. // the elements it will hold and the
  400. // initial fill size.
  401. //
  402. for ( Count1=0;Count1 < MaxCaches1;Count1 ++ )
  403. {
  404. REGISTER CACHE_STACK *CacheStack =
  405. & ThreadCache -> Caches[ Count1 ];
  406. REGISTER CACHE_DETAILS *Details =
  407. & Caches1[ Count1 ];
  408. //
  409. // Setup the inital values from
  410. // the cache descriptions.
  411. //
  412. CacheStack -> Active = False;
  413. CacheStack -> MaxSize = Details -> CacheSize;
  414. CacheStack -> FillSize = 1;
  415. CacheStack -> Space = Details -> AllocationSize;
  416. CacheStack -> Top = 0;
  417. CacheStack -> Stack = NULL;
  418. }
  419. //
  420. // When we setup each cache stack it is
  421. // not active but will load in details
  422. // about is maximum size, the size of
  423. // the elements it will hold and the
  424. // initial fill size.
  425. //
  426. for ( Count1=0;Count1 < MaxCaches2;Count1 ++ )
  427. {
  428. REGISTER CACHE_STACK *CacheStack =
  429. & ThreadCache -> Caches[ MaxCaches1 + Count1 ];
  430. REGISTER CACHE_DETAILS *Details =
  431. & Caches2[ Count1 ];
  432. //
  433. // Setup the inital values from
  434. // the cache descriptions.
  435. //
  436. CacheStack -> Active = False;
  437. CacheStack -> MaxSize = Details -> CacheSize;
  438. CacheStack -> FillSize = 1;
  439. CacheStack -> Space = Details -> AllocationSize;
  440. CacheStack -> Top = 0;
  441. CacheStack -> Stack = NULL;
  442. }
  443. //
  444. // Now we have completed creating the
  445. // thread cache we have to insert it
  446. // into the active list.
  447. //
  448. Sharelock.ClaimExclusiveLock();
  449. ThreadCache -> Insert( ActiveList );
  450. Sharelock.ReleaseExclusiveLock();
  451. }
  452. }
  453. //
  454. // Create a cache for the current thread and
  455. // update the TLS pointer.
  456. //
  457. Tls -> SetPointer( ((VOID*) ThreadCache) );
  458. }
  459. /********************************************************************/
  460. /* */
  461. /* Activate a cache stack. */
  462. /* */
  463. /* Activate a cache stack and prepare it for use. */
  464. /* */
  465. /********************************************************************/
  466. void SMP_HEAP::ActivateCacheStack( CACHE_STACK *CacheStack )
  467. {
  468. //
  469. // We verify that we have not already created a
  470. // stack for the current cache. If so we create
  471. // one if there is available memory.
  472. //
  473. if ( ! CacheStack -> Active )
  474. {
  475. //
  476. // If the cache size is smaller than the
  477. // minimum size it is not worth building
  478. // a cache.
  479. //
  480. if ( CacheStack -> MaxSize >= MinThreadStack )
  481. {
  482. //
  483. // Create a new cache stack.
  484. //
  485. CacheStack -> Stack =
  486. (
  487. (VOID**) SpecialNew
  488. (
  489. (CacheStack -> MaxSize * sizeof(VOID*))
  490. )
  491. );
  492. //
  493. // The key step in this function is the
  494. // allocation of space for the cache.
  495. // If this step fails we will be unable
  496. // to do anything and will silently exit.
  497. //
  498. if ( CacheStack -> Stack != NULL )
  499. {
  500. //
  501. // Setup the cache sizes.
  502. //
  503. CacheStack -> Active = True;
  504. CacheStack -> Top = 0;
  505. }
  506. }
  507. }
  508. }
  509. /********************************************************************/
  510. /* */
  511. /* Memory deallocation. */
  512. /* */
  513. /* When we delete an allocation we try to put it in the per */
  514. /* thread cache so it can be reallocated later. */
  515. /* */
  516. /********************************************************************/
  517. bool SMP_HEAP::Delete( void *Address,int Size )
  518. {
  519. //
  520. // Although it is very rare there is a chance
  521. // that we failed to build the basic heap structures.
  522. //
  523. if ( Active )
  524. {
  525. REGISTER THREAD_CACHE *ThreadCache =
  526. ((THREAD_CACHE*) Tls -> GetPointer());
  527. //
  528. // We need to examine the TLS pointer to make
  529. // sure we have a cache for the current thread.
  530. // If not we build one for next time.
  531. //
  532. if ( ThreadCache != NULL )
  533. {
  534. AUTO int Space;
  535. //
  536. // When the heap is deleted or truncated
  537. // we have to flush the per thread caches
  538. // the next time we are called to clean
  539. // out any stale contents.
  540. //
  541. if ( ThreadCache -> Flush )
  542. { FlushThreadCache( ThreadCache ); }
  543. //
  544. // We would like to put the deleted
  545. // allocation back in the cache.
  546. // However, we don't have any information
  547. // about it so we need to get its size
  548. // and verify it will fit in the cache.
  549. //
  550. if
  551. (
  552. ROCKALL::Details( Address,& Space )
  553. &&
  554. ((Space > 0) && (Space < MaxSize2))
  555. )
  556. {
  557. REGISTER CACHE_STACK *CacheStack =
  558. (FindCache( Space,ThreadCache ));
  559. //
  560. // We try to put the deleted element
  561. // back into the per thread cache. If
  562. // the cache is not active then we
  563. // activate it for next time.
  564. //
  565. if ( CacheStack -> Active )
  566. {
  567. //
  568. // Just to be sure lets just check
  569. // to make sure this is the size
  570. // that we expect.
  571. //
  572. if ( CacheStack -> Space == Space )
  573. {
  574. //
  575. // Flush the cache if it is full.
  576. //
  577. if ( CacheStack -> Top >= CacheStack -> MaxSize )
  578. {
  579. //
  580. // Flush the top half of the
  581. // cache.
  582. //
  583. CacheStack -> Top /= 2;
  584. ROCKALL::MultipleDelete
  585. (
  586. (CacheStack -> MaxSize - CacheStack -> Top),
  587. & CacheStack -> Stack[ CacheStack -> Top ],
  588. CacheStack -> Space
  589. );
  590. }
  591. //
  592. // Push the item back onto the new
  593. // stack so it can be reallocated.
  594. //
  595. CacheStack -> Stack[ (CacheStack -> Top ++) ] = Address;
  596. return True;
  597. }
  598. }
  599. else
  600. {
  601. //
  602. // Activate the cache stack for next
  603. // time.
  604. //
  605. ActivateCacheStack( CacheStack );
  606. }
  607. }
  608. }
  609. else
  610. {
  611. //
  612. // Create a thread cache for next time.
  613. //
  614. CreateThreadCache();
  615. }
  616. }
  617. //
  618. // If all else fails call the heap directly and
  619. // return the result.
  620. //
  621. return (ROCKALL::Delete( Address,Size ));
  622. }
  623. /********************************************************************/
  624. /* */
  625. /* Delete all allocations. */
  626. /* */
  627. /* We check to make sure the heap is not corrupt and force */
  628. /* the return of all heap space back to the operating system. */
  629. /* */
  630. /********************************************************************/
  631. void SMP_HEAP::DeleteAll( bool Recycle )
  632. {
  633. //
  634. // Although it is very rare there is a chance
  635. // that we failed to build the basic heap structures.
  636. //
  637. if ( Active )
  638. {
  639. //
  640. // Flush all the local caches.
  641. //
  642. FlushAllThreadCaches();
  643. //
  644. // Delete the current cache.
  645. //
  646. DeleteThreadCache();
  647. }
  648. //
  649. // Delete all outstanding allocations.
  650. //
  651. ROCKALL::DeleteAll( Recycle );
  652. }
  653. /********************************************************************/
  654. /* */
  655. /* Find a local cache. */
  656. /* */
  657. /* Find the local cache that allocates elements of the supplied */
  658. /* size for this thread. */
  659. /* */
  660. /********************************************************************/
  661. CACHE_STACK *SMP_HEAP::FindCache( int Size,THREAD_CACHE *ThreadCache )
  662. {
  663. if ( Size <= MaxSize1 )
  664. { return (ThreadCache -> SizeToCache1[ ((Size-1) >> ShiftSize1) ]); }
  665. else
  666. { return (ThreadCache -> SizeToCache2[ ((Size-1) >> ShiftSize2) ]); }
  667. }
  668. /********************************************************************/
  669. /* */
  670. /* Flush all local caches. */
  671. /* */
  672. /* Flush the local per thread caches by setting each caches */
  673. /* flush flag (the actual flush occurs sometime later). */
  674. /* */
  675. /********************************************************************/
  676. void SMP_HEAP::FlushAllThreadCaches( void )
  677. {
  678. REGISTER THREAD_CACHE *Current;
  679. //
  680. // Claim a process wide lock.
  681. //
  682. Sharelock.ClaimShareLock();
  683. //
  684. // Walk the list of active caches and set
  685. // the flush flag.
  686. //
  687. for
  688. (
  689. Current = ((THREAD_CACHE*) ActiveList -> First());
  690. (Current != NULL);
  691. Current = ((THREAD_CACHE*) Current -> Next())
  692. )
  693. { Current -> Flush = True; }
  694. //
  695. // Release the lock.
  696. //
  697. Sharelock.ReleaseShareLock();
  698. }
  699. /********************************************************************/
  700. /* */
  701. /* Flush a local cache. */
  702. /* */
  703. /* Flush a local per thread cache and return all the outstanding */
  704. /* allocations to the main heap. */
  705. /* */
  706. /********************************************************************/
  707. void SMP_HEAP::FlushThreadCache( THREAD_CACHE *ThreadCache )
  708. {
  709. //
  710. // We would hope that there is a cache to flush
  711. // but just to be sure we verify it.
  712. //
  713. if ( ThreadCache != NULL )
  714. {
  715. REGISTER SBIT32 Count;
  716. REGISTER SBIT32 MaxCaches = (MaxCaches1 + MaxCaches2);
  717. //
  718. // Reset the flags.
  719. //
  720. ThreadCache -> Flush = False;
  721. //
  722. // Flush all the caches.
  723. //
  724. for ( Count=0;Count < MaxCaches;Count ++ )
  725. { FlushCacheStack( & ThreadCache -> Caches[ Count ] ); }
  726. }
  727. }
  728. /********************************************************************/
  729. /* */
  730. /* Flush a cache stack. */
  731. /* */
  732. /* Flush a cache stack back to the main memory manager to */
  733. /* release the cached space. */
  734. /* */
  735. /********************************************************************/
  736. void SMP_HEAP::FlushCacheStack( CACHE_STACK *CacheStack )
  737. {
  738. //
  739. // There is a chance that this cache is not active.
  740. // If so we skip the cache flush.
  741. //
  742. if ( CacheStack -> Active )
  743. {
  744. REGISTER SBIT32 Top = CacheStack -> Top;
  745. //
  746. // We flush the cache if it has any allocated
  747. // space. If not we just exit.
  748. //
  749. if ( Top != 0 )
  750. {
  751. //
  752. // Zero the top of stack.
  753. //
  754. CacheStack -> FillSize = 1;
  755. CacheStack -> Top = 0;
  756. //
  757. // We simply flush any allocated memory
  758. // back to the heap. This looks easy
  759. // doesn't it. However, if the 'DeleteAll()'
  760. // function was called then this memory
  761. // might exist. However, if 'Truncate()'
  762. // was called it should. Moreover, some of
  763. // the allocations might not even be from
  764. // this heap. What a mess. We avoid all
  765. // this by disabling 'Recycle' and skiping
  766. // any complaints about unallocated memory.
  767. //
  768. ROCKALL::MultipleDelete
  769. (
  770. Top,
  771. CacheStack -> Stack,
  772. CacheStack -> Space
  773. );
  774. }
  775. }
  776. }
  777. /********************************************************************/
  778. /* */
  779. /* Memory allocation. */
  780. /* */
  781. /* We allocate space for the current thread from the local */
  782. /* per thread cache. If we run out of space we bulk load */
  783. /* additional elements from a central shared heap. */
  784. /* */
  785. /********************************************************************/
  786. void *SMP_HEAP::New( int Size,int *Space,bool Zero )
  787. {
  788. //
  789. // Although it is very rare there is a chance
  790. // that we failed to build the basic heap structures.
  791. //
  792. if ( Active )
  793. {
  794. REGISTER THREAD_CACHE *ThreadCache =
  795. ((THREAD_CACHE*) Tls -> GetPointer());
  796. //
  797. // We need to examine the TLS pointer to make
  798. // sure we have a cache for the current thread.
  799. // If not we build one for next time.
  800. //
  801. if ( ThreadCache != NULL )
  802. {
  803. //
  804. // When the heap is deleted or truncated
  805. // we have to flush the per thread caches
  806. // the next time we are called to clean
  807. // out any stale contents.
  808. //
  809. if ( ThreadCache -> Flush )
  810. { FlushThreadCache( ThreadCache ); }
  811. //
  812. // The per thread cache can only slave
  813. // certain allocation sizes. If the size
  814. // is out of range then pass it along to
  815. // the allocator.
  816. //
  817. if ( (Size > 0) && (Size < MaxSize2) )
  818. {
  819. REGISTER CACHE_STACK *CacheStack =
  820. (FindCache( Size,ThreadCache ));
  821. //
  822. // Although we have created a cache
  823. // description it may not be active.
  824. //
  825. if ( CacheStack -> Active )
  826. {
  827. //
  828. // We see if we need to refill the
  829. // current cache. If so we increase
  830. // the fill size slowly ensure good
  831. // overall utilization.
  832. //
  833. if ( CacheStack -> Top <= 0 )
  834. {
  835. REGISTER SBIT32 MaxFillSize =
  836. (CacheStack -> MaxSize / 2);
  837. //
  838. // We slowly increse the fill size
  839. // of the cache to make sure we don't
  840. // waste too much space.
  841. //
  842. if ( CacheStack -> FillSize < MaxFillSize )
  843. {
  844. if ( (CacheStack -> FillSize *= 2) > MaxFillSize )
  845. { CacheStack -> FillSize = MaxFillSize; }
  846. }
  847. //
  848. // Refill the current cache stack.
  849. //
  850. ROCKALL::MultipleNew
  851. (
  852. ((int*) & CacheStack -> Top),
  853. ((void**) CacheStack -> Stack),
  854. ((int) CacheStack -> FillSize),
  855. ((int) CacheStack -> Space)
  856. );
  857. }
  858. //
  859. // If there is some space in the
  860. // current cache stack we allocate it.
  861. //
  862. if ( CacheStack -> Top > 0 )
  863. {
  864. REGISTER VOID *Address =
  865. (CacheStack -> Stack[ (-- CacheStack -> Top) ]);
  866. //
  867. // Prefetch the first cache line of
  868. // the allocation if we are running
  869. // a Pentium III or better.
  870. //
  871. Prefetch.L1( ((CHAR*) Address),1 );
  872. //
  873. // If the caller want to know the
  874. // real size them we supply it.
  875. //
  876. if ( Space != NULL )
  877. { (*Space) = CacheStack -> Space; }
  878. //
  879. // If we need to zero the allocation
  880. // we do it here.
  881. //
  882. if ( Zero )
  883. { ZeroMemory( Address,CacheStack -> Space ); }
  884. return Address;
  885. }
  886. }
  887. else
  888. {
  889. //
  890. // Activate the cache stack for next
  891. // time.
  892. //
  893. ActivateCacheStack( CacheStack );
  894. }
  895. }
  896. }
  897. else
  898. {
  899. //
  900. // Create a thread cache for next time.
  901. //
  902. CreateThreadCache();
  903. }
  904. }
  905. //
  906. // If all else fails call the heap directly and
  907. // return the result.
  908. //
  909. return (ROCKALL::New( Size,Space,Zero ));
  910. }
  911. /********************************************************************/
  912. /* */
  913. /* Search all local caches. */
  914. /* */
  915. /* Search the local per thread caches by for an address so we */
  916. /* know whether it is available. */
  917. /* */
  918. /********************************************************************/
  919. bool SMP_HEAP::SearchAllThreadCaches( void *Address,int Size )
  920. {
  921. REGISTER LIST *Current;
  922. REGISTER bool Result = False;
  923. //
  924. // Claim a process wide lock.
  925. //
  926. Sharelock.ClaimShareLock();
  927. //
  928. // Walk the list of active caches.
  929. //
  930. for
  931. (
  932. Current = ActiveList -> First();
  933. ((Current != NULL) && (! Result));
  934. Current = Current -> Next()
  935. )
  936. {
  937. //
  938. // Search each per thread cache.
  939. //
  940. Result =
  941. (
  942. SearchThreadCache
  943. (
  944. Address,
  945. Size,
  946. ((THREAD_CACHE*) Current)
  947. )
  948. );
  949. }
  950. //
  951. // Release the lock.
  952. //
  953. Sharelock.ReleaseShareLock();
  954. return Result;
  955. }
  956. /********************************************************************/
  957. /* */
  958. /* Search a local cache. */
  959. /* */
  960. /* Search a local per thread cache for a memory allocation. */
  961. /* */
  962. /********************************************************************/
  963. bool SMP_HEAP::SearchThreadCache
  964. (
  965. void *Address,
  966. int Size,
  967. THREAD_CACHE *ThreadCache
  968. )
  969. {
  970. //
  971. // We would hope that there is a cache to search
  972. // but just to be sure we verify it.
  973. //
  974. if ( ThreadCache != NULL )
  975. {
  976. //
  977. // The per thread cache can only slave
  978. // certain allocation sizes. If the size
  979. // is out of range then skip the search.
  980. //
  981. if ( (Size > 0) && (Size < MaxSize2) )
  982. {
  983. REGISTER CACHE_STACK *CacheStack =
  984. (FindCache( Size,ThreadCache ));
  985. return (SearchCacheStack( Address,CacheStack ));
  986. }
  987. }
  988. return False;
  989. }
  990. /********************************************************************/
  991. /* */
  992. /* Search a cache stack. */
  993. /* */
  994. /* Search a cache stack for an allocation address. */
  995. /* */
  996. /********************************************************************/
  997. bool SMP_HEAP::SearchCacheStack( void *Address,CACHE_STACK *CacheStack )
  998. {
  999. //
  1000. // There is a chance that this cache is not active.
  1001. // If so we skip the cache flush.
  1002. //
  1003. if ( CacheStack -> Active )
  1004. {
  1005. REGISTER SBIT32 Count;
  1006. //
  1007. // Search for the address.
  1008. //
  1009. for ( Count=(CacheStack -> Top-1);Count >= 0;Count -- )
  1010. {
  1011. //
  1012. // If the address matches exit.
  1013. //
  1014. if ( Address == CacheStack -> Stack[ Count ] )
  1015. { return True; }
  1016. }
  1017. }
  1018. return False;
  1019. }
  1020. /********************************************************************/
  1021. /* */
  1022. /* Truncate the heap. */
  1023. /* */
  1024. /* We need to truncate the heap. This is pretty much a null */
  1025. /* call as we do this as we go along anyway. The only thing we */
  1026. /* can do is free any space the user suggested keeping earlier. */
  1027. /* */
  1028. /********************************************************************/
  1029. bool SMP_HEAP::Truncate( int MaxFreeSpace )
  1030. {
  1031. //
  1032. // Although it is very rare there is a chance
  1033. // that we failed to build the basic heap structures.
  1034. //
  1035. if ( Active )
  1036. {
  1037. //
  1038. // Flush all the local caches.
  1039. //
  1040. FlushAllThreadCaches();
  1041. //
  1042. // Delete the current cache.
  1043. //
  1044. DeleteThreadCache();
  1045. }
  1046. //
  1047. // Truncate the heap.
  1048. //
  1049. return (ROCKALL::Truncate( MaxFreeSpace ));
  1050. }
  1051. /********************************************************************/
  1052. /* */
  1053. /* Verify memory allocation details. */
  1054. /* */
  1055. /* Extract information about a memory allocation and just for */
  1056. /* good measure check the guard words at the same time. */
  1057. /* */
  1058. /********************************************************************/
  1059. bool SMP_HEAP::Verify( void *Address,int *Space )
  1060. {
  1061. AUTO int Size;
  1062. //
  1063. // Extract information about the memory
  1064. // allocation.
  1065. //
  1066. if ( ROCKALL::Verify( Address,& Size ) )
  1067. {
  1068. //
  1069. // If the caller requested the allocation
  1070. // size then return it.
  1071. //
  1072. if ( Space != NULL )
  1073. { (*Space) = Size; }
  1074. //
  1075. // Although it is very rare there is a
  1076. // chance that we failed to build the
  1077. // basic heap structures.
  1078. //
  1079. if ( Active )
  1080. {
  1081. //
  1082. // Search for the allocation in the
  1083. // local per thread caches.
  1084. //
  1085. return (! SearchAllThreadCaches( Address,Size ));
  1086. }
  1087. return true;
  1088. }
  1089. else
  1090. { return false; }
  1091. }
  1092. /********************************************************************/
  1093. /* */
  1094. /* Walk the heap. */
  1095. /* */
  1096. /* We have been asked to walk the heap. It is hard to know */
  1097. /* why anybody might want to do this given the rest of the */
  1098. /* functionality available. Nonetheless, we just do what is */
  1099. /* required to keep everyone happy. */
  1100. /* */
  1101. /********************************************************************/
  1102. bool SMP_HEAP::Walk( bool *Activity,void **Address,int *Space )
  1103. {
  1104. //
  1105. // Walk the heap.
  1106. //
  1107. if ( ROCKALL::Walk( Activity,Address,Space ) )
  1108. {
  1109. //
  1110. // Although it is very rare there is a
  1111. // chance that we failed to build the
  1112. // basic heap structures.
  1113. //
  1114. if ( Active )
  1115. {
  1116. //
  1117. // Search for the allocation in the
  1118. // local per thread caches.
  1119. //
  1120. (*Activity) = (! SearchAllThreadCaches( Address,(*Space) ));
  1121. }
  1122. return true;
  1123. }
  1124. else
  1125. { return false; }
  1126. }
  1127. /********************************************************************/
  1128. /* */
  1129. /* Delete a local cache. */
  1130. /* */
  1131. /* Delete a local per thread cache and return all the outstanding */
  1132. /* allocations to the main heap. */
  1133. /* */
  1134. /********************************************************************/
  1135. void SMP_HEAP::DeleteThreadCache( void )
  1136. {
  1137. REGISTER THREAD_CACHE *ThreadCache =
  1138. ((THREAD_CACHE*) Tls -> GetPointer());
  1139. //
  1140. // We would certainly expect to have a cache
  1141. // to delete but we check just to be sure.
  1142. //
  1143. if ( ThreadCache != NULL )
  1144. {
  1145. //
  1146. // Flush the cache.
  1147. //
  1148. FlushThreadCache( ThreadCache );
  1149. //
  1150. // We have finished with the cache so
  1151. // add it to the list of free caches
  1152. // so we can find it again later.
  1153. //
  1154. Sharelock.ClaimExclusiveLock();
  1155. ThreadCache -> Delete( ActiveList );
  1156. ThreadCache -> Insert( FreeList );
  1157. Sharelock.ReleaseExclusiveLock();
  1158. //
  1159. // Delete the threads private cache
  1160. // pointer so it can no longer find
  1161. // the cache.
  1162. //
  1163. Tls -> SetPointer( NULL );
  1164. }
  1165. }
  1166. /********************************************************************/
  1167. /* */
  1168. /* Class destructor. */
  1169. /* */
  1170. /* Destory the heap. */
  1171. /* */
  1172. /********************************************************************/
  1173. SMP_HEAP::~SMP_HEAP( void )
  1174. {
  1175. //
  1176. // Although it is very rare there is a chance
  1177. // that we failed to build the basic heap structures.
  1178. //
  1179. if ( Active )
  1180. {
  1181. //
  1182. // Deactivate the cache.
  1183. //
  1184. Active = False;
  1185. FlushAllThreadCaches();
  1186. //
  1187. // Call the list and TLS destructors.
  1188. //
  1189. PLACEMENT_DELETE( Tls,THREAD_LOCAL_STORE );
  1190. PLACEMENT_DELETE( FreeList,LIST );
  1191. PLACEMENT_DELETE( ActiveList,LIST );
  1192. }
  1193. }