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.

1038 lines
24 KiB

  1. //#---------------------------------------------------------------
  2. // File: CPool.cpp
  3. //
  4. // Synopsis: This file implements the CPool class
  5. //
  6. // Copyright (C) 1995 Microsoft Corporation
  7. // All rights reserved.
  8. //
  9. // Authors: HowardCu
  10. //----------------------------------------------------------------
  11. #ifdef THIS_FILE
  12. #undef THIS_FILE
  13. #endif
  14. static char __szTraceSourceFile[] = __FILE__;
  15. #define THIS_FILE __szTraceSourceFile
  16. #include <windows.h>
  17. #include "cpool.h"
  18. #include "dbgtrace.h"
  19. #define PREAMBLE (BYTE)'H'
  20. #define POSTAMBLE (BYTE)'C'
  21. #define FILLER (BYTE)0xCC
  22. //
  23. // Define internal Debug structs designed to help find over/underwrites
  24. //
  25. #ifdef DEBUG
  26. #ifndef DISABLE_CPOOL_DEBUG
  27. #define CPOOL_DEBUG
  28. #endif
  29. #endif
  30. #ifdef CPOOL_DEBUG
  31. #define HEAD_SIGNATURE (DWORD)'daeH'
  32. #define TAIL_SIGNATURE (DWORD)'liaT'
  33. #define FREE_STATE (DWORD)'eerF'
  34. #define USED_STATE (DWORD)'desU'
  35. //
  36. // forward declaration
  37. //
  38. class CPoolDebugTail;
  39. //
  40. // Prefix for CPool instances when in debug mode
  41. //
  42. class CPoolDebugHead {
  43. public:
  44. //
  45. // declared so normal CPool free list can clobber this member
  46. //
  47. void* m_pLink;
  48. CPoolDebugHead();
  49. ~CPoolDebugHead( void );
  50. void *operator new( size_t cSize, void *pInstance )
  51. { return pInstance; };
  52. void operator delete (void *pInstance) {};
  53. //
  54. // Function to mark the instance in use
  55. //
  56. void MarkInUse( DWORD m_dwSignature, DWORD m_cInstanceSize );
  57. //
  58. // Function to mark the instance free
  59. //
  60. void MarkFree( DWORD m_dwSignature, DWORD m_cInstanceSize );
  61. //
  62. // class signature
  63. //
  64. DWORD m_dwSignature;
  65. //
  66. // state; either FREE_STATE or USED_STATE
  67. //
  68. DWORD m_dwState;
  69. //
  70. // time of allocation
  71. //
  72. SYSTEMTIME m_time;
  73. //
  74. // ThreadID which alloc'd/free'd memory
  75. //
  76. DWORD m_dwThreadID;
  77. //
  78. // tail pointer used to find the end
  79. //
  80. CPoolDebugTail UNALIGNED *m_pTailDebug;
  81. //
  82. // parent CPool signature
  83. //
  84. DWORD m_dwPoolSignature;
  85. //
  86. // parent CPool Fragment
  87. //
  88. LPVOID m_PoolFragment;
  89. };
  90. //
  91. // Suffix for CPool instances when in debug mode
  92. //
  93. class CPoolDebugTail {
  94. public:
  95. CPoolDebugTail();
  96. ~CPoolDebugTail( void );
  97. void *operator new( size_t cSize, void *pInstance )
  98. { return pInstance; };
  99. void operator delete (void *pInstance) {};
  100. //
  101. // routine to validate the integrity of the instance
  102. //
  103. void IsValid( DWORD dwPoolSignature, DWORD cInstanceSize );
  104. //
  105. // class signature
  106. //
  107. DWORD m_dwSignature;
  108. //
  109. // tail pointer used to find the end
  110. //
  111. CPoolDebugHead UNALIGNED *m_pHeadDebug;
  112. };
  113. //+---------------------------------------------------------------
  114. //
  115. // Function: CPoolDebugHead
  116. //
  117. // Synopsis: constructor; extra init done in def'n
  118. //
  119. // Arguments: void
  120. //
  121. // Returns: void
  122. //
  123. //----------------------------------------------------------------
  124. CPoolDebugHead::CPoolDebugHead( void ) :
  125. m_dwState( FREE_STATE ),
  126. m_dwSignature( HEAD_SIGNATURE ),
  127. m_pTailDebug( NULL )
  128. {
  129. //
  130. // debug helpers
  131. //
  132. GetLocalTime( &m_time ) ;
  133. m_dwThreadID = GetCurrentThreadId();
  134. }
  135. //+---------------------------------------------------------------
  136. //
  137. // Function: ~CPoolDebugHead
  138. //
  139. // Synopsis: destructor; only used to assert error conditions
  140. //
  141. // Arguments: void
  142. //
  143. // Returns: void
  144. //
  145. //----------------------------------------------------------------
  146. CPoolDebugHead::~CPoolDebugHead( void )
  147. {
  148. _ASSERT( m_dwSignature == HEAD_SIGNATURE );
  149. }
  150. //+---------------------------------------------------------------
  151. //
  152. // Function: CPoolDebugHead::MarkInUse
  153. //
  154. // Synopsis: Called when instance is allocated
  155. //
  156. // Arguments: DWORD dwPoolSignature: signature of parent pool
  157. // DWORD cInstanceSize: instance size of parent pool
  158. //
  159. // Returns: void
  160. //
  161. //----------------------------------------------------------------
  162. void CPoolDebugHead::MarkInUse( DWORD dwPoolSignature, DWORD cInstanceSize )
  163. {
  164. _ASSERT( m_dwSignature == HEAD_SIGNATURE );
  165. _ASSERT( m_dwState == FREE_STATE );
  166. m_dwState = USED_STATE;
  167. //
  168. // validate that the application portion is not tampered with
  169. //
  170. for ( LPBYTE pb = (LPBYTE)(this+1);
  171. pb < (LPBYTE)m_pTailDebug;
  172. pb++ )
  173. {
  174. _ASSERT( *pb == FILLER );
  175. }
  176. //
  177. // check the validity of the entire instance
  178. //
  179. m_pTailDebug->IsValid( dwPoolSignature, cInstanceSize );
  180. //
  181. // debug helpers
  182. //
  183. GetLocalTime( &m_time ) ;
  184. m_dwThreadID = GetCurrentThreadId();
  185. }
  186. //+---------------------------------------------------------------
  187. //
  188. // Function: CPoolDebugHead::MarkFree
  189. //
  190. // Synopsis: Called when instance is freed
  191. //
  192. // Arguments: DWORD dwPoolSignature: signature of parent pool
  193. // DWORD cInstanceSize: instance size of parent pool
  194. //
  195. // Returns: void
  196. //
  197. //----------------------------------------------------------------
  198. void CPoolDebugHead::MarkFree( DWORD dwPoolSignature, DWORD cInstanceSize )
  199. {
  200. _ASSERT( m_dwSignature == HEAD_SIGNATURE );
  201. //
  202. // Check and set the state
  203. //
  204. _ASSERT( m_dwState == USED_STATE );
  205. m_dwState = FREE_STATE;
  206. //
  207. // check enough to call IsValid
  208. //
  209. _ASSERT( m_pTailDebug != 0 );
  210. _ASSERT( (DWORD_PTR)m_pTailDebug > (DWORD_PTR)this );
  211. _ASSERT( m_dwThreadID != 0 ) ;
  212. //
  213. // check the validity of the entire instance
  214. //
  215. m_pTailDebug->IsValid( dwPoolSignature, cInstanceSize );
  216. //
  217. // set the application data to filler
  218. //
  219. FillMemory( (LPBYTE)(this+1),
  220. (DWORD)((LPBYTE)m_pTailDebug - (LPBYTE)(this+1)),
  221. FILLER );
  222. //
  223. // debug helpers
  224. //
  225. GetLocalTime( &m_time ) ;
  226. m_dwThreadID = GetCurrentThreadId();
  227. }
  228. //+---------------------------------------------------------------
  229. //
  230. // Function: CPoolDebugTail
  231. //
  232. // Synopsis: constructor; extra init done in def'n
  233. //
  234. // Arguments: void
  235. //
  236. // Returns: void
  237. //
  238. //----------------------------------------------------------------
  239. CPoolDebugTail::CPoolDebugTail( void ) :
  240. m_dwSignature( TAIL_SIGNATURE ),
  241. m_pHeadDebug( NULL )
  242. {
  243. }
  244. //+---------------------------------------------------------------
  245. //
  246. // Function: ~CPoolDebugTail
  247. //
  248. // Synopsis: destructor; only used to assert error conditions
  249. //
  250. // Arguments: void
  251. //
  252. // Returns: void
  253. //
  254. //----------------------------------------------------------------
  255. CPoolDebugTail::~CPoolDebugTail( void )
  256. {
  257. _ASSERT( m_dwSignature == TAIL_SIGNATURE );
  258. }
  259. //+---------------------------------------------------------------
  260. //
  261. // Function: IsValid
  262. //
  263. // Synopsis: check validity of instance
  264. //
  265. // Arguments: DWORD dwPoolSignature: signature of parent pool
  266. // DWORD cInstanceSize: instance size of parent pool
  267. //
  268. // Returns: void
  269. //
  270. //----------------------------------------------------------------
  271. void CPoolDebugTail::IsValid( DWORD dwPoolSignature, DWORD cInstanceSize )
  272. {
  273. _ASSERT( m_dwSignature == TAIL_SIGNATURE );
  274. //
  275. // validate that the head is offset at the correct location
  276. //
  277. _ASSERT( m_pHeadDebug != NULL );
  278. _ASSERT( (UINT_PTR)m_pHeadDebug == (UINT_PTR)(this+1) - cInstanceSize );
  279. //
  280. // validate the head structure
  281. //
  282. _ASSERT( m_pHeadDebug->m_dwSignature == HEAD_SIGNATURE );
  283. _ASSERT( m_pHeadDebug->m_dwPoolSignature == dwPoolSignature );
  284. _ASSERT( m_pHeadDebug->m_pTailDebug == this );
  285. _ASSERT( m_pHeadDebug->m_dwState == FREE_STATE ||
  286. m_pHeadDebug->m_dwState == USED_STATE );
  287. }
  288. #endif
  289. //+---------------------------------------------------------------
  290. //
  291. // Function: CPool
  292. //
  293. // Synopsis: constructor
  294. //
  295. // Arguments: void
  296. //
  297. // Returns: void
  298. //
  299. // History: gordm Created 5 Jul 1995
  300. //
  301. //----------------------------------------------------------------
  302. CPool::CPool( DWORD dwSignature ) : m_dwSignature( dwSignature )
  303. {
  304. TraceFunctEnter( "CPool::CPool" );
  305. m_pFreeList = NULL;
  306. m_pExtraFreeLink = NULL;
  307. //
  308. // Debug variables to help catch heap bugs
  309. //
  310. m_pLastAlloc = NULL;
  311. m_pLastExtraAlloc = NULL;
  312. m_cTotalFrees = 0;
  313. m_cTotalAllocs = 0;
  314. m_cTotalExtraAllocs = 0;
  315. m_cInstanceSize = 0;
  316. //
  317. // Avail + InUse should equal Committed if we're not
  318. // in grow/alloc or free. Diagnostic and admin only
  319. // This will keep code in critsec as small as possible
  320. //
  321. m_cNumberAvail = 0;
  322. m_cNumberInUse = 0;
  323. m_cNumberCommitted = 0;
  324. InitializeCriticalSection( &m_PoolCriticalSection );
  325. //
  326. // initialize the fragment member variables
  327. //
  328. m_cFragmentInstances = 0;
  329. m_cFragments = 0;
  330. ZeroMemory( m_pFragments, sizeof(m_pFragments) );
  331. TraceFunctLeave();
  332. }
  333. //+---------------------------------------------------------------
  334. //
  335. // Function: ~CPool
  336. //
  337. // Synopsis: destructor
  338. //
  339. // Arguments: void
  340. //
  341. // Returns: void
  342. //
  343. // History: HowardCu Created 8 May 1995
  344. //
  345. //----------------------------------------------------------------
  346. CPool::~CPool( void )
  347. {
  348. TraceFunctEnter( "CPool::~CPool" );
  349. _ASSERT( m_cNumberInUse == 0 );
  350. for ( int i=0; i<MAX_CPOOL_FRAGMENTS; i++ )
  351. {
  352. _ASSERT( m_pFragments[i] == NULL );
  353. }
  354. DebugTrace( (LPARAM)this,
  355. "CPool: %x EntryCount: %d ContentionCount: %d, Allocs: %d, Frees: %d",
  356. m_dwSignature,
  357. GetEntryCount(),
  358. GetContentionCount(),
  359. GetTotalAllocCount(),
  360. GetTotalFreeCount() );
  361. DeleteCriticalSection( &m_PoolCriticalSection );
  362. TraceFunctLeave();
  363. }
  364. //+---------------------------------------------------------------
  365. //
  366. // Function: Alloc
  367. //
  368. // Synopsis: Allocates a new instance from the pool
  369. //
  370. // Arguments: void
  371. //
  372. // Returns: pointer to the new instance
  373. //
  374. // History: gordm Created 5 Jul 1995
  375. //
  376. //----------------------------------------------------------------
  377. void* CPool::Alloc( void )
  378. {
  379. #ifdef ALLOC_TRACING
  380. TraceFunctEnter( "CPool::Alloc" );
  381. #endif
  382. Link* pAlloc;
  383. IsValid();
  384. //
  385. // moved outside of the critsec because it should not be necessary
  386. // to protect this variable. inc before the alloc so this var wraps
  387. // the actual allocation
  388. //
  389. InterlockedIncrement( (LPLONG)&m_cNumberInUse );
  390. //
  391. // check the extra pointer to avoid the critsec path if
  392. // possible. big wins because we can potentially avoid
  393. // the extra code and the wait on semaphore
  394. //
  395. pAlloc = (Link*)InterlockedExchangePointer( (PVOID*)&m_pExtraFreeLink, NULL );
  396. if ( pAlloc == NULL )
  397. {
  398. EnterCriticalSection( &m_PoolCriticalSection );
  399. //
  400. // commit more memory if the list is empty
  401. //
  402. if ( (m_pFreeList == NULL) && (m_cNumberCommitted < m_cMaxInstances) )
  403. {
  404. GrowPool();
  405. }
  406. //
  407. // try to allocate a Descriptor from the free list
  408. //
  409. if ( (pAlloc = m_pFreeList) != NULL )
  410. {
  411. m_pFreeList = pAlloc->pNext;
  412. }
  413. m_pLastAlloc = pAlloc;
  414. LeaveCriticalSection( &m_PoolCriticalSection );
  415. }
  416. else
  417. {
  418. m_pLastExtraAlloc = pAlloc;
  419. m_cTotalExtraAllocs++;
  420. }
  421. //
  422. // alloc failed
  423. //
  424. if ( pAlloc == NULL )
  425. {
  426. InterlockedDecrement( (LPLONG)&m_cNumberInUse );
  427. }
  428. else
  429. {
  430. //
  431. // debug/admin use only - ok to do outside of critsec
  432. //
  433. m_cTotalAllocs++;
  434. #ifdef CPOOL_DEBUG
  435. CPoolDebugHead* pHead = (CPoolDebugHead*)pAlloc;
  436. //
  437. // validate that the address in the range
  438. //
  439. _ASSERT( (char*)pAlloc >= pHead->m_PoolFragment );
  440. _ASSERT( (char*)pAlloc < (char*)pHead->m_PoolFragment +
  441. m_cNumberCommitted*m_cInstanceSize );
  442. pHead->MarkInUse( m_dwSignature, m_cInstanceSize );
  443. pAlloc = (Link*)(pHead+1);
  444. #endif
  445. }
  446. #ifdef ALLOC_TRACING
  447. DebugTrace( (LPARAM)this, "Alloc: 0x%08X", pAlloc );
  448. TraceFunctLeave();
  449. #endif
  450. return (void*)pAlloc;
  451. }
  452. //+---------------------------------------------------------------
  453. //
  454. // Function: Free
  455. //
  456. // Synopsis: frees the instances
  457. //
  458. // Arguments: pInstance - a pointer to the CDescriptor
  459. //
  460. // Returns: void
  461. //
  462. // History: gordm Created 5 Jul 1995
  463. //
  464. //----------------------------------------------------------------
  465. void CPool::Free( void* pInstance )
  466. {
  467. #ifdef ALLOC_TRACING
  468. TraceFunctEnter( "CPool::Free" );
  469. #endif
  470. #ifdef CPOOL_DEBUG
  471. CPoolDebugHead* pHead = ((CPoolDebugHead*)pInstance) - 1;
  472. //
  473. // validate that the address in the range
  474. //
  475. _ASSERT( (char*)pInstance >=pHead->m_PoolFragment);
  476. _ASSERT( (char*)pInstance < (char*)pHead->m_PoolFragment +
  477. m_cNumberCommitted*m_cInstanceSize );
  478. pHead->MarkFree( m_dwSignature, m_cInstanceSize );
  479. pInstance = (void*)pHead;
  480. #endif
  481. IsValid();
  482. _ASSERT(m_cNumberInUse > 0);
  483. pInstance = InterlockedExchangePointer( (LPVOID *)&m_pExtraFreeLink, pInstance );
  484. //
  485. // free the previous extra pointer if one existed
  486. //
  487. if ( pInstance != NULL )
  488. {
  489. EnterCriticalSection( &m_PoolCriticalSection );
  490. ((Link*)pInstance)->pNext = m_pFreeList;
  491. m_pFreeList = (Link*)pInstance;
  492. LeaveCriticalSection( &m_PoolCriticalSection );
  493. }
  494. //
  495. // moved outside of the critsec because it should not be necessary
  496. // to protect this variable. We'll think this list is empty only
  497. // when we get to this point. This var is inc'd before entering
  498. // the critsec and is dec'd if the operation fails.
  499. //
  500. InterlockedDecrement( (LPLONG)&m_cNumberInUse );
  501. //
  502. // debug/admin use only - ok to do outside of critsec - deletes don't fail
  503. //
  504. m_cTotalFrees++;
  505. #ifdef ALLOC_TRACING
  506. DebugTrace( (LPARAM)this, "Freed: 0x%08X", pInstance );
  507. TraceFunctLeave();
  508. #endif
  509. }
  510. //
  511. // setup a const DWORD for size manipulation
  512. //
  513. const DWORD KB = 1024;
  514. //+---------------------------------------------------------------
  515. //
  516. // Function: ReserveMemory
  517. //
  518. // Synopsis: Initializes the pool
  519. //
  520. // Arguments: NumDescriptors - the number of total descriptors in the pool
  521. // DescriptorSize - the size of any one descriptor
  522. // Signature - object signature
  523. //
  524. // Returns: TRUE is success, else FALSE
  525. //
  526. // History: HowardCu Created 8 May 1995
  527. //
  528. //----------------------------------------------------------------
  529. BOOL CPool::ReserveMemory( DWORD MaxInstances,
  530. DWORD InstanceSize,
  531. DWORD IncrementSize )
  532. {
  533. TraceFunctEnter( "CPool::ReserveMemory" );
  534. DWORD cFragments;
  535. DWORD cFragmentInstances;
  536. DWORD cIncrementInstances;
  537. _ASSERT( MaxInstances != 0 );
  538. _ASSERT( InstanceSize >= sizeof(struct Link) );
  539. #ifdef CPOOL_DEBUG
  540. InstanceSize += sizeof( CPoolDebugHead ) + sizeof( CPoolDebugTail );
  541. #endif
  542. if ( IncrementSize == DEFAULT_ALLOC_INCREMENT )
  543. {
  544. //
  545. // ensure we go to the OS for at least 8 instances at a time
  546. //
  547. if ( InstanceSize <= 4*KB / 8 )
  548. {
  549. cIncrementInstances = 4*KB / InstanceSize;
  550. }
  551. else if ( InstanceSize <= 64*KB / 8 )
  552. {
  553. cIncrementInstances = 64*KB / InstanceSize;
  554. }
  555. else
  556. {
  557. cIncrementInstances = min( MaxInstances, 8 );
  558. }
  559. }
  560. else
  561. {
  562. cIncrementInstances = IncrementSize;
  563. }
  564. //
  565. // now calculate the number larger fragments
  566. //
  567. if ( cIncrementInstances > MaxInstances )
  568. {
  569. //
  570. // no need for CPool; but we shouldn't alloc more than necessary
  571. //
  572. cFragmentInstances = cIncrementInstances = MaxInstances;
  573. cFragments = 1;
  574. }
  575. else
  576. {
  577. //
  578. // Round up MaxInstances to a integral number of IncrementSize
  579. //
  580. MaxInstances += cIncrementInstances - 1;
  581. MaxInstances /= cIncrementInstances;
  582. MaxInstances *= cIncrementInstances;
  583. //
  584. // as an initial attempt divide the number of instances by max frags
  585. //
  586. cFragmentInstances = (MaxInstances + MAX_CPOOL_FRAGMENTS - 1) /
  587. MAX_CPOOL_FRAGMENTS;
  588. if ( cFragmentInstances == 0 )
  589. {
  590. cFragmentInstances = MaxInstances;
  591. cFragments = 1;
  592. }
  593. else
  594. {
  595. //
  596. // round up the number of instances in a fragment to an
  597. // integral number of IncrementSizes
  598. //
  599. cFragmentInstances += cIncrementInstances - 1;
  600. cFragmentInstances /= cIncrementInstances;
  601. cFragmentInstances *= cIncrementInstances;
  602. //
  603. // recalculate the number of fragments required based on the integral
  604. // number of IncrementSizes ( last one may no longer be required )
  605. //
  606. cFragments = (MaxInstances + cFragmentInstances - 1) /
  607. cFragmentInstances;
  608. }
  609. }
  610. _ASSERT( cFragments > 0 );
  611. _ASSERT( cFragments*cFragmentInstances >= MaxInstances );
  612. m_cInstanceSize = InstanceSize;
  613. m_cMaxInstances = MaxInstances;
  614. m_cFragments = cFragments;
  615. m_cFragmentInstances = cFragmentInstances;
  616. m_cIncrementInstances = cIncrementInstances;
  617. TraceFunctLeave();
  618. return TRUE;
  619. }
  620. //+---------------------------------------------------------------
  621. //
  622. // Function: ReleaseMemory
  623. //
  624. // Synopsis: Releases the pool
  625. //
  626. // Arguments: none
  627. //
  628. // Returns: TRUE is success, else FALSE
  629. //
  630. // History: HowardCu Created 8 May 1995
  631. //
  632. //----------------------------------------------------------------
  633. BOOL CPool::ReleaseMemory( void )
  634. {
  635. TraceFunctEnter( "CPool::ReleaseMemory" );
  636. BOOL bFree = TRUE;
  637. DWORD i, cStart;
  638. EnterCriticalSection( &m_PoolCriticalSection );
  639. for ( i=cStart=0; i<m_cFragments; i++, cStart += m_cFragmentInstances )
  640. {
  641. LPVOID pHeap = m_pFragments[i];
  642. if ( pHeap != NULL )
  643. {
  644. _ASSERT( cStart < m_cNumberCommitted );
  645. DWORD cSize = min( m_cFragmentInstances, m_cNumberCommitted-cStart );
  646. _VERIFY( bFree = VirtualFree( pHeap, cSize*m_cInstanceSize, MEM_DECOMMIT ) );
  647. _VERIFY( bFree &=VirtualFree( pHeap, 0, MEM_RELEASE ) );
  648. if ( bFree == FALSE )
  649. {
  650. ErrorTrace( (LPARAM)this, "VirtualFree failed: err %d", GetLastError() );
  651. break;
  652. }
  653. m_pFragments[i] = NULL;
  654. }
  655. else
  656. {
  657. break;
  658. }
  659. }
  660. LeaveCriticalSection( &m_PoolCriticalSection );
  661. //
  662. // zero out important data fields
  663. //
  664. m_pFreeList = NULL;
  665. m_pExtraFreeLink = NULL;
  666. m_cNumberCommitted = 0;
  667. return bFree;
  668. }
  669. #ifdef CPOOL_DEBUG
  670. //+---------------------------------------------------------------
  671. //
  672. // Function: InitDebugInstance
  673. //
  674. // Synopsis: sets up the appropriate debug class variables
  675. //
  676. // Arguments: void* pInstance: the new instance
  677. // DWORD dwPoolSignature: parent Pool signature
  678. // DWORD cInstanceSize: size of the enlarged instance
  679. //
  680. // Returns: void
  681. //
  682. // History: gordm Created 11 Jan 1996
  683. //
  684. //----------------------------------------------------------------
  685. void InitDebugInstance(
  686. char* pInstance,
  687. DWORD dwPoolSignature,
  688. DWORD cInstanceSize,
  689. LPVOID pPoolFragment
  690. )
  691. {
  692. CPoolDebugHead* pHead = new( pInstance ) CPoolDebugHead();
  693. CPoolDebugTail* pTail = new( pInstance +
  694. cInstanceSize -
  695. sizeof(CPoolDebugTail) ) CPoolDebugTail();
  696. pHead->m_pTailDebug = pTail;
  697. pTail->m_pHeadDebug = pHead;
  698. //
  699. // helps with debugging to see the parent CPool signature
  700. //
  701. pHead->m_dwPoolSignature = dwPoolSignature;
  702. //
  703. // helps with asserts for valid ranges
  704. //
  705. pHead->m_PoolFragment = pPoolFragment;
  706. //
  707. // fake out the state before calling mark Free
  708. //
  709. pHead->m_dwState = USED_STATE;
  710. pHead->MarkFree( dwPoolSignature, cInstanceSize );
  711. }
  712. #endif
  713. //+---------------------------------------------------------------
  714. //
  715. // Function: GrowPool
  716. //
  717. // Synopsis: grows the number of committed instances in the pool
  718. //
  719. // Arguments: void
  720. //
  721. // Returns: void
  722. //
  723. // History: gordm Created 5 Jul 1995
  724. //
  725. //----------------------------------------------------------------
  726. void CPool::GrowPool( void )
  727. {
  728. #ifdef ALLOC_TRACING
  729. TraceFunctEnter( "CPool::GrowPool" );
  730. #endif
  731. DWORD cFragment = m_cNumberCommitted / m_cFragmentInstances;
  732. DWORD cStart = m_cNumberCommitted % m_cFragmentInstances;
  733. DWORD cbSize = (cStart+m_cIncrementInstances) * m_cInstanceSize;
  734. #ifdef ALLOC_TRACING
  735. DebugTrace( (LPARAM)this, "Expanding the pool to %d descriptors",
  736. cNewCommit );
  737. #endif
  738. //
  739. // if we're starting a new fragment
  740. //
  741. if ( cStart == 0 )
  742. {
  743. //
  744. // if we are at a boundary of a fragment Reserve the next fragment
  745. m_pFragments[cFragment] = VirtualAlloc(
  746. NULL,
  747. m_cFragmentInstances*m_cInstanceSize,
  748. MEM_RESERVE | MEM_TOP_DOWN,
  749. PAGE_NOACCESS
  750. );
  751. if ( m_pFragments[cFragment] == NULL )
  752. {
  753. #ifdef ALLOC_TRACING
  754. ErrorTrace( (LPARAM)this,
  755. "Could not reserve more memory: error = %d",
  756. GetLastError() );
  757. #endif
  758. return;
  759. }
  760. }
  761. LPVOID pHeap = m_pFragments[cFragment];
  762. if ( VirtualAlloc( pHeap,
  763. cbSize,
  764. MEM_COMMIT,
  765. PAGE_READWRITE ) != NULL )
  766. {
  767. char* pStart = (char*)pHeap + cStart*m_cInstanceSize;
  768. char* pLast = (char*)pHeap + cbSize - m_cInstanceSize;
  769. //
  770. // run the list joining the next pointers
  771. // possible because we own the critsec
  772. //
  773. for ( char* p=pStart; p<pLast; p+=m_cInstanceSize)
  774. {
  775. #ifdef CPOOL_DEBUG
  776. InitDebugInstance( p, m_dwSignature, m_cInstanceSize, pHeap );
  777. #endif
  778. //
  779. // statement works for CPOOL_DEBUG as well because
  780. // we reserve the first 4 bytes of CPoolDebugHead
  781. //
  782. ((Link*)p)->pNext = (Link*)(p+m_cInstanceSize);
  783. }
  784. //
  785. // terminate and then set the head to beginning of new list
  786. //
  787. #ifdef CPOOL_DEBUG
  788. InitDebugInstance( pLast, m_dwSignature, m_cInstanceSize, pHeap );
  789. #endif
  790. ((Link*)pLast)->pNext = NULL;
  791. m_pFreeList = (Link*)pStart;
  792. m_cNumberCommitted += m_cIncrementInstances;
  793. }
  794. #ifdef ALLOC_TRACING
  795. else
  796. {
  797. ErrorTrace( (LPARAM)this,
  798. "Could not commit another descriptor: error = %d",
  799. GetLastError() );
  800. }
  801. TraceFunctLeave();
  802. #endif
  803. }
  804. //+---------------------------------------------------------------
  805. //
  806. // Function: GetContentionCount
  807. //
  808. // Synopsis: Returns the contention count on the alloc/free
  809. // critsec
  810. //
  811. // Arguments: void
  812. //
  813. // Returns: the actual count
  814. //
  815. //----------------------------------------------------------------
  816. DWORD CPool::GetContentionCount( void )
  817. {
  818. return m_PoolCriticalSection.DebugInfo != NULL ?
  819. m_PoolCriticalSection.DebugInfo->ContentionCount :
  820. 0 ;
  821. }
  822. //+---------------------------------------------------------------
  823. //
  824. // Function: GetEntryCount
  825. //
  826. // Synopsis: Returns the entry count on the alloc/free
  827. // critsec
  828. //
  829. // Arguments: void
  830. //
  831. // Returns: the actual count
  832. //
  833. //----------------------------------------------------------------
  834. DWORD CPool::GetEntryCount( void )
  835. {
  836. return m_PoolCriticalSection.DebugInfo != NULL ?
  837. m_PoolCriticalSection.DebugInfo->EntryCount :
  838. 0 ;
  839. }
  840. //+---------------------------------------------------------------
  841. //
  842. // Function: GetInstanceSize
  843. //
  844. // Synopsis: Returns the application's instance size
  845. //
  846. // Arguments: void
  847. //
  848. // Returns: the instance size of the app
  849. //
  850. //----------------------------------------------------------------
  851. DWORD CPool::GetInstanceSize( void )
  852. {
  853. #ifdef CPOOL_DEBUG
  854. return m_cInstanceSize - sizeof(CPoolDebugHead) - sizeof(CPoolDebugTail);
  855. #else
  856. return m_cInstanceSize;
  857. #endif
  858. }
  859. #ifdef DEBUG
  860. //+---------------------------------------------------------------
  861. //
  862. // Function: IsValid
  863. //
  864. // Synopsis: Validates the pool signature
  865. //
  866. // Arguments: void
  867. //
  868. // Returns: TRUE is success, else FALSE
  869. //
  870. // History: HowardCu Created 8 May 1995
  871. //
  872. //----------------------------------------------------------------
  873. inline void CPool::IsValid( void )
  874. {
  875. _ASSERT( m_cMaxInstances != 0 );
  876. _ASSERT( m_cInstanceSize >= sizeof(struct Link) );
  877. _ASSERT( m_cIncrementInstances != 0 );
  878. _ASSERT( m_dwSignature != 0 );
  879. }
  880. #endif