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.

951 lines
30 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000.
  5. //
  6. // File: tblalloc.hxx
  7. //
  8. // Contents: Memory allocation wrappers for large tables
  9. //
  10. // Classes: PVarAllocator - protocol for variable data allocators
  11. // PFixedAllocator - protocol for fixed and variable alloctors
  12. // PFixedVarAllocator - protocol for fixed and variable alloctors
  13. // CVarBufferAllocator - simple allocation from a buffer
  14. // CFixedVarBufferAllocator - fixed/var allocation from a buffer
  15. // CWindowDataAllocator - data allocator for window var data
  16. // CFixedVarAllocator - data allocator for fixed and var pieces
  17. //
  18. // Functions: TblPageAlloc - Allocate page-alligned memory
  19. // TblPageRealloc - re-allocate page-alligned memory
  20. // TblPageDealloc - deallocate page-alligned memory
  21. // TblPageGrowSize - suggest a new size for page-alligned memory
  22. //
  23. // Notes: TODO - There is no means to limit growth of data segments.
  24. // How will memory allocation targets be maintained?
  25. // Does there need to be some means of signalling
  26. // between the memory allocators and their consumers?
  27. //
  28. // History: 14 Mar 1994 AlanW Created
  29. //
  30. //--------------------------------------------------------------------------
  31. #pragma once
  32. #ifdef DISPLAY_INCLUDES
  33. #pragma message( "#include <" __FILE__ ">..." )
  34. #endif
  35. #include <pmalloc.hxx>
  36. typedef ULONG_PTR TBL_OFF;
  37. //
  38. // Signature structure (for debugging primarily)
  39. //
  40. struct TBL_PAGE_SIGNATURE {
  41. ULONG ulSig;
  42. ULONG cbSize;
  43. PVOID pbAddr;
  44. PVOID pCaller; // pad to paragraph for convenience
  45. };
  46. //
  47. // Signature values; all start with the string 'tbl'
  48. //
  49. const ULONG TBL_SIG_COMPRESSED = 0x436c6274; // 'tblC'
  50. const ULONG TBL_SIG_ROWDATA = 0x526c6274; // 'tblR'
  51. const ULONG TBL_SIG_VARDATA = 0x566c6274; // 'tblV'
  52. const unsigned cbTblAllocAlignment = sizeof( double );
  53. inline DWORD _RoundUpToChunk( DWORD x, DWORD chunksize )
  54. { return (x + chunksize - 1) & ~(chunksize - 1); }
  55. //
  56. // Minimum size and incremental growth constants
  57. //
  58. const ULONG TBL_PAGE_ALLOC_MIN = 4096;
  59. const ULONG TBL_PAGE_MASK = (TBL_PAGE_ALLOC_MIN - 1);
  60. const ULONG TBL_PAGE_ALLOC_INCR = 32768;
  61. //
  62. // Maximum size of a growable data segment
  63. //
  64. const ULONG TBL_PAGE_MAX_SEGMENT_SIZE = 64 * 1024;
  65. //+-------------------------------------------------------------------------
  66. //
  67. // Function: TblPageAlloc, public
  68. //
  69. // Synopsis: Allocate page-alligned memory
  70. //
  71. // Effects: The memory allocation counter is incremented.
  72. // rcbSizeNeeded is adjusted on return to indicate the
  73. // size of the allocated memory.
  74. //
  75. // Arguments: [rcbSizeNeeded] - required size of memory area
  76. // [rcbPageAllocTracker] - memory allocation counter
  77. // [ulSig] - signature of the memory (optional)
  78. //
  79. // Returns: PVOID - pointer to the allocated memory. NULL if
  80. // allocation failure.
  81. //
  82. // Notes: rcbSizeNeeded is set to the minimum required size
  83. // needed. TblPageGrowSize can be called to suggest
  84. // a new size for an existing memory region.
  85. //
  86. // If ulSig is non-zero, the beginning of the allocated
  87. // block is initialized with a signature block which
  88. // identifies the caller, and which gives the size of the
  89. // memory block. In this case, the returned pointer is
  90. // advanced beyond the signature block.
  91. //
  92. //--------------------------------------------------------------------------
  93. PVOID TblPageAlloc(
  94. ULONG& rcbSizeNeeded,
  95. ULONG& rcbPageAllocTracker,
  96. ULONG const ulSig = 0
  97. );
  98. //+-------------------------------------------------------------------------
  99. //
  100. // Function: TblPageRealloc, public
  101. //
  102. // Synopsis: Re-allocate page-alligned memory
  103. //
  104. // Effects: The memory allocation counter is incremented.
  105. // Memory is committed or decommitted to the required size.
  106. //
  107. // Arguments: [rcbSizeNeeded] - required size of memory area
  108. // [rcbPageAllocTracker] - memory allocation counter
  109. // [cbNewSize] - required size of memory area
  110. // [cbOldSize] - current size of memory area
  111. //
  112. // Returns: PVOID - pointer to the allocated memory. NULL if
  113. // allocation failure.
  114. //
  115. // Notes: cbOldSize need not be supplied if the memory area
  116. // begins with a signature block. In this case, the
  117. // pbMem passed in should point to beyond the signature
  118. // block, and the cbNewSize should not include the size
  119. // of the signature block.
  120. //
  121. //--------------------------------------------------------------------------
  122. PVOID TblPageRealloc(
  123. PVOID pbMem,
  124. ULONG& rcbPageAllocTracker,
  125. ULONG cbNewSize,
  126. ULONG cbOldSize
  127. );
  128. //+-------------------------------------------------------------------------
  129. //
  130. // Function: TblPageDealloc, public
  131. //
  132. // Synopsis: Deallocate page-alligned memory
  133. //
  134. // Effects: The memory allocation counter is decremented
  135. //
  136. // Arguments: [pbMem] - pointer to the memory to be deallocated
  137. // [rcbPageAllocTracker] - memory allocation counter
  138. //
  139. // Requires: memory to be deallocated must have previously been
  140. // allocated by TblPageAlloc.
  141. //
  142. // Returns: nothing
  143. //
  144. // Notes:
  145. //
  146. //--------------------------------------------------------------------------
  147. void TblPageDealloc(
  148. PVOID pbMem,
  149. ULONG& rcbPageAllocTracker,
  150. ULONG cbSize = 0
  151. );
  152. //+-------------------------------------------------------------------------
  153. //
  154. // Function: TblPageGrowSize, inline
  155. //
  156. // Synopsis: Suggest a new size for memory growth
  157. //
  158. // Arguments: [cbCurrentSize] - current allocation size
  159. // [fSigned] - TRUE iff mem. block will include signature
  160. //
  161. // Returns: ULONG - size to be input to TblPageAlloc
  162. //
  163. // Notes:
  164. //
  165. //--------------------------------------------------------------------------
  166. inline ULONG TblPageGrowSize(
  167. ULONG cbCurrentSize,
  168. ULONG const fSigned = FALSE
  169. ) {
  170. if (cbCurrentSize == 0) {
  171. return (ULONG)(fSigned ? TBL_PAGE_ALLOC_MIN - sizeof (TBL_PAGE_SIGNATURE):
  172. TBL_PAGE_ALLOC_MIN);
  173. }
  174. ULONG cbSize = cbCurrentSize;
  175. if (fSigned) {
  176. cbSize += sizeof (TBL_PAGE_SIGNATURE);
  177. }
  178. if (cbSize < TBL_PAGE_ALLOC_INCR) {
  179. cbSize *= 2;
  180. } else {
  181. cbSize += TBL_PAGE_ALLOC_INCR;
  182. }
  183. // Round to page size
  184. cbSize = _RoundUpToChunk( cbSize, TBL_PAGE_ALLOC_MIN );
  185. if (fSigned)
  186. cbSize -= sizeof (TBL_PAGE_SIGNATURE);
  187. return cbSize;
  188. }
  189. //+-------------------------------------------------------------------------
  190. //
  191. // Class: PFixedAllocator
  192. //
  193. // Purpose: Base class for fixed data allocator
  194. //
  195. //--------------------------------------------------------------------------
  196. class PFixedAllocator
  197. {
  198. public:
  199. // Allocate a piece of fixed memory.
  200. virtual PVOID AllocFixed() = 0;
  201. // Return the size of the allocation unit
  202. virtual size_t FixedWidth() const = 0;
  203. // Return the base address of the reserved area
  204. virtual BYTE* BufferAddr() const = 0;
  205. // Return the size of the reserved area
  206. virtual size_t GetReservedSize() const = 0;
  207. virtual void ReInit( BOOL fVarOffsets,
  208. size_t cbReserved,
  209. void * pvBuf,
  210. ULONG cbBuf )
  211. { Win4Assert(!"Never called"); }
  212. };
  213. //+-------------------------------------------------------------------------
  214. //
  215. // Class: PFixedVarAllocator
  216. //
  217. // Purpose: Base class for fixed/variable data allocator
  218. //
  219. //--------------------------------------------------------------------------
  220. class PFixedVarAllocator: public PVarAllocator, public PFixedAllocator
  221. {
  222. };
  223. //+-------------------------------------------------------------------------
  224. //
  225. // Class: CVarBufferAllocator
  226. //
  227. // Purpose: Simple data allocator for byte buffer allocation.
  228. //
  229. // Notes: This allocator just carves pieces out of a data
  230. // buffer and hands them out.
  231. //
  232. //--------------------------------------------------------------------------
  233. class CVarBufferAllocator : public PVarAllocator {
  234. public:
  235. CVarBufferAllocator (PVOID pBuf,
  236. size_t cbBuf) :
  237. _pBuf( (BYTE *)pBuf),
  238. _pBaseAddr( (BYTE *)pBuf ),
  239. _cbBuf( cbBuf )
  240. {
  241. }
  242. // Allocate a piece of memory.
  243. PVOID Allocate(ULONG cbNeeded);
  244. // Free a previously allocated piece of memory (can't in a buffer).
  245. void Free(PVOID pMem) {
  246. return;
  247. }
  248. // Return whether OffsetToPointer has non-null effect
  249. BOOL IsBasedMemory(void) {
  250. return _pBaseAddr != 0;
  251. }
  252. // Convert a pointer offset to a pointer.
  253. PVOID OffsetToPointer(TBL_OFF oBuf) {
  254. return _pBaseAddr + oBuf;
  255. }
  256. // Convert a pointer to a pointer offset.
  257. TBL_OFF PointerToOffset(PVOID pBuf) {
  258. return (BYTE *)pBuf - _pBaseAddr;
  259. }
  260. // Set base address for OffsetToPointer and PointerToOffset
  261. void SetBase(BYTE* pbBase) {
  262. _pBaseAddr = pbBase;
  263. }
  264. protected:
  265. BYTE* _pBuf; // Buffer base
  266. BYTE* _pBaseAddr; // Bias for addresses
  267. size_t _cbBuf; // Available space in _pBuf
  268. };
  269. //+-------------------------------------------------------------------------
  270. //
  271. // Member: CVarBufferAllocator::Allocate, inline
  272. //
  273. // Synopsis: Allocates a piece of data out of a memory buffer
  274. //
  275. // Effects: updates _pBuf and _cbBuf
  276. //
  277. // Arguments: [cbNeeded] - number of byes of memory needed
  278. //
  279. // Returns: PVOID - a pointer to the allocated memory
  280. //
  281. // Signals: Throws E_OUTOFMEMORY if not enough memory is available.
  282. //
  283. // Notes:
  284. //
  285. //--------------------------------------------------------------------------
  286. inline PVOID CVarBufferAllocator::Allocate( ULONG cbNeeded )
  287. {
  288. BYTE* pRetBuf;
  289. if (cbNeeded <= _cbBuf)
  290. {
  291. pRetBuf = _pBuf;
  292. _pBuf += cbNeeded;
  293. _cbBuf -= cbNeeded;
  294. }
  295. else
  296. {
  297. QUIETTHROW( CException(E_OUTOFMEMORY) );
  298. }
  299. return pRetBuf;
  300. }
  301. //+-------------------------------------------------------------------------
  302. //
  303. // Class: CFixedVarBufferAllocator
  304. //
  305. // Purpose: fixed/var data allocator for byte buffer allocation.
  306. //
  307. // Notes: This allocator just carves pieces out of a data
  308. // buffer and hands them out. It supports both fixed
  309. // and variable data allocation, growing variable data
  310. // downward from the end of the buffer.
  311. //
  312. //--------------------------------------------------------------------------
  313. class CFixedVarBufferAllocator : public PFixedVarAllocator
  314. {
  315. public:
  316. CFixedVarBufferAllocator (PVOID pBuf,
  317. ULONG_PTR ulOffsetFixup,
  318. size_t cbBuf,
  319. size_t cbFixed,
  320. size_t cbReserved = 0) :
  321. _pBufferAddr( (BYTE *)pBuf ),
  322. _pBaseOffset( (BYTE *)pBuf ),
  323. _ulOffsetFixup( ulOffsetFixup ),
  324. _pFixedBuf( (BYTE *)pBuf + cbReserved),
  325. _pVarBuf( (BYTE *)pBuf + cbBuf),
  326. _cbReserved( cbReserved ),
  327. _cbFixed( cbFixed )
  328. {
  329. // make the variable allocations 8-byte aligned
  330. while ( ( (ULONG_PTR) _pVarBuf ) & ( cbTblAllocAlignment - 1 ) )
  331. _pVarBuf--;
  332. }
  333. // Allocate a piece of fixed memory.
  334. PVOID AllocFixed();
  335. // Allocate a piece of variable memory.
  336. PVOID Allocate(ULONG cbNeeded);
  337. // Free a previously allocated piece of memory (can't in a buffer).
  338. void Free(PVOID pMem) {}
  339. // Return whether OffsetToPointer has non-null effect
  340. BOOL IsBasedMemory(void) { return _pBaseOffset != 0; }
  341. // Convert a pointer offset to a pointer.
  342. PVOID OffsetToPointer(TBL_OFF oBuf) {
  343. return oBuf -
  344. _ulOffsetFixup +
  345. _pBaseOffset;
  346. }
  347. // Convert a pointer to a pointer offset.
  348. TBL_OFF PointerToOffset(PVOID pBuf) {
  349. return (BYTE *) pBuf -
  350. _pBaseOffset +
  351. _ulOffsetFixup;
  352. }
  353. // Set base address for OffsetToPointer and PointerToOffset
  354. void SetBase(BYTE* pbBase) { _pBaseOffset = pbBase; }
  355. // Return size of fixed data records
  356. size_t FixedWidth() const { return _cbFixed; }
  357. // Return the size of the reserved area
  358. size_t GetReservedSize() const { return _cbReserved; }
  359. // Return the base address of the reserved area
  360. BYTE* BufferAddr() const { return _pBufferAddr; }
  361. protected:
  362. size_t _FreeSpace() { return (size_t)(_pVarBuf - _pFixedBuf); }
  363. BYTE* _pBufferAddr; // Buffer base
  364. BYTE* _pBaseOffset; // Buffer base for offset calculations
  365. ULONG_PTR _ulOffsetFixup; // Client's version of the buffer base
  366. BYTE* _pFixedBuf; // Buffer pointer for next fixed alloc.
  367. BYTE* _pVarBuf; // Buffer pointer for next variable alloc.
  368. size_t _cbFixed; // Size of fixed allocations
  369. size_t _cbReserved; // Size of reserved area
  370. };
  371. //+-------------------------------------------------------------------------
  372. //
  373. // Member: CFixedVarBufferAllocator::AllocFixed, inline
  374. //
  375. // Synopsis: Allocates a piece of fixed data out of a memory buffer
  376. //
  377. // Effects: updates _pFixedBuf
  378. //
  379. // Arguments: [cbNeeded] - number of byes of memory needed
  380. //
  381. // Returns: PVOID - a pointer to the allocated memory
  382. //
  383. // Signals: Throws STATUS_BUFFER_TOO_SMALL if not enough memory
  384. // is available.
  385. //
  386. //--------------------------------------------------------------------------
  387. inline PVOID CFixedVarBufferAllocator::AllocFixed()
  388. {
  389. BYTE* pRetBuf = _pFixedBuf;
  390. if (_cbFixed <= _FreeSpace())
  391. _pFixedBuf += _cbFixed;
  392. else
  393. QUIETTHROW( CException( STATUS_BUFFER_TOO_SMALL ) );
  394. return pRetBuf;
  395. }
  396. //+-------------------------------------------------------------------------
  397. //
  398. // Member: CFixedVarBufferAllocator::Allocate, inline
  399. //
  400. // Synopsis: Allocates a piece of data out of a memory buffer
  401. //
  402. // Effects: updates _pVarBuf
  403. //
  404. // Arguments: [cbNeeded] - number of byes of memory needed
  405. //
  406. // Returns: PVOID - a pointer to the allocated memory
  407. //
  408. // Signals: Throws STATUS_BUFFER_TOO_SMALL if not enough memory
  409. // is available.
  410. //
  411. //--------------------------------------------------------------------------
  412. inline PVOID CFixedVarBufferAllocator::Allocate( ULONG cbNeeded )
  413. {
  414. // align to 8 byte boundry -- a little wasteful?
  415. cbNeeded = _RoundUpToChunk( cbNeeded, cbTblAllocAlignment );
  416. if (cbNeeded <= _FreeSpace())
  417. _pVarBuf -= cbNeeded;
  418. else
  419. QUIETTHROW( CException( STATUS_BUFFER_TOO_SMALL ) );
  420. return _pVarBuf;
  421. }
  422. //+-------------------------------------------------------------------------
  423. //
  424. // Class: CWindowDataAllocator
  425. //
  426. // Purpose: Data allocator for window variable data
  427. //
  428. // Interface: PVarAllocator
  429. //
  430. // Notes: This allocator manages a pool of pages as a simple
  431. // heap.
  432. //
  433. // Data allocated out of the variable data space will
  434. // be stored internally as offsets, so that the data may
  435. // be moved around without need for adjusting pointers.
  436. //
  437. //--------------------------------------------------------------------------
  438. class CWindowDataAllocator: public PVarAllocator
  439. {
  440. friend class CFixedVarAllocator; // for access to CHeapHeader
  441. //
  442. // Heap header used to record sizes of allocated and
  443. // freed memory.
  444. //
  445. struct CHeapHeader {
  446. USHORT cbSize; // size of this memory block
  447. USHORT cbPrev; // size of preceeding mem. block
  448. // the size of this struct needs to be 8-byte aligned.
  449. ULONG _dummy;
  450. // Flags or'ed with cbSize or cbPrev
  451. enum EHeapFlags {
  452. HeapFree = 1,
  453. HeapEnd = 2,
  454. HEAP_FLAGS = 3 // HeapFree | HeapEnd
  455. };
  456. USHORT Size(void) { return cbSize & ~HEAP_FLAGS; }
  457. BOOL IsFree(void) { return cbSize & HeapFree; }
  458. BOOL IsFirst(void) { return (cbPrev & HeapEnd) != 0; }
  459. BOOL IsLast(void) { return (cbSize & HeapEnd) != 0; }
  460. CHeapHeader* Next(void) { return IsLast() ? 0 :
  461. (CHeapHeader*) (((BYTE *) this) + Size());
  462. }
  463. CHeapHeader* Prev(void) { return IsFirst() ? 0 :
  464. (CHeapHeader*) (((BYTE *) this) -
  465. (cbPrev & ~HEAP_FLAGS));
  466. }
  467. };
  468. //
  469. // Header used on each segment of arena to link them together
  470. // and provide for offset mapping.
  471. //
  472. struct CSegmentHeader {
  473. CSegmentHeader* pNextSegment; // linked list to other segments
  474. ULONG oBaseOffset; // assigned offset for first memory
  475. ULONG cbSize;
  476. ULONG cbFree; // Free space in segment
  477. };
  478. public:
  479. CWindowDataAllocator (ULONG* pcbPageTracker = &_cbPageTracker) :
  480. _cbTotal( 0 ),
  481. _pBaseAddr( 0 ),
  482. _pcbPageUsed( pcbPageTracker ),
  483. _oNextOffset( sizeof (TBL_PAGE_SIGNATURE ))
  484. { }
  485. CWindowDataAllocator (PVOID pBuf,
  486. size_t cbBuf,
  487. CHeapHeader* pHeap = NULL,
  488. ULONG* pcbPageTracker = &_cbPageTracker
  489. ) :
  490. _cbTotal( 0 ),
  491. _pBaseAddr( 0 ),
  492. _pcbPageUsed( pcbPageTracker ),
  493. _oNextOffset( sizeof (TBL_PAGE_SIGNATURE )) {
  494. _SetArena(pBuf, cbBuf, pHeap, sizeof(TBL_PAGE_SIGNATURE));
  495. }
  496. ~CWindowDataAllocator();
  497. // Allocate a piece of memory.
  498. PVOID Allocate(ULONG cbNeeded);
  499. // Free a previously allocated piece of memory.
  500. void Free(PVOID pMem);
  501. // Return whether OffsetToPointer has non-null effect
  502. BOOL IsBasedMemory(void) {
  503. return TRUE;
  504. }
  505. // Convert a pointer offset to a pointer.
  506. PVOID OffsetToPointer(TBL_OFF oBuf);
  507. // Convert a pointer to a pointer offset.
  508. TBL_OFF PointerToOffset(PVOID pBuf);
  509. // Set base address for OffsetToPointer and PointerToOffset
  510. void SetBase(BYTE* pbBase);
  511. #if CIDBG
  512. void WalkHeap(void (pfnReport)(PVOID pb, USHORT cb, USHORT f));
  513. #endif
  514. private:
  515. // Set the limits of the allocation area.
  516. void _SetArena( PVOID pBufBase,
  517. size_t cbBuf,
  518. CHeapHeader* pHeap = NULL,
  519. ULONG oBuf = 0);
  520. PVOID _SplitHeap(CSegmentHeader* pSegHdr,
  521. CHeapHeader* pThisHeap,
  522. size_t cbNeeded);
  523. CSegmentHeader* _pBaseAddr; // pointer to first segment in arena
  524. ULONG _oNextOffset; // next offset value to be assigned
  525. size_t _cbTotal; // total size of allocation area
  526. ULONG* _pcbPageUsed; // page usage tracking variable
  527. static ULONG _cbPageTracker; // default page tracker
  528. };
  529. //+-------------------------------------------------------------------------
  530. //
  531. // Class: CFixedVarAllocator
  532. //
  533. // Purpose: The ultimate data allocator. Supports fixed and
  534. // variable memory allocations from the same segment.
  535. // Automatically grows both fixed and variable allocations
  536. // automatically.
  537. // When memory usage grows beyond 1 page, fixed and
  538. // variable allocations will be taken from separate
  539. // segments.
  540. //
  541. //--------------------------------------------------------------------------
  542. class CFixedVarAllocator: public PFixedVarAllocator
  543. {
  544. public:
  545. CFixedVarAllocator (BOOL fGrowInitially,
  546. BOOL fVarOffsets,
  547. size_t cbDataWidth,
  548. size_t cbReserved = 0) :
  549. _fVarOffsets( fVarOffsets ),
  550. _pbBaseAddr( NULL ),
  551. _pbLastAddrPlusOne( NULL ),
  552. _pbBuf( NULL ),
  553. _cbBuf( 0 ),
  554. _cbReserved( cbReserved ),
  555. _cbDataWidth( cbDataWidth ),
  556. _VarAllocator( NULL ),
  557. _cbPageUsed( 0 ),
  558. _cbTotal( 0 ),
  559. _fDidReInit( FALSE )
  560. {
  561. if ( fGrowInitially )
  562. _GrowData();
  563. }
  564. ~CFixedVarAllocator ( );
  565. void ReInit( BOOL fVarOffsets,
  566. size_t cbReserved,
  567. void * pvBuf,
  568. ULONG cbBuf )
  569. {
  570. Win4Assert( ! _fDidReInit );
  571. Win4Assert( 0 == _pbBaseAddr );
  572. Win4Assert( 0 == _VarAllocator );
  573. _cbPageUsed = cbBuf;
  574. _cbReserved = cbReserved;
  575. _fVarOffsets = fVarOffsets;
  576. _pbBaseAddr = (BYTE *) pvBuf;
  577. _pbLastAddrPlusOne = _pbBaseAddr + _cbBuf;
  578. _fDidReInit = TRUE;
  579. }
  580. // Allocate a piece of fixed memory.
  581. PVOID AllocFixed()
  582. {
  583. Win4Assert( ! _fDidReInit );
  584. BYTE* pRetBuf;
  585. if (_pbBaseAddr == NULL)
  586. _GrowData();
  587. if ( _cbDataWidth <= FreeSpace() )
  588. {
  589. pRetBuf = _pbBuf;
  590. _pbBuf += _cbDataWidth;
  591. return pRetBuf;
  592. }
  593. if (_cbDataWidth > FreeSpace() )
  594. {
  595. if (_cbTotal != _cbBuf)
  596. _SplitData(TRUE);
  597. else
  598. _GrowData();
  599. }
  600. if ( _cbDataWidth <= FreeSpace() )
  601. {
  602. pRetBuf = _pbBuf;
  603. _pbBuf += _cbDataWidth;
  604. }
  605. else
  606. {
  607. Win4Assert( !"unexpected out of memory" );
  608. }
  609. return pRetBuf;
  610. }
  611. // Return the size of the allocation unit
  612. size_t FixedWidth() const { return _cbDataWidth; }
  613. // Return the base address of the reserved area
  614. BYTE* BufferAddr() const { return _pbBaseAddr; }
  615. // Return the size of the reserved area
  616. size_t GetReservedSize() const { return _cbReserved; }
  617. // Convert an offset to a pointer
  618. BYTE* FixedPointer( TBL_OFF obData ) const { return _pbBaseAddr+obData; }
  619. // Convert an offset to a pointer
  620. TBL_OFF FixedOffset( BYTE* pbData ) const { return pbData - _pbBaseAddr; }
  621. // Return the base address of the allocation area
  622. BYTE* FirstRow() const { return _pbBaseAddr + _cbReserved; }
  623. // Set the size of the allocation unit
  624. VOID SetRowSize(size_t cbDataWidth) { _cbDataWidth = cbDataWidth; }
  625. // Set the size of the reserved area
  626. VOID SetReservedSize(size_t cbReserved)
  627. {
  628. _cbReserved = cbReserved;
  629. if (_pbBaseAddr == NULL)
  630. _pbBuf = _pbBaseAddr + cbReserved;
  631. }
  632. // Resize the fixed portion of the buffer
  633. void ResizeAndInitFixed( size_t cbDataWidth, ULONG cItems );
  634. // Get a buffer for the specified number of fixed size allocations
  635. void * AllocMultipleFixed( ULONG cItems );
  636. // Allocate a piece of variable memory.
  637. PVOID Allocate(ULONG cbNeeded);
  638. // Free a previously allocated piece of memory.
  639. void Free(PVOID pMem);
  640. // Return whether OffsetToPointer has non-null effect
  641. BOOL IsBasedMemory(void)
  642. {
  643. return _fVarOffsets;
  644. }
  645. // Set base address for OffsetToPointer and PointerToOffset
  646. void SetBase(BYTE* pbBase)
  647. {
  648. if (pbBase == 0)
  649. _fVarOffsets = FALSE;
  650. else
  651. Win4Assert( !"CFixedVarAllocator::SetBase not supported" );
  652. }
  653. // Convert a pointer offset to a pointer.
  654. PVOID OffsetToPointer(TBL_OFF oBuf)
  655. {
  656. if (_fVarOffsets)
  657. {
  658. if (_VarAllocator)
  659. return _VarAllocator->OffsetToPointer(oBuf);
  660. else if ( _fDidReInit )
  661. return _pbBaseAddr + oBuf;
  662. else
  663. return _pbBaseAddr + oBuf - sizeof (TBL_PAGE_SIGNATURE);
  664. }
  665. else
  666. {
  667. return (PVOID) oBuf;
  668. }
  669. }
  670. // Convert a pointer to a pointer offset. Bias it so the offset
  671. // adds easily with a page address.
  672. TBL_OFF PointerToOffset(PVOID pBuf)
  673. {
  674. if (_fVarOffsets)
  675. {
  676. if (_VarAllocator)
  677. return _VarAllocator->PointerToOffset(pBuf);
  678. else if ( _fDidReInit )
  679. return (BYTE *) pBuf - _pbBaseAddr;
  680. else
  681. return ((BYTE *)pBuf - _pbBaseAddr) + sizeof (TBL_PAGE_SIGNATURE);
  682. }
  683. else
  684. {
  685. return (TBL_OFF) pBuf;
  686. }
  687. }
  688. // Return free space in buffer
  689. size_t FreeSpace() const
  690. {
  691. return (_cbBuf - (UINT)(_pbBuf - _pbBaseAddr));
  692. }
  693. // Return total memory used
  694. ULONG MemUsed( void ) { return _cbPageUsed; }
  695. #if CIDBG
  696. CWindowDataAllocator* VarAllocator(void) { return _VarAllocator; }
  697. #endif
  698. #ifdef CIEXTMODE
  699. void CiExtDump(void *ciExtSelf);
  700. #endif
  701. protected:
  702. size_t _cbTotal; // Total allocated size of _pbBaseAddr
  703. ULONG _cbPageUsed; // Total memory used
  704. private:
  705. void _GrowData(size_t cbNeeded = 0);
  706. void _SplitData(BOOL fMoveFixedData);
  707. CWindowDataAllocator* _VarAllocator; // Var data allocator after split
  708. BOOL _fVarOffsets; // offsets != pointers for var allocations
  709. BOOL _fDidReInit; // hence the allocator is read-only and
  710. // has one buffer for fixed & variable data
  711. BYTE* _pbBaseAddr; // Bias for addresses
  712. BYTE* _pbLastAddrPlusOne; // First byte past allocated memory
  713. BYTE* _pbBuf; // Buffer base
  714. size_t _cbBuf; // Available space in _pbBaseAddr
  715. size_t _cbDataWidth; // Size of each allocated piece of memory
  716. size_t _cbReserved; // Size of reserved area
  717. };
  718. class CFixedVarTableWindowAllocator: public PFixedVarAllocator
  719. {
  720. enum { cbFixedIncrement = 4096, cbVariableIncrement = 8192 };
  721. public:
  722. CFixedVarTableWindowAllocator() :
  723. _cbFixedSize(0),
  724. _cbFixedUsed(0),
  725. _iCurVar(0),
  726. _cbVarUsed(0)
  727. {}
  728. ~CFixedVarTableWindowAllocator()
  729. {
  730. for ( unsigned i = 0; i < _aVariableBufs.Count(); i++ )
  731. delete _aVariableBufs[i];
  732. }
  733. PVOID AllocFixed()
  734. {
  735. Win4Assert( _cbFixedSize <= cbFixedIncrement );
  736. if ( ( _cbFixedSize + _cbFixedUsed ) > _aFixed.Count() )
  737. _aFixed.ReSize( _aFixed.Count() + cbFixedIncrement );
  738. void *pv = _aFixed.Get() + _cbFixedUsed;
  739. _cbFixedUsed += _cbFixedSize;
  740. return pv;
  741. }
  742. size_t FixedWidth() const { return _cbFixedSize; }
  743. BYTE * BufferAddr() const { return _aFixed.Get(); }
  744. size_t GetReservedSize() const { return 0; }
  745. void ReInit( BOOL fVarOffsets,
  746. size_t cbReserved,
  747. void * pvBuf,
  748. ULONG cbBuf ) { Win4Assert(!"Never called"); }
  749. PVOID Allocate(ULONG cbNeeded)
  750. {
  751. cbNeeded = _RoundUpToChunk( cbNeeded, sizeof( double ) );
  752. Win4Assert( cbNeeded <= cbVariableIncrement );
  753. if ( 0 == _aVariableBufs.Count() )
  754. {
  755. XArray<BYTE> xTmp( cbVariableIncrement );
  756. _aVariableBufs[0] = xTmp.Get();
  757. xTmp.Acquire();
  758. }
  759. else if ( ( cbNeeded + _cbVarUsed ) > cbVariableIncrement )
  760. {
  761. _iCurVar = _aVariableBufs.Count();
  762. XArray<BYTE> xTmp( cbVariableIncrement );
  763. _aVariableBufs[_aVariableBufs.Count()] = xTmp.Get();
  764. xTmp.Acquire();
  765. _cbVarUsed = 0;
  766. }
  767. void * pv = _aVariableBufs[_iCurVar] + _cbVarUsed;
  768. _cbVarUsed += cbNeeded;
  769. return pv;
  770. }
  771. void Free(PVOID pMem) { Win4Assert( !"not called" ); }
  772. BOOL IsBasedMemory(void) { return FALSE; }
  773. PVOID OffsetToPointer(TBL_OFF oBuf) { return (PVOID) oBuf; }
  774. TBL_OFF PointerToOffset(PVOID pBuf) { return (TBL_OFF) pBuf; }
  775. void SetBase(BYTE* pbBase) {}
  776. VOID SetRowSize(size_t cbDataWidth) { _cbFixedSize = cbDataWidth; }
  777. BYTE * FixedPointer( TBL_OFF obData ) { return _aFixed.Get()+obData; }
  778. TBL_OFF FixedOffset( BYTE* pbData ) { return pbData - _aFixed.Get(); }
  779. ULONG MemUsed()
  780. {
  781. return _cbFixedUsed + _aVariableBufs.Count() * cbVariableIncrement;
  782. }
  783. BYTE * FirstRow() const { return _aFixed.Get(); }
  784. private:
  785. size_t _cbFixedSize;
  786. size_t _cbFixedUsed;
  787. XArray<BYTE> _aFixed;
  788. unsigned _iCurVar;
  789. unsigned _cbVarUsed;
  790. CDynArrayInPlace<BYTE *> _aVariableBufs;
  791. };