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.

1031 lines
28 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-1998
  5. //
  6. // File: falloc.cxx
  7. //
  8. // Contents: Fast allocator that sits on top of HeapAlloc for
  9. // better size and performance on small allocations.
  10. //
  11. // History: 15-Mar-96 dlee Created.
  12. //
  13. // Notes: No header/tail checking is done in this allocator.
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include "falloc.hxx"
  19. #pragma optimize( "t", on )
  20. extern HANDLE gmem_hHeap;
  21. // any allocation larger than this isn't specially handled
  22. const USHORT cbMaxFalloc = 256;
  23. // allows more than 150 meg of allocations of less than cbMaxFalloc.
  24. const ULONG cMaxPages = 2048;
  25. // size of first page for each allocation granularity
  26. const ULONG cbFirstPage = 2048; //1024;
  27. #if CIDBG==1 || DBG==1
  28. DECLARE_DEBUG( fal );
  29. DECLARE_INFOLEVEL( fal );
  30. #define falDebugOut(x) falInlineDebugOut x
  31. const int fillFastAlloc = 0xda;
  32. const int fillListAlloc = 0xdb;
  33. const int fillFree = 0xdc;
  34. const int fillBigAlloc = 0xdd;
  35. const int fillBigFree = 0xde;
  36. void memPrintMemoryChains();
  37. // Define this to keep track of the amount of non-specially-handled
  38. // memory allocated. Should be turned off for a retail build.
  39. #define FALLOC_TRACK_NOTINPAGE
  40. #endif // CIDBG==1 || DBG==1
  41. CMemMutex gmem_mutex;
  42. static inline void EnterMemSection()
  43. {
  44. gmem_mutex.Enter();
  45. }
  46. static inline void LeaveMemSection()
  47. {
  48. gmem_mutex.Leave();
  49. }
  50. //+---------------------------------------------------------------------------
  51. //
  52. // Class: CPageHeader
  53. //
  54. // Purpose: Each page allocated has one of these objects at its start.
  55. // Pages aren't necessarily the system page size.
  56. //
  57. // History: 15-Mar-96 dlee Created.
  58. //
  59. //----------------------------------------------------------------------------
  60. class CPageHeader
  61. {
  62. public:
  63. void Init( ULONG cbChunk, UINT cbPage )
  64. {
  65. _cbChunk = (USHORT) cbChunk;
  66. _pcFreeList = 0;
  67. _cbFree = cbPage - sizeof CPageHeader;
  68. _cAlloced = 0;
  69. _pcEndPlusOne = ( (char *) this ) + cbPage;
  70. _pphPrev = 0;
  71. }
  72. #if CIDBG==1 || DBG==1
  73. void CheckFreeList() const
  74. {
  75. // validate the free list head; look for heap trashing
  76. ciAssert( _pcFreeList < _pcEndPlusOne );
  77. if ( 0 == _pcFreeList )
  78. return;
  79. UINT_PTR ulBase = (UINT_PTR) (this + 1);
  80. UINT_PTR ulFreeList = (UINT_PTR) _pcFreeList;
  81. ciAssert( ulFreeList >= ulBase );
  82. // freelist pointers are from the start of each chunk
  83. UINT_PTR ulDiff = ulFreeList - ulBase;
  84. ciAssert( 0 == ( ulDiff % _cbChunk ) );
  85. }
  86. #endif // CIDBG==1 || DBG==1
  87. void * FastAlloc()
  88. {
  89. // allocates memory from beyond the end of currently allocated space
  90. #if CIDBG==1 || DBG==1
  91. ciAssert(( _cbChunk <= cbMaxFalloc ));
  92. ciAssert(( _cbFree >= _cbChunk ));
  93. ciAssert(( _cAlloced < 65535 ));
  94. #endif // CIDBG==1 || DBG==1
  95. void *pv = _pcEndPlusOne - _cbFree;
  96. _cbFree -= _cbChunk;
  97. _cAlloced++;
  98. #if CIDBG==1 || DBG==1
  99. ciAssert( IsInPage( pv ) );
  100. RtlFillMemory( pv, _cbChunk, fillFastAlloc );
  101. #endif // CIDBG==1 || DBG==1
  102. return pv;
  103. }
  104. void * FreeListAlloc()
  105. {
  106. // allocates memory from the freelist
  107. #if CIDBG==1 || DBG==1
  108. ciAssert(( _cAlloced < 65535 )); // overflow?
  109. CheckFreeList();
  110. #endif // CIDBG==1 || DBG==1
  111. _cAlloced++;
  112. void *pv = _pcFreeList;
  113. _pcFreeList = * ( (char **) pv );
  114. #if CIDBG==1 || DBG==1
  115. ciAssert(( ( 0 == _pcFreeList ) ||
  116. ( _pcFreeList > (char *) this ) ));
  117. ciAssert( IsInPage( pv ) );
  118. CheckFreeList();
  119. RtlFillMemory( pv, _cbChunk, fillListAlloc );
  120. #endif // CIDBG==1 || DBG==1
  121. return pv;
  122. }
  123. void Free( void * pv )
  124. {
  125. #if CIDBG==1 || DBG==1
  126. ciAssert(( GetChunkSize() <= cbMaxFalloc ));
  127. ciAssert(( IsInPage( pv ) ));
  128. ciAssert( 0 != _cAlloced );
  129. CheckFreeList();
  130. #endif // CIDBG==1 || DBG==1
  131. // put the block at the front of the page's freelist
  132. ( * (char **) pv ) = _pcFreeList;
  133. _pcFreeList = (char *) pv;
  134. _cAlloced--;
  135. #if CIDBG==1 || DBG==1
  136. CheckFreeList();
  137. #endif // CIDBG==1 || DBG==1
  138. }
  139. BOOL IsValidPointer( const void * pv ) const
  140. {
  141. #if CIDBG==1 || DBG==1
  142. CheckFreeList();
  143. #endif // CIDBG==1 || DBG==1
  144. void * pvBase = (void *) (this + 1);
  145. UINT_PTR diff = (UINT_PTR) ( (char *) pv - (char *) pvBase );
  146. UINT_PTR mod = diff % _cbChunk;
  147. #if CIDBG==1 || DBG==1
  148. if ( 0 != mod )
  149. {
  150. falDebugOut(( DEB_WARN,
  151. "Invalid small pointer: 0x%x\n", pv ));
  152. ciAssert( !"Invalid small pointer" );
  153. }
  154. #endif // CIDBG==1 || DBG==1
  155. return ( 0 == mod );
  156. }
  157. BOOL IsInPage( void * pv )
  158. {
  159. return ( ( pv >= (char *) this ) &&
  160. ( pv < _pcEndPlusOne ) );
  161. }
  162. ULONG Size() { return (ULONG) ( _pcEndPlusOne - (char *) this ); }
  163. char * GetEndPlusOne() { return _pcEndPlusOne; }
  164. char * GetFreeList() { return _pcFreeList; }
  165. void SetNext( CPageHeader * p ) { _pphNext = p; }
  166. CPageHeader * Next() { return _pphNext; }
  167. void SetPrev( CPageHeader * p ) { _pphPrev = p; }
  168. CPageHeader * Prev() { return _pphPrev; }
  169. ULONG GetFreeSize() { return _cbFree; }
  170. ULONG GetAlloced() { return _cAlloced; }
  171. BOOL IsPageEmpty() { return 0 == _cAlloced; }
  172. ULONG GetChunkSize() { return _cbChunk; }
  173. private:
  174. char * _pcEndPlusOne; // one byte past the end of this page
  175. char * _pcFreeList; // first element in the free list
  176. CPageHeader * _pphNext; // next page of the same chunk size
  177. CPageHeader * _pphPrev; // previous page of the same chunk size
  178. ULONG _cbFree; // # bytes free and not in free list
  179. USHORT _cAlloced; // allows for maximum of 256k page size
  180. USHORT _cbChunk; // size of allocations in this page
  181. };
  182. #ifdef FALLOC_TRACK_NOTINPAGE
  183. LONG gmem_cbNotInPages = 0;
  184. LONG gmem_cbPeakNotInPages = 0;
  185. #endif //FALLOC_TRACK_NOTINPAGE
  186. // # of pages currently allocated
  187. UINT gmem_cPages = 0;
  188. // peak # of bytes allocated at once
  189. ULONG gmem_cbPeakUsage = 0;
  190. // current # of bytes allocated
  191. ULONG gmem_cbCurrentUsage = 0;
  192. // array of pointers to pages for each allocation size, the first of
  193. // which is the best place to look for an allocation.
  194. CPageHeader * gmem_aHints[ cbMaxFalloc / cbMemAlignment ];
  195. // array of all pages allocated, sorted by address
  196. CPageHeader * gmem_aPages[ cMaxPages ];
  197. //+---------------------------------------------------------------------------
  198. //
  199. // Function: SizeToHint
  200. //
  201. // Synopsis: Translates a memory allocation size to an index in the
  202. // hint array. If alignment is 8, any allocation of size 1
  203. // to 8 is in hint 0, size 9 to 16 is hint 1, etc.
  204. //
  205. // Arguments: [cb] -- size of the allocation
  206. //
  207. // Returns: The hint
  208. //
  209. // History: 15-Mar-96 dlee Created.
  210. //
  211. //----------------------------------------------------------------------------
  212. static inline ULONG SizeToHint( ULONG cb )
  213. {
  214. ciAssert(( cb <= cbMaxFalloc ));
  215. ciAssert(( cb >= cbMemAlignment ));
  216. return ( cb / cbMemAlignment ) - 1;
  217. } //SizeToHint
  218. //+---------------------------------------------------------------------------
  219. //
  220. // Function: ReallyAllocate
  221. //
  222. // Synopsis: Calls the real memory allocator.
  223. //
  224. // Arguments: [cb] -- size of the allocation
  225. //
  226. // Returns: The pointer or 0 on failure
  227. //
  228. // History: 15-Mar-96 dlee Created.
  229. //
  230. //----------------------------------------------------------------------------
  231. static inline void *ReallyAllocate( UINT cb )
  232. {
  233. return (void *) HeapAlloc( gmem_hHeap, 0, cb );
  234. } //ReallyAllocate
  235. //+---------------------------------------------------------------------------
  236. //
  237. // Function: ReallyFree
  238. //
  239. // Synopsis: Frees memory
  240. //
  241. // Arguments: [pv] -- pointer to free
  242. //
  243. // History: 15-Mar-96 dlee Created.
  244. //
  245. //----------------------------------------------------------------------------
  246. static inline void ReallyFree( void * pv )
  247. {
  248. #if CIDBG==1 || DBG==1
  249. if ( !HeapFree( gmem_hHeap, 0, pv ) )
  250. ciAssert(!"Bad ptr for operator delete => LocalFree");
  251. #else // CIDBG==1 || DBG==1
  252. HeapFree( gmem_hHeap, 0, pv );
  253. #endif // CIDBG==1 || DBG==1
  254. } //ReallyFree
  255. static inline BOOL ReallyIsValidPointer( const void * pv )
  256. {
  257. BOOL fOK = ( -1 != HeapSize( gmem_hHeap, 0, pv ) );
  258. #if CIDBG==1 || DBG==1
  259. if ( !fOK )
  260. ciAssert( !"Invalid Pointer Detected" );
  261. #endif // CIDBG==1 || DBG==1
  262. return fOK;
  263. } //ReallyIsValidPointer
  264. //+---------------------------------------------------------------------------
  265. //
  266. // Function: ReallyGetSize
  267. //
  268. // Synopsis: Returns the size of an allocation
  269. //
  270. // Arguments: [pv] -- pointer to allocated memory
  271. //
  272. // Returns: Size of the allocation
  273. //
  274. // History: 15-Mar-96 dlee Created.
  275. //
  276. //----------------------------------------------------------------------------
  277. static inline UINT ReallyGetSize( void const * pv )
  278. {
  279. return (UINT)HeapSize( gmem_hHeap, 0, pv );
  280. } //ReallyGetSize
  281. //+---------------------------------------------------------------------------
  282. //
  283. // Function: memFindPageIndex
  284. //
  285. // Synopsis: Finds the page in which a pointer might reside or where
  286. // a new page would be inserted.
  287. //
  288. // Arguments: [pv] -- pointer to use for the search
  289. //
  290. // Returns: The page number in which the page either resides or would
  291. // reside (if doing an insertion).
  292. //
  293. // History: 15-Mar-96 dlee Created.
  294. //
  295. //----------------------------------------------------------------------------
  296. inline ULONG memFindPageIndex( const void * pv )
  297. {
  298. ULONG cPages = gmem_cPages;
  299. ULONG iHi = cPages - 1;
  300. ULONG iLo = 0;
  301. // do a binary search looking for the page
  302. do
  303. {
  304. ULONG cHalf = cPages / 2;
  305. if ( 0 != cHalf )
  306. {
  307. ULONG cTmp = cHalf - 1 + ( cPages & 1 );
  308. ULONG iMid = iLo + cTmp;
  309. CPageHeader *page = gmem_aPages[ iMid ];
  310. if ( page > pv )
  311. {
  312. iHi = iMid - 1;
  313. cPages = cTmp;
  314. }
  315. else if ( page->GetEndPlusOne() <= pv )
  316. {
  317. iLo = iMid + 1;
  318. cPages = cHalf;
  319. }
  320. else
  321. {
  322. return iMid;
  323. }
  324. }
  325. else if ( 0 != cPages )
  326. {
  327. if ( ( gmem_aPages[ iLo ]->GetEndPlusOne() ) > pv )
  328. return iLo;
  329. else
  330. return iLo + 1;
  331. }
  332. else return iLo;
  333. }
  334. while ( TRUE );
  335. ciAssert(( ! "Invalid memFindPageIndex function exit point" ));
  336. return 0;
  337. } //memFindPageIndex
  338. //+---------------------------------------------------------------------------
  339. //
  340. // Function: AdjustPageSize
  341. //
  342. // Synopsis: Picks a page size for an allocation of a certain size base
  343. // on the allocation usage so far.
  344. //
  345. // Arguments: [cbAtLeast] -- the page must be at least this large.
  346. // [cbChunk] -- size of the allocation.
  347. //
  348. // Returns: The recommended page size for a new page of allocations of
  349. // size cbChunk.
  350. //
  351. // History: 15-Mar-96 dlee Created.
  352. //
  353. //----------------------------------------------------------------------------
  354. static inline ULONG AdjustPageSize(
  355. UINT cbAtLeast,
  356. USHORT cbChunk )
  357. {
  358. ciAssert(( cbChunk <= cbMaxFalloc ));
  359. UINT cPages = 0;
  360. CPageHeader * p = gmem_aHints[ SizeToHint( cbChunk ) ];
  361. while ( 0 != p )
  362. {
  363. cPages++;
  364. p = p->Next();
  365. }
  366. UINT cbPage;
  367. if ( 0 == cPages )
  368. cbPage = cbFirstPage;
  369. else if ( cPages < 4 )
  370. cbPage = 4096;
  371. else if ( cPages < 16 )
  372. cbPage = 8192;
  373. else if ( cPages < 200 )
  374. cbPage = 16384;
  375. else if ( cPages < 256 )
  376. cbPage = 32768;
  377. else
  378. cbPage = 65536;
  379. return __max( cbAtLeast, cbPage );
  380. } //AdjustPageSize
  381. //+---------------------------------------------------------------------------
  382. //
  383. // Function: memAddPage
  384. //
  385. // Synopsis: Allocates and adds a page to the list of pages
  386. //
  387. // Arguments: [cbPage] -- the page must be at least this large.
  388. // [cbChunk] -- size of each allocation in the page.
  389. //
  390. // Returns: pointer to the page
  391. //
  392. // History: 15-Mar-96 dlee Created.
  393. //
  394. //----------------------------------------------------------------------------
  395. CPageHeader * memAddPage(
  396. UINT cbPage,
  397. ULONG cbChunk )
  398. {
  399. ciAssert(( cbChunk <= cbMaxFalloc ));
  400. ciAssert(( gmem_cPages < cMaxPages ));
  401. // first-pass initializations for the allocator
  402. if ( 0 == gmem_cbPeakUsage )
  403. {
  404. RtlZeroMemory( gmem_aHints, sizeof gmem_aHints );
  405. RtlZeroMemory( gmem_aPages, sizeof gmem_aPages );
  406. }
  407. void * pvPage = ReallyAllocate( cbPage );
  408. // fail out-of-memory gracefully
  409. if ( 0 == pvPage )
  410. return 0;
  411. gmem_cbCurrentUsage += cbPage;
  412. gmem_cbPeakUsage = __max( gmem_cbPeakUsage, gmem_cbCurrentUsage );
  413. CPageHeader * page = (CPageHeader *) pvPage;
  414. ULONG iPage;
  415. if ( 0 == gmem_cPages )
  416. iPage = 0;
  417. else
  418. {
  419. iPage = memFindPageIndex( page );
  420. ciAssert(( iPage <= gmem_cPages ));
  421. // the pages are kept in order of address, so shift elements
  422. // down to make room if necessary.
  423. if ( iPage < gmem_cPages )
  424. RtlMoveMemory( & ( gmem_aPages[ iPage + 1 ] ),
  425. & ( gmem_aPages[ iPage ] ),
  426. ( sizeof(void *) ) * ( gmem_cPages - iPage ) );
  427. }
  428. // add the new page
  429. gmem_aPages[ iPage ] = page;
  430. gmem_cPages++;
  431. page->Init( cbChunk, cbPage );
  432. ULONG iHint = SizeToHint( cbChunk );
  433. CPageHeader *pOriginal = gmem_aHints[ iHint ];
  434. gmem_aHints[ iHint ] = page;
  435. page->SetNext( pOriginal );
  436. if ( 0 != pOriginal )
  437. pOriginal->SetPrev( page );
  438. #if CIDBG==1 || DBG==1
  439. // make sure the pages really are sorted
  440. if ( gmem_cPages >= 2 )
  441. for ( ULONG x = 0; x < gmem_cPages - 1; x++ )
  442. ciAssert(( gmem_aPages[ x ] < gmem_aPages[ x + 1 ] ));
  443. #endif // CIDBG==1 || DBG==1
  444. return page;
  445. } //memAddPage
  446. //+---------------------------------------------------------------------------
  447. //
  448. // Function: memDeletePage
  449. //
  450. // Synopsis: Deletes a page from the list of pages
  451. //
  452. // Arguments: [index] -- index of the page to be deleted.
  453. // [page] -- pointer to the page to be deleted.
  454. //
  455. // History: 15-Mar-96 dlee Created.
  456. //
  457. //----------------------------------------------------------------------------
  458. void memDeletePage(
  459. ULONG index,
  460. CPageHeader * page )
  461. {
  462. ciAssert(( index < gmem_cPages ));
  463. // leave the first page around -- it's small and cheap
  464. if ( page->Size() == cbFirstPage )
  465. return;
  466. // remove the page from the hint array
  467. ULONG iHint = SizeToHint( page->GetChunkSize() );
  468. if ( gmem_aHints[ iHint ] == page )
  469. {
  470. // it's the first element in the hint linked list
  471. gmem_aHints[ iHint ] = page->Next();
  472. if ( 0 != page->Next() )
  473. page->Next()->SetPrev( 0 );
  474. }
  475. else
  476. {
  477. // it's somewhere in the list of hints
  478. ciAssert(( 0 != page->Prev() ));
  479. page->Prev()->SetNext( page->Next() );
  480. if ( 0 != page->Next() )
  481. page->Next()->SetPrev( page->Prev() );
  482. }
  483. gmem_cPages--;
  484. if ( index < gmem_cPages )
  485. RtlMoveMemory( & ( gmem_aPages[ index ] ),
  486. & ( gmem_aPages[ index + 1 ] ),
  487. (sizeof( void * )) * ( gmem_cPages - index ) );
  488. gmem_cbCurrentUsage -= page->Size();
  489. #if CIDBG==1 || DBG==1
  490. // make sure the pages really are sorted
  491. if ( gmem_cPages >= 2 )
  492. for ( ULONG x = 0; x < gmem_cPages - 1; x++ )
  493. ciAssert(( gmem_aPages[ x ] < gmem_aPages[ x + 1 ] ));
  494. #endif // CIDBG==1 || DBG==1
  495. ReallyFree( page );
  496. } //memDeletePage
  497. //+---------------------------------------------------------------------------
  498. //
  499. // Function: memAlloc
  500. //
  501. // Synopsis: Allocates a piece of memory. This code should never raise
  502. // in any circumstance other than memory corruption.
  503. //
  504. // Arguments: [cbAlloc] -- # of bytes to allocate
  505. //
  506. // Returns: pointer to the memory or 0 if failed
  507. //
  508. // History: 15-Mar-96 dlee Created.
  509. //
  510. //----------------------------------------------------------------------------
  511. void * memAlloc( UINT cbAlloc)
  512. {
  513. // 0 sized allocations are ok in C++ and must return unique pointers
  514. // Align all allocations.
  515. // Do this work here, where it is not under lock
  516. if ( 0 != cbAlloc )
  517. cbAlloc = memAlignBlock( cbAlloc );
  518. else
  519. cbAlloc = cbMemAlignment;
  520. // can we special-case this allocation?
  521. if ( cbAlloc <= cbMaxFalloc )
  522. {
  523. // try the hint page first
  524. ULONG iHint = SizeToHint( cbAlloc );
  525. EnterMemSection();
  526. CPageHeader *page = gmem_aHints[ iHint ];
  527. if ( 0 != page )
  528. {
  529. // most typical case is re-use of memory
  530. if ( 0 != page->GetFreeList() )
  531. {
  532. void *pv = page->FreeListAlloc();
  533. LeaveMemSection();
  534. return pv;
  535. }
  536. // next most typical case is first-time allocation
  537. if ( cbAlloc <= page->GetFreeSize() )
  538. {
  539. void *pv = page->FastAlloc();
  540. LeaveMemSection();
  541. return pv;
  542. }
  543. // otherwise look for a page with a freelist entry
  544. page = page->Next();
  545. while ( 0 != page )
  546. {
  547. ciAssert(( cbAlloc == page->GetChunkSize() ));
  548. // if this weren't true, why isn't the page a hint?
  549. ciAssert(( cbAlloc > page->GetFreeSize() ));
  550. if ( 0 != page->GetFreeList() )
  551. {
  552. // try to make the hint be a page with free entries.
  553. // this is about a 5% speedup when a lot is allocated.
  554. CPageHeader *ptmp = gmem_aHints[ iHint ];
  555. if ( page != ptmp )
  556. {
  557. page->Prev()->SetNext( page->Next() );
  558. if ( 0 != page->Next() )
  559. page->Next()->SetPrev( page->Prev() );
  560. page->SetPrev( 0 );
  561. page->SetNext( ptmp );
  562. ptmp->SetPrev( page );
  563. gmem_aHints[ iHint ] = page;
  564. }
  565. void *pv = page->FreeListAlloc();
  566. LeaveMemSection();
  567. return pv;
  568. }
  569. page = page->Next();
  570. }
  571. }
  572. // New page is needed
  573. ciAssert(( 0 == page ));
  574. if ( gmem_cPages < cMaxPages )
  575. {
  576. page = memAddPage( AdjustPageSize( cbAlloc + sizeof CPageHeader,
  577. (USHORT)cbAlloc ),
  578. cbAlloc );
  579. void *pv = 0;
  580. if ( 0 != page )
  581. pv = page->FastAlloc();
  582. LeaveMemSection();
  583. return pv;
  584. }
  585. // wow. More than 150+ meg of allocations less than 256 bytes.
  586. // Just call the real allocator (after asserting)
  587. ciAssert(( !"bug? why did we allocate so much memory?" ));
  588. LeaveMemSection();
  589. }
  590. // just allocate a block and be done with it.
  591. void *pv = ReallyAllocate( cbAlloc );
  592. #ifdef FALLOC_TRACK_NOTINPAGE
  593. if ( 0 != pv )
  594. {
  595. InterlockedExchangeAdd( &gmem_cbNotInPages,
  596. (LONG) ReallyGetSize( pv ) );
  597. if ( gmem_cbNotInPages > gmem_cbPeakNotInPages )
  598. gmem_cbPeakNotInPages = gmem_cbNotInPages;
  599. }
  600. #endif //FALLOC_TRACK_NOTINPAGE
  601. #if CIDBG==1 || DBG==1
  602. if ( 0 != pv )
  603. RtlFillMemory( pv, cbAlloc, fillBigAlloc );
  604. #endif // CIDBG==1 || DBG==1
  605. return pv;
  606. } //memAlloc
  607. //+---------------------------------------------------------------------------
  608. //
  609. // Function: memFree
  610. //
  611. // Synopsis: Frees memory
  612. //
  613. // Arguments: [pv] -- pointer to free
  614. //
  615. // History: 15-Mar-96 dlee Created.
  616. //
  617. //----------------------------------------------------------------------------
  618. void memFree( void * pv )
  619. {
  620. // ciDelete does this check
  621. ciAssert( 0 != pv );
  622. {
  623. EnterMemSection();
  624. ULONG index = memFindPageIndex( pv );
  625. // The page is either in the array of tiny allocation pages
  626. // or not in the array and is a stand-alone allocation.
  627. if ( index < gmem_cPages )
  628. {
  629. CPageHeader * page = gmem_aPages[ index ];
  630. // metadata at head of page prevents this
  631. ciAssert(( pv != page ));
  632. // it's sufficient to check just the start of the page since if
  633. // pv were greater than the end of the page the next index
  634. // would have been returned from the memFindPageIndex() call
  635. if ( pv > page )
  636. {
  637. ciAssert(( pv >= ( (char *) page + ( sizeof CPageHeader ) ) ));
  638. ciAssert(( pv < page->GetEndPlusOne() ));
  639. #if CIDBG==1 || DBG==1
  640. RtlFillMemory( pv, page->GetChunkSize(), fillFree );
  641. #endif // CIDBG==1 || DBG==1
  642. page->Free( pv );
  643. if ( page->IsPageEmpty() )
  644. memDeletePage( index, page );
  645. LeaveMemSection();
  646. return;
  647. }
  648. }
  649. LeaveMemSection();
  650. }
  651. #ifdef FALLOC_TRACK_NOTINPAGE
  652. InterlockedExchangeAdd( &gmem_cbNotInPages,
  653. - (LONG) ReallyGetSize( pv ) );
  654. #endif //FALLOC_TRACK_NOTINPAGE
  655. #if CIDBG==1 || DBG==1
  656. ULONG cbBlock = ReallyGetSize( pv );
  657. RtlFillMemory( pv, cbBlock, fillBigFree );
  658. #endif // CIDBG==1 || DBG==1
  659. ReallyFree( pv );
  660. } //memFree
  661. //+---------------------------------------------------------------------------
  662. //
  663. // Function: memIsValidPointer
  664. //
  665. // Synopsis: Validates a pointer
  666. //
  667. // Arguments: [pv] -- pointer to validate
  668. //
  669. // Returns: TRUE if the pointer is apparently valid, FALSE otherwise
  670. //
  671. // History: 15-Oct-97 dlee Created.
  672. //
  673. //----------------------------------------------------------------------------
  674. BOOL memIsValidPointer( const void * pv )
  675. {
  676. if ( 0 == pv )
  677. return TRUE;
  678. {
  679. EnterMemSection();
  680. ULONG index = memFindPageIndex( pv );
  681. // The page is either in the array of tiny allocation pages
  682. // or not in the array and is a stand-alone allocation.
  683. if ( index < gmem_cPages )
  684. {
  685. CPageHeader * page = gmem_aPages[ index ];
  686. // metadata at head of page prevents this
  687. ciAssert(( pv != page ));
  688. // it's sufficient to check just the start of the page since if
  689. // pv were greater than the end of the page the next index
  690. // would have been returned from the memFindPageIndex() call
  691. if ( pv > page )
  692. {
  693. ciAssert(( pv >= ( (char *) page + ( sizeof CPageHeader ) ) ));
  694. ciAssert(( pv < page->GetEndPlusOne() ));
  695. BOOL fValid = page->IsValidPointer( pv );
  696. LeaveMemSection();
  697. return fValid;
  698. }
  699. }
  700. LeaveMemSection();
  701. }
  702. return ReallyIsValidPointer( pv );
  703. } //memIsValidPointer
  704. //+---------------------------------------------------------------------------
  705. //
  706. // Function: memSize
  707. //
  708. // Synopsis: Returns the size of an allocation
  709. //
  710. // Arguments: [pv] -- pointer to check
  711. //
  712. // Returns: Size in bytes of the allocation
  713. //
  714. // History: 25-Oct-98 dlee Created.
  715. //
  716. //----------------------------------------------------------------------------
  717. UINT memSize( const void * pv )
  718. {
  719. if ( 0 == pv )
  720. return 0;
  721. {
  722. EnterMemSection();
  723. ULONG index = memFindPageIndex( pv );
  724. // The page is either in the array of tiny allocation pages
  725. // or not in the array and is a stand-alone allocation.
  726. if ( index < gmem_cPages )
  727. {
  728. CPageHeader * page = gmem_aPages[ index ];
  729. // metadata at head of page prevents this
  730. ciAssert(( pv != page ));
  731. // it's sufficient to check just the start of the page since if
  732. // pv were greater than the end of the page the next index
  733. // would have been returned from the memFindPageIndex() call
  734. if ( pv > page )
  735. {
  736. ciAssert(( pv >= ( (char *) page + ( sizeof CPageHeader ) ) ));
  737. ciAssert(( pv < page->GetEndPlusOne() ));
  738. UINT cb = page->GetChunkSize();
  739. LeaveMemSection();
  740. return cb;
  741. }
  742. }
  743. LeaveMemSection();
  744. }
  745. return ReallyGetSize( pv );
  746. } //memSize
  747. #pragma optimize( "", on )
  748. void memUtilization()
  749. {
  750. #if CIDBG==1 || DBG==1
  751. EnterMemSection();
  752. #ifdef FALLOC_TRACK_NOTINPAGE
  753. falDebugOut(( DEB_WARN,
  754. "mem > 256 bytes 0x%x (%d), peak 0x%x (%d)\n",
  755. gmem_cbNotInPages,
  756. gmem_cbNotInPages,
  757. gmem_cbPeakNotInPages,
  758. gmem_cbPeakNotInPages ));
  759. #endif //FALLOC_TRACK_NOTINPAGE
  760. falDebugOut(( DEB_WARN,
  761. "mem <= 256 bytes 0x%x (%d), peak 0x%x (%d)\n",
  762. gmem_cbCurrentUsage,
  763. gmem_cbCurrentUsage,
  764. gmem_cbPeakUsage,
  765. gmem_cbPeakUsage ));
  766. ULONG cbTotalSize = 0;
  767. ULONG cbTotalInUse = 0;
  768. for ( ULONG i = 0; i < gmem_cPages; i++ )
  769. {
  770. CPageHeader *p = gmem_aPages[ i ];
  771. ULONG c = p->GetAlloced();
  772. c *= p->GetChunkSize();
  773. cbTotalInUse += c;
  774. cbTotalSize += p->Size();
  775. falDebugOut(( DEB_WARN,
  776. "p 0x%p cb %#x fl 0x%p f %#x a %#x s %#x u %#x\n",
  777. p,
  778. (ULONG) p->GetChunkSize(),
  779. (ULONG_PTR) p->GetFreeList(),
  780. (ULONG) p->GetFreeSize(),
  781. (ULONG) p->GetAlloced(),
  782. (ULONG) p->Size(),
  783. c ));
  784. }
  785. falDebugOut(( DEB_WARN, "total %#x (%d), in use: %#x (%d)\n",
  786. cbTotalSize, cbTotalSize,
  787. cbTotalInUse, cbTotalInUse ));
  788. LeaveMemSection();
  789. #endif // CIDBG==1 || DBG==1
  790. } //memUtilization