Source code of Windows XP (NT5)
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.

695 lines
17 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1995 - 2000 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: ClassFPM.h
  6. * Content: fixed size pool manager for classes
  7. *
  8. * History:
  9. * Date By Reason
  10. * ====== == ======
  11. * 12-18-97 aarono Original
  12. * 11-06-98 ejs Add custom handler for Release function
  13. * 04-12-99 jtk Trimmed unused functions and parameters, added size assert
  14. * 01-31-00 jtk Added code to check for items already being in the pool on Release().
  15. * 03-20-01 vanceo Added thread-local versions
  16. ***************************************************************************/
  17. #ifndef __CLASS_FPM_H__
  18. #define __CLASS_FPM_H__
  19. #undef DPF_SUBCOMP
  20. #define DPF_SUBCOMP DN_SUBCOMP_COMMON
  21. //**********************************************************************
  22. // Constant definitions
  23. //**********************************************************************
  24. #define CLASSFPM_BLANK_NODE_VALUE 0x55AA817E
  25. #define CHECK_FOR_DUPLICATE_CLASSFPM_RELEASE
  26. //**********************************************************************
  27. // Macro definitions
  28. //**********************************************************************
  29. #ifndef OFFSETOF
  30. // Macro to compute the offset of an element inside of a larger structure (copied from MSDEV's STDLIB.H)
  31. #define OFFSETOF(s,m) ( (INT_PTR) &(((s *)0)->m) )
  32. #define __LOCAL_OFFSETOF_DEFINED__
  33. #endif // OFFSETOF
  34. #ifndef CONTAINING_OBJECT
  35. #define CONTAINING_OBJECT(b,t,m) (reinterpret_cast<t*>(&reinterpret_cast<BYTE*>(b)[-OFFSETOF(t,m)]))
  36. #endif
  37. //**********************************************************************
  38. // Structure definitions
  39. //**********************************************************************
  40. //**********************************************************************
  41. // Variable definitions
  42. //**********************************************************************
  43. //**********************************************************************
  44. // Function prototypes
  45. //**********************************************************************
  46. //**********************************************************************
  47. // Class definitions
  48. //**********************************************************************
  49. // class to act as a link in the pool
  50. template< class T >
  51. class CPoolNode
  52. {
  53. public:
  54. CPoolNode() { m_pNext = NULL; }
  55. ~CPoolNode() {};
  56. T m_Item;
  57. CPoolNode *m_pNext;
  58. protected:
  59. private:
  60. };
  61. // class to manage the pool
  62. template< class T >
  63. class CFixedPool
  64. {
  65. public:
  66. CFixedPool();
  67. ~CFixedPool();
  68. T *Get( void );
  69. void Release( T *const pItem );
  70. protected:
  71. private:
  72. CPoolNode< T > *m_pPool; // pointer to list of available elements
  73. DEBUG_ONLY( UINT_PTR m_uOutstandingItemCount );
  74. };
  75. //**********************************************************************
  76. // Class function definitions
  77. //**********************************************************************
  78. //**********************************************************************
  79. // ------------------------------
  80. // CFixedPool::CFixedPool - constructor
  81. //
  82. // Entry: Nothing
  83. //
  84. // Exit: Nothing
  85. // ------------------------------
  86. #undef DPF_MODNAME
  87. #define DPF_MODNAME "CFixedPool::CFixedPool"
  88. template< class T >
  89. CFixedPool< T >::CFixedPool()
  90. {
  91. m_pPool = NULL;
  92. DEBUG_ONLY( m_uOutstandingItemCount = 0 );
  93. }
  94. //**********************************************************************
  95. //**********************************************************************
  96. // ------------------------------
  97. // CFixedPool::~CFixedPool - destructor
  98. //
  99. // Entry: Nothing
  100. //
  101. // Exit: Nothing
  102. // ------------------------------
  103. #undef DPF_MODNAME
  104. #define DPF_MODNAME "CFixedPool::~CFixedPool"
  105. template< class T >
  106. CFixedPool< T >::~CFixedPool()
  107. {
  108. DEBUG_ONLY( DNASSERT( m_uOutstandingItemCount == 0 ) );
  109. while ( m_pPool != NULL )
  110. {
  111. CPoolNode< T > *pTemp;
  112. pTemp = m_pPool;
  113. m_pPool = m_pPool->m_pNext;
  114. delete pTemp;
  115. }
  116. }
  117. //**********************************************************************
  118. //**********************************************************************
  119. // ------------------------------
  120. // CFixedPool::Get - get an item from the pool
  121. //
  122. // Entry: Nothing
  123. //
  124. // Exit: Pointer to item
  125. // NULL = out of memory
  126. // ------------------------------
  127. #undef DPF_MODNAME
  128. #define DPF_MODNAME "CFixedPool::Get"
  129. template< class T >
  130. T *CFixedPool< T >::Get( void )
  131. {
  132. CPoolNode< T > *pNode;
  133. T *pReturn;
  134. // initialize
  135. pReturn = NULL;
  136. // is the pool empty?
  137. if ( m_pPool == NULL )
  138. {
  139. // try to create a new entry
  140. pNode = new CPoolNode< T >;
  141. }
  142. else
  143. {
  144. // grab first item from the pool
  145. pNode = m_pPool;
  146. m_pPool = m_pPool->m_pNext;
  147. }
  148. if ( pNode != NULL )
  149. {
  150. DEBUG_ONLY( pNode->m_pNext = (CPoolNode<T>*) CLASSFPM_BLANK_NODE_VALUE );
  151. pReturn = &pNode->m_Item;
  152. DEBUG_ONLY( m_uOutstandingItemCount++ );
  153. }
  154. return pReturn;
  155. }
  156. //**********************************************************************
  157. //**********************************************************************
  158. // ------------------------------
  159. // CFixedPool::Release - return item to pool
  160. //
  161. // Entry: Pointer to item
  162. //
  163. // Exit: Nothing
  164. // ------------------------------
  165. #undef DPF_MODNAME
  166. #define DPF_MODNAME "CFixedPool::Release"
  167. template< class T >
  168. void CFixedPool< T >::Release( T *const pItem )
  169. {
  170. CPoolNode< T > *pNode;
  171. DNASSERT( pItem != NULL );
  172. DBG_CASSERT( sizeof( BYTE* ) == sizeof( pItem ) );
  173. DBG_CASSERT( sizeof( CPoolNode< T >* ) == sizeof( BYTE* ) );
  174. pNode = reinterpret_cast<CPoolNode< T >*>( &reinterpret_cast<BYTE*>( pItem )[ -OFFSETOF( CPoolNode< T >, m_Item ) ] );
  175. #if defined(CHECK_FOR_DUPLICATE_CLASSFPM_RELEASE) && defined(DEBUG)
  176. {
  177. CPoolNode< T > *pTemp;
  178. pTemp = m_pPool;
  179. while ( pTemp != NULL )
  180. {
  181. DNASSERT( pTemp != pNode );
  182. pTemp = pTemp->m_pNext;
  183. }
  184. }
  185. #endif // CHECK_FOR_DUPLICATE_CLASSFPM_RELEASE
  186. DEBUG_ONLY( DNASSERT( pNode->m_pNext == (CPoolNode< T >*)CLASSFPM_BLANK_NODE_VALUE ) );
  187. #ifdef NO_POOLS
  188. delete pNode;
  189. #else
  190. pNode->m_pNext = m_pPool;
  191. m_pPool = pNode;
  192. #endif
  193. DEBUG_ONLY( m_uOutstandingItemCount-- );
  194. }
  195. //**********************************************************************
  196. // class to act as a link in the pool
  197. template< class T >
  198. class CTLPoolNode
  199. {
  200. public:
  201. CTLPoolNode()
  202. {
  203. m_blList.Initialize();
  204. #ifdef TRACK_POOL_STATS
  205. m_dwSourceThreadID = 0;
  206. #endif // TRACK_POOL_STATS
  207. };
  208. #undef DPF_MODNAME
  209. #define DPF_MODNAME "CTLPoolNode::~CTLPoolNode"
  210. ~CTLPoolNode()
  211. {
  212. DNASSERT(m_blList.IsEmpty());
  213. };
  214. CBilink m_blList;
  215. T m_Item;
  216. #ifdef TRACK_POOL_STATS
  217. DWORD m_dwSourceThreadID;
  218. #endif // TRACK_POOL_STATS
  219. protected:
  220. private:
  221. };
  222. // class to manage the pool
  223. template< class T >
  224. class CFixedTLPool
  225. {
  226. public:
  227. CFixedTLPool(CFixedTLPool< T > * pGlobalPool);
  228. ~CFixedTLPool();
  229. T *Get( void );
  230. void Release( T *const pItem );
  231. static void ReleaseWithoutPool( T *const pItem );
  232. protected:
  233. private:
  234. CBilink m_blItems; // bilink list of available elements
  235. CFixedTLPool< T > * m_pGlobalPool; // pointer to global pool, or NULL if this is the global pool
  236. DNCRITICAL_SECTION * m_pcsLock; // pointer to pool critical section, or NULL if this is not the global pool
  237. DWORD m_dwNumItems; // number of items currently in this pool
  238. #ifdef TRACK_POOL_STATS
  239. DWORD m_dwAllocations; // how many objects were allocated by this pool
  240. DWORD m_dwSlurpsFromGlobal; // how many times some items were taken from the global pool
  241. DWORD m_dwLargestSlurpFromGlobal; // most number of items taken from the global pool at one time
  242. DWORD m_dwRetrievals; // how many times objects were pulled out of this pool
  243. DWORD m_dwReturnsOnSameThread; // how many times objects that were pulled out of this pool were returned to this pool
  244. DWORD m_dwReturnsOnDifferentThread; // how many times objects that were pulled out of another thread's pool were returned to this pool
  245. DWORD m_dwDumpsToGlobal; // how many times some items were dumped into the global pool
  246. DWORD m_dwDeallocations; // how many objects were freed by this pool
  247. #endif // TRACK_POOL_STATS
  248. };
  249. //**********************************************************************
  250. // Class function definitions
  251. //**********************************************************************
  252. //**********************************************************************
  253. // ------------------------------
  254. // CFixedTLPool::CFixedTLPool - constructor
  255. //
  256. // Entry: Pointer to global pool, or NULL if this is a global pool
  257. //
  258. // Exit: Nothing
  259. // ------------------------------
  260. #undef DPF_MODNAME
  261. #define DPF_MODNAME "CFixedTLPool::CFixedTLPool"
  262. template< class T >
  263. CFixedTLPool< T >::CFixedTLPool(CFixedTLPool< T > * pGlobalPool):
  264. m_pGlobalPool( pGlobalPool ),
  265. m_pcsLock( NULL ),
  266. m_dwNumItems( 0 )
  267. {
  268. m_blItems.Initialize();
  269. if (pGlobalPool == NULL)
  270. {
  271. //DPFX(DPFPREP, 9, "Initializing global pool 0x%p.", this);
  272. m_pcsLock = (DNCRITICAL_SECTION*) DNMalloc( sizeof(DNCRITICAL_SECTION) );
  273. if (m_pcsLock != NULL)
  274. {
  275. if (! DNInitializeCriticalSection( m_pcsLock ))
  276. {
  277. DNFree( m_pcsLock );
  278. DEBUG_ONLY( m_pcsLock = NULL );
  279. }
  280. }
  281. }
  282. #ifdef TRACK_POOL_STATS
  283. m_dwAllocations = 0;
  284. m_dwSlurpsFromGlobal = 0;
  285. m_dwLargestSlurpFromGlobal = 0;
  286. m_dwRetrievals = 0;
  287. m_dwReturnsOnSameThread = 0;
  288. m_dwReturnsOnDifferentThread = 0;
  289. m_dwDumpsToGlobal = 0;
  290. m_dwDeallocations = 0;
  291. #endif // TRACK_POOL_STATS
  292. }
  293. //**********************************************************************
  294. //**********************************************************************
  295. // ------------------------------
  296. // CFixedTLPool::~CFixedTLPool - destructor
  297. //
  298. // Entry: Nothing
  299. //
  300. // Exit: Nothing
  301. // ------------------------------
  302. #undef DPF_MODNAME
  303. #define DPF_MODNAME "CFixedTLPool::~CFixedTLPool"
  304. template< class T >
  305. CFixedTLPool< T >::~CFixedTLPool()
  306. {
  307. CBilink * pBilink;
  308. CTLPoolNode< T > * pNode;
  309. pBilink = m_blItems.GetNext();
  310. while ( pBilink != &m_blItems )
  311. {
  312. pNode = CONTAINING_OBJECT(pBilink, CTLPoolNode< T >, m_blList);
  313. pBilink = pBilink->GetNext();
  314. pNode->m_blList.RemoveFromList();
  315. delete pNode;
  316. #ifdef TRACK_POOL_STATS
  317. m_dwDeallocations++;
  318. #endif // TRACK_POOL_STATS
  319. DEBUG_ONLY( m_dwNumItems-- );
  320. }
  321. DNASSERT( m_dwNumItems == 0 );
  322. DNASSERT( m_blItems.IsEmpty() );
  323. if (m_pcsLock != NULL)
  324. {
  325. //DPFX(DPFPREP, 9, "Deinitializing global pool 0x%p.", this);
  326. DNDeleteCriticalSection( m_pcsLock );
  327. DNFree( m_pcsLock );
  328. DEBUG_ONLY( m_pcsLock = NULL );
  329. }
  330. #ifdef TRACK_POOL_STATS
  331. DPFX(DPFPREP, 9, "Pool 0x%p information:", this);
  332. DPFX(DPFPREP, 9, "\tAllocations = %u", m_dwAllocations);
  333. DPFX(DPFPREP, 9, "\tSlurpsFromGlobal = %u", m_dwSlurpsFromGlobal);
  334. DPFX(DPFPREP, 9, "\tLargestSlurpFromGlobal = %u", m_dwLargestSlurpFromGlobal);
  335. DPFX(DPFPREP, 9, "\tRetrievals = %u", m_dwRetrievals);
  336. DPFX(DPFPREP, 9, "\tReturnsOnSameThread = %u", m_dwReturnsOnSameThread);
  337. DPFX(DPFPREP, 9, "\tReturnsOnDifferentThread = %u", m_dwReturnsOnDifferentThread);
  338. DPFX(DPFPREP, 9, "\tDumpsToGlobal = %u", m_dwDumpsToGlobal);
  339. DPFX(DPFPREP, 9, "\tDeallocations = %u", m_dwDeallocations);
  340. #endif // TRACK_POOL_STATS
  341. }
  342. //**********************************************************************
  343. //**********************************************************************
  344. // ------------------------------
  345. // CFixedTLPool::Get - get an item from the pool
  346. //
  347. // Entry: Nothing
  348. //
  349. // Exit: Pointer to item
  350. // NULL = out of memory
  351. // ------------------------------
  352. #undef DPF_MODNAME
  353. #define DPF_MODNAME "CFixedTLPool::Get"
  354. template< class T >
  355. T *CFixedTLPool< T >::Get( void )
  356. {
  357. CBilink * pBilink;
  358. CTLPoolNode< T > * pNode;
  359. T * pReturn;
  360. DNASSERT( m_pGlobalPool != NULL );
  361. //
  362. // If the pool is empty, steal the ones in the global pool.
  363. //
  364. pBilink = m_blItems.GetNext();
  365. if ( pBilink == &m_blItems )
  366. {
  367. DNEnterCriticalSection( m_pGlobalPool->m_pcsLock );
  368. pBilink = m_pGlobalPool->m_blItems.GetNext();
  369. if ( pBilink == &m_pGlobalPool->m_blItems )
  370. {
  371. //
  372. // No items. Drop global pool lock and allocate a new one.
  373. //
  374. DNLeaveCriticalSection( m_pGlobalPool->m_pcsLock );
  375. pNode = new CTLPoolNode< T >;
  376. if ( pNode != NULL )
  377. {
  378. #ifdef TRACK_POOL_STATS
  379. //
  380. // Update counter.
  381. //
  382. m_dwAllocations++;
  383. #endif // TRACK_POOL_STATS
  384. }
  385. else
  386. {
  387. pReturn = NULL;
  388. goto Exit;
  389. }
  390. }
  391. else
  392. {
  393. //
  394. // Separate all the items from the global list.
  395. // We still have a pointer to the orphaned items (pBilink).
  396. //
  397. m_pGlobalPool->m_blItems.RemoveFromList();
  398. DNASSERT(m_pGlobalPool->m_dwNumItems > 0);
  399. #ifdef TRACK_POOL_STATS
  400. m_dwSlurpsFromGlobal++;
  401. if ( m_pGlobalPool->m_dwNumItems > m_dwLargestSlurpFromGlobal )
  402. {
  403. m_dwLargestSlurpFromGlobal = m_pGlobalPool->m_dwNumItems;
  404. }
  405. #endif // TRACK_POOL_STATS
  406. m_dwNumItems = m_pGlobalPool->m_dwNumItems - 1; // -1 because we need one right now
  407. m_pGlobalPool->m_dwNumItems = 0;
  408. //
  409. // Drop the lock since we don't need the global pool anymore.
  410. //
  411. DNLeaveCriticalSection( m_pGlobalPool->m_pcsLock );
  412. //
  413. // Get the first item from the orphaned list.
  414. //
  415. pNode = CONTAINING_OBJECT(pBilink, CTLPoolNode< T >, m_blList);
  416. //
  417. // If there was more than one item in the global pool, transfer
  418. // the remaining orphaned items (after the first) to this pool.
  419. //
  420. if (pBilink != pBilink->GetNext())
  421. {
  422. pBilink = pBilink->GetNext();
  423. pNode->m_blList.RemoveFromList();
  424. m_blItems.InsertBefore(pBilink);
  425. }
  426. }
  427. }
  428. else
  429. {
  430. pNode = CONTAINING_OBJECT(pBilink, CTLPoolNode< T >, m_blList);
  431. pBilink->RemoveFromList();
  432. DNASSERT( m_dwNumItems > 0 );
  433. m_dwNumItems--;
  434. }
  435. //
  436. // If we're here, we have an entry (it was freshly created, or removed from
  437. // some pool).
  438. //
  439. pReturn = &pNode->m_Item;
  440. #ifdef TRACK_POOL_STATS
  441. //
  442. // Update status counts.
  443. //
  444. m_dwRetrievals++;
  445. pNode->m_dwSourceThreadID = GetCurrentThreadId();
  446. #endif // TRACK_POOL_STATS
  447. Exit:
  448. return pReturn;
  449. }
  450. //**********************************************************************
  451. //**********************************************************************
  452. // ------------------------------
  453. // CFixedTLPool::Release - return item to pool
  454. //
  455. // Entry: Pointer to item
  456. //
  457. // Exit: Nothing
  458. // ------------------------------
  459. #undef DPF_MODNAME
  460. #define DPF_MODNAME "CFixedTLPool::Release"
  461. template< class T >
  462. void CFixedTLPool< T >::Release( T *const pItem )
  463. {
  464. CTLPoolNode< T > *pNode;
  465. DNASSERT( m_pGlobalPool != NULL );
  466. DNASSERT( pItem != NULL );
  467. DBG_CASSERT( sizeof( BYTE* ) == sizeof( pItem ) );
  468. DBG_CASSERT( sizeof( CTLPoolNode< T >* ) == sizeof( BYTE* ) );
  469. pNode = reinterpret_cast<CTLPoolNode< T >*>( &reinterpret_cast<BYTE*>( pItem )[ -OFFSETOF( CTLPoolNode< T >, m_Item ) ] );
  470. #if defined(CHECK_FOR_DUPLICATE_CONTEXTCFPM_RELEASE) && defined(DEBUG)
  471. DNASSERT( ! pNode->m_blList.IsListMember( &m_blItems ));
  472. #endif // CHECK_FOR_DUPLICATE_CONTEXTCFPM_RELEASE
  473. #ifdef TRACK_POOL_STATS
  474. //
  475. // Update status counts.
  476. //
  477. if (pNode->m_dwSourceThreadID == GetCurrentThreadId())
  478. {
  479. m_dwReturnsOnSameThread++;
  480. }
  481. else
  482. {
  483. m_dwReturnsOnDifferentThread++;
  484. }
  485. #endif // TRACK_POOL_STATS
  486. #ifdef NO_POOLS
  487. delete pNode;
  488. #ifdef TRACK_POOL_STATS
  489. m_dwDeallocations++;
  490. #endif // TRACK_POOL_STATS
  491. #else // ! NO_POOLS
  492. pNode->m_blList.InsertAfter( &m_blItems );
  493. m_dwNumItems++;
  494. //
  495. // If this pool has built up some extra items, return them to the
  496. // global pool.
  497. //
  498. if ( m_dwNumItems >= 25 )
  499. {
  500. CBilink * pFirstItem;
  501. //
  502. // Save a pointer to the first item.
  503. //
  504. pFirstItem = m_blItems.GetNext();
  505. DNASSERT( pFirstItem != &m_blItems );
  506. //
  507. // Orphan the items.
  508. //
  509. m_blItems.RemoveFromList();
  510. //
  511. // Take the lock and transfer the list to the global pool.
  512. //
  513. DNEnterCriticalSection( m_pGlobalPool->m_pcsLock );
  514. m_pGlobalPool->m_blItems.AttachListBefore(pFirstItem);
  515. m_pGlobalPool->m_dwNumItems += m_dwNumItems;
  516. DNLeaveCriticalSection( m_pGlobalPool->m_pcsLock );
  517. m_dwNumItems = 0;
  518. #ifdef TRACK_POOL_STATS
  519. m_dwDumpsToGlobal++;
  520. #endif // TRACK_POOL_STATS
  521. }
  522. #endif // ! NO_POOLS
  523. }
  524. //**********************************************************************
  525. //**********************************************************************
  526. // ------------------------------
  527. // CFixedTLPool::ReleaseWithoutPool - destroy an item without returning it to a
  528. // pool
  529. // NOTE: this is a static function and cannot use
  530. // the 'this' pointer!
  531. //
  532. // Entry: Pointer to item
  533. //
  534. // Exit: Nothing
  535. // ------------------------------
  536. #undef DPF_MODNAME
  537. #define DPF_MODNAME "CFixedTLPool::ReleaseWithoutPool"
  538. template< class T >
  539. void CFixedTLPool< T >::ReleaseWithoutPool( T *const pItem )
  540. {
  541. CTLPoolNode< T > *pNode;
  542. DNASSERT( pItem != NULL );
  543. DBG_CASSERT( sizeof( BYTE* ) == sizeof( pItem ) );
  544. DBG_CASSERT( sizeof( CTLPoolNode< T >* ) == sizeof( BYTE* ) );
  545. pNode = reinterpret_cast<CTLPoolNode< T >*>( &reinterpret_cast<BYTE*>( pItem )[ -OFFSETOF( CTLPoolNode< T >, m_Item ) ] );
  546. DNASSERT( pNode->m_blList.IsEmpty() );
  547. delete pNode;
  548. }
  549. //**********************************************************************
  550. #ifdef __LOCAL_OFFSETOF_DEFINED__
  551. #undef __LOCAL_OFFSETOF_DEFINED__
  552. #undef OFFSETOF
  553. #endif // __LOCAL_OFFSETOF_DEFINED__
  554. #undef DPF_SUBCOMP
  555. #undef DPF_MODNAME
  556. #endif // __CLASS_FPM_H__