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.

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