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.

1333 lines
41 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 2000
  5. //
  6. // File: tblalloc.cxx
  7. //
  8. // Contents: Memory allocation wrappers for large tables
  9. //
  10. // Classes: CWindowDataAllocator - data allocator for window var data
  11. // CFixedVarAllocator - data allocator for fixed and var data
  12. //
  13. // Functions: TblPageAlloc - Allocate page-alligned memory
  14. // TblPageRealloc - reallocate page-alligned memory to new size
  15. // TblPageDealloc - deallocate page-alligned memory
  16. //
  17. // History: 14 Mar 1994 AlanW Created
  18. //
  19. //--------------------------------------------------------------------------
  20. #include "pch.cxx"
  21. #pragma hdrstop
  22. #include <tblalloc.hxx>
  23. #include "tabledbg.hxx"
  24. //+-------------------------------------------------------------------------
  25. //
  26. // Function: TblPageAlloc, public
  27. //
  28. // Synopsis: Allocate page-alligned memory
  29. //
  30. // Effects: The memory allocation counter is incremented.
  31. // rcbSizeNeeded is adjusted on return to indicate the
  32. // size of the allocated memory.
  33. //
  34. // Arguments: [rcbSizeNeeded] - required size of memory area
  35. // [rcbPageAllocTracker] - memory allocation counter
  36. // [ulSig] - signature of the memory (optional)
  37. //
  38. // Returns: PVOID - pointer to the allocated memory. Throws
  39. // E_OUTOFMEMORY on allocation failure.
  40. //
  41. // Notes: rcbSizeNeeded is set to the minimum required size
  42. // needed. TblPageGrowSize can be called to grow an
  43. // existing memory region.
  44. //
  45. // If ulSig is non-zero, the beginning of the allocated
  46. // block is initialized with a signature block which
  47. // identifies the caller, and which gives the size of the
  48. // memory block. In this case, the returned pointer is
  49. // advanced beyond the signature block.
  50. //
  51. //--------------------------------------------------------------------------
  52. PVOID TblPageAlloc(
  53. ULONG& rcbSizeNeeded,
  54. ULONG& rcbPageAllocTracker,
  55. ULONG const ulSig
  56. ) {
  57. ULONG cbSize = rcbSizeNeeded +
  58. (ulSig != 0) * sizeof (TBL_PAGE_SIGNATURE);
  59. BYTE* pbAlloc = 0;
  60. Win4Assert(cbSize && (cbSize & TBL_PAGE_MASK) == 0);
  61. if (cbSize == 0)
  62. cbSize++;
  63. if ((cbSize & TBL_PAGE_MASK) != 0) {
  64. cbSize = (cbSize + TBL_PAGE_MASK) & ~TBL_PAGE_MASK;
  65. }
  66. if (cbSize < TBL_PAGE_MAX_SEGMENT_SIZE)
  67. {
  68. pbAlloc = (BYTE *)VirtualAlloc( 0,
  69. TBL_PAGE_MAX_SEGMENT_SIZE,
  70. MEM_RESERVE,
  71. PAGE_READWRITE);
  72. if ( 0 == pbAlloc )
  73. THROW(CException(E_OUTOFMEMORY));
  74. pbAlloc = (BYTE *)VirtualAlloc( pbAlloc,
  75. cbSize,
  76. MEM_COMMIT,
  77. PAGE_READWRITE);
  78. }
  79. else
  80. {
  81. pbAlloc = (BYTE *)VirtualAlloc( 0,
  82. cbSize,
  83. MEM_COMMIT,
  84. PAGE_READWRITE);
  85. }
  86. if (pbAlloc == 0)
  87. THROW(CException(E_OUTOFMEMORY));
  88. Win4Assert( (((ULONG_PTR)pbAlloc) & TBL_PAGE_MASK) == 0 );
  89. rcbPageAllocTracker += cbSize;
  90. if (ulSig)
  91. {
  92. TBL_PAGE_SIGNATURE * pSigStruct = (TBL_PAGE_SIGNATURE *) pbAlloc;
  93. pSigStruct->ulSig = ulSig;
  94. pSigStruct->cbSize = cbSize;
  95. pSigStruct->pbAddr = pbAlloc;
  96. #if CIDBG
  97. PVOID CallersCaller;
  98. RtlGetCallersAddress(&pSigStruct->pCaller, &CallersCaller);
  99. #else
  100. pSigStruct->pCaller = 0;
  101. #endif // CIDBG
  102. pbAlloc = (BYTE *) ++pSigStruct;
  103. cbSize -= sizeof (TBL_PAGE_SIGNATURE);
  104. }
  105. rcbSizeNeeded = cbSize;
  106. return pbAlloc;
  107. }
  108. //+-------------------------------------------------------------------------
  109. //
  110. // Function: TblPageRealloc, public
  111. //
  112. // Synopsis: Re-allocate page-alligned memory
  113. //
  114. // Effects: The memory allocation counter is incremented.
  115. // Memory is committed or decommitted to the required size.
  116. //
  117. // Arguments: [rcbSizeNeeded] - required size of memory area
  118. // [rcbPageAllocTracker] - memory allocation counter
  119. // [cbNewSize] - required size of memory area
  120. // [cbOldSize] - current size of memory area
  121. //
  122. // Returns: PVOID - pointer to the allocated memory. Throws
  123. // E_OUTOFMEMORY on allocation failure.
  124. //
  125. // Notes: cbOldSize need not be supplied if the memory area
  126. // begins with a signature block. In this case, the
  127. // pbMem passed in should point to beyond the signature
  128. // block, and the cbNewSize should not include the size
  129. // of the signature block.
  130. //
  131. // Not available in Kernel. Although VirtualAlloc
  132. // functionality is not available in the kernel, we
  133. // could do a poor man's realloc by optimistically
  134. // assuming that a page allocation would be contiguous
  135. // with the existing page, then setting some mark in
  136. // the page header that multiple frees need to be done
  137. // on the segment.
  138. //
  139. //--------------------------------------------------------------------------
  140. PVOID TblPageRealloc(
  141. PVOID pbMem,
  142. ULONG& rcbPageAllocTracker,
  143. ULONG cbNewSize,
  144. ULONG cbOldSize
  145. ) {
  146. BYTE* pbAlloc = (BYTE *)pbMem;
  147. TBL_PAGE_SIGNATURE * pSigStruct = 0;
  148. ULONG cbPageOffset = (ULONG)(((ULONG_PTR)pbMem) & TBL_PAGE_MASK);
  149. Win4Assert(cbPageOffset == 0 ||
  150. cbPageOffset == sizeof (TBL_PAGE_SIGNATURE));
  151. if (cbPageOffset == sizeof (TBL_PAGE_SIGNATURE))
  152. {
  153. pSigStruct = (TBL_PAGE_SIGNATURE *)
  154. ((BYTE*)pbMem - sizeof (TBL_PAGE_SIGNATURE));
  155. Win4Assert (pSigStruct->ulSig != 0 &&
  156. pSigStruct->cbSize >= TBL_PAGE_ALLOC_MIN &&
  157. pSigStruct->pbAddr == (BYTE *)pSigStruct &&
  158. cbOldSize == 0);
  159. cbOldSize = pSigStruct->cbSize;
  160. Win4Assert(((cbNewSize + sizeof (TBL_PAGE_SIGNATURE)) & TBL_PAGE_MASK) ==
  161. 0);
  162. cbNewSize += sizeof (TBL_PAGE_SIGNATURE);
  163. pbAlloc -= sizeof (TBL_PAGE_SIGNATURE);
  164. }
  165. if (cbNewSize > cbOldSize)
  166. {
  167. if (0 == VirtualAlloc(pbAlloc + cbOldSize,
  168. cbNewSize - cbOldSize,
  169. MEM_COMMIT,
  170. PAGE_READWRITE))
  171. THROW(CException(E_OUTOFMEMORY));
  172. rcbPageAllocTracker += (cbNewSize - cbOldSize);
  173. }
  174. else
  175. {
  176. VirtualFree(pbAlloc + cbNewSize, cbOldSize-cbNewSize, MEM_DECOMMIT);
  177. rcbPageAllocTracker -= (cbOldSize - cbNewSize);
  178. }
  179. if (pSigStruct) {
  180. pSigStruct->cbSize = cbNewSize;
  181. pbAlloc += sizeof (TBL_PAGE_SIGNATURE);
  182. }
  183. return (PVOID)pbMem;
  184. }
  185. //+-------------------------------------------------------------------------
  186. //
  187. // Function: TblPageDealloc, public
  188. //
  189. // Synopsis: Deallocate page-alligned memory
  190. //
  191. // Effects: The memory allocation counter is decremented
  192. //
  193. // Arguments: [pbMem] - pointer to the memory to be deallocated
  194. // [rcbPageAllocTracker] - memory allocation counter
  195. // [cbSize] - optional size of memory segment
  196. //
  197. // Requires: memory to be deallocated must have previously been
  198. // allocated by TblPageAlloc.
  199. //
  200. // Returns: nothing
  201. //
  202. // Notes:
  203. //
  204. //--------------------------------------------------------------------------
  205. void TblPageDealloc(
  206. PVOID pbMem,
  207. ULONG& rcbPageAllocTracker,
  208. ULONG cbSize
  209. ) {
  210. ULONG cbPageOffset = (ULONG)(((ULONG_PTR)pbMem) & TBL_PAGE_MASK);
  211. Win4Assert(cbPageOffset == 0 ||
  212. cbPageOffset == sizeof (TBL_PAGE_SIGNATURE));
  213. if (cbPageOffset == sizeof (TBL_PAGE_SIGNATURE)) {
  214. TBL_PAGE_SIGNATURE * pSigStruct =
  215. (TBL_PAGE_SIGNATURE *) ((BYTE*)pbMem - sizeof (TBL_PAGE_SIGNATURE));
  216. Win4Assert (pSigStruct->ulSig != 0 &&
  217. pSigStruct->cbSize >= TBL_PAGE_ALLOC_MIN &&
  218. pSigStruct->pbAddr == (BYTE *)pSigStruct);
  219. cbSize = pSigStruct->cbSize;
  220. pbMem = (BYTE *)pSigStruct;
  221. } else {
  222. Win4Assert(cbSize != 0);
  223. }
  224. BOOL fOK = VirtualFree(pbMem, 0, MEM_RELEASE);
  225. Win4Assert( fOK && "virtual free failed!" );
  226. rcbPageAllocTracker -= cbSize;
  227. }
  228. //
  229. // Default memory tracking variable
  230. //
  231. ULONG CWindowDataAllocator::_cbPageTracker = 0;
  232. //+-------------------------------------------------------------------------
  233. //
  234. // Member: CWindowDataAllocator::~CWindowDataAllocator, public
  235. //
  236. // Synopsis: Destroys a window data allocator
  237. //
  238. // Notes:
  239. //
  240. //--------------------------------------------------------------------------
  241. CWindowDataAllocator::~CWindowDataAllocator ()
  242. {
  243. CSegmentHeader* pSegHdr = (CSegmentHeader*) _pBaseAddr;
  244. while (pSegHdr) {
  245. _pBaseAddr = pSegHdr->pNextSegment;
  246. TblPageDealloc(pSegHdr, *_pcbPageUsed);
  247. pSegHdr = _pBaseAddr;
  248. }
  249. }
  250. //+-------------------------------------------------------------------------
  251. //
  252. // Member: CWindowDataAllocator::_SetArena, private
  253. //
  254. // Synopsis: Creates the initial memory arena in a memory segment
  255. //
  256. // Arguments: [pBufBase] - start of memory area
  257. // [cbBuf] - total size of memory area
  258. // [pHeap] - optional pointer to previously set up heap
  259. // Assumed to be entirely within pBufBase.
  260. // [oBuf] - buffer offset assigned to segment
  261. //
  262. // Returns: nothing
  263. //
  264. // Notes:
  265. //
  266. //--------------------------------------------------------------------------
  267. void CWindowDataAllocator::_SetArena (PVOID pBufBase,
  268. size_t cbBuf,
  269. CHeapHeader* pHeap,
  270. ULONG oBuf
  271. ) {
  272. CSegmentHeader* pSegHdr = (CSegmentHeader*) pBufBase;
  273. Win4Assert(cbBuf > sizeof (CSegmentHeader) + sizeof (CHeapHeader));
  274. if (oBuf) {
  275. pSegHdr->oBaseOffset = oBuf;
  276. if (oBuf + cbBuf > _oNextOffset)
  277. _oNextOffset = oBuf + cbBuf;
  278. if (oBuf + TBL_PAGE_MAX_SEGMENT_SIZE > _oNextOffset)
  279. _oNextOffset = oBuf + TBL_PAGE_MAX_SEGMENT_SIZE;
  280. } else {
  281. //
  282. // Offset is not constrained to some previously used
  283. // value. For convenience, round up to make it easy
  284. // to add to page addresses.
  285. //
  286. _oNextOffset = (_oNextOffset + TBL_PAGE_MASK) &
  287. ~(TBL_PAGE_MASK);
  288. _oNextOffset |= (ULONG)((ULONG_PTR)pBufBase & (TBL_PAGE_MASK));
  289. pSegHdr->oBaseOffset = _oNextOffset;
  290. _oNextOffset += (cbBuf > TBL_PAGE_MAX_SEGMENT_SIZE) ?
  291. cbBuf : TBL_PAGE_MAX_SEGMENT_SIZE;
  292. }
  293. pSegHdr->cbSize = cbBuf;
  294. CHeapHeader* pFirstHeap = (CHeapHeader*) (pSegHdr+1);
  295. cbBuf -= sizeof (CSegmentHeader);
  296. Win4Assert((cbBuf & (sizeof (CHeapHeader) - 1)) == 0);
  297. if (pHeap) {
  298. Win4Assert((BYTE*)pHeap < ((BYTE*)pFirstHeap) + cbBuf &&
  299. (BYTE*)pHeap >= ((BYTE*)pFirstHeap) + 2*sizeof (CHeapHeader));
  300. Win4Assert(! pHeap->IsFree() && pHeap->IsFirst());
  301. cbBuf = (size_t)((BYTE*)pHeap - (BYTE*)pFirstHeap);
  302. pHeap->cbPrev = (USHORT)cbBuf;
  303. pFirstHeap->cbSize = cbBuf | CHeapHeader::HeapFree;
  304. pSegHdr->cbFree = cbBuf;
  305. while (! pHeap->IsLast()) {
  306. pHeap = pHeap->Next();
  307. if (pHeap->IsFree())
  308. pSegHdr->cbFree += pHeap->Size();
  309. }
  310. } else {
  311. pFirstHeap->cbSize = cbBuf | CHeapHeader::HeapFree|CHeapHeader::HeapEnd;
  312. pSegHdr->cbFree = cbBuf;
  313. }
  314. pFirstHeap->cbPrev = CHeapHeader::HeapEnd;
  315. //
  316. // Now insert this segment into the list of segments.
  317. //
  318. pSegHdr->pNextSegment = _pBaseAddr;
  319. _pBaseAddr = pSegHdr;
  320. }
  321. //+-------------------------------------------------------------------------
  322. //
  323. // Member: CWindowDataAllocator::Allocate, public
  324. //
  325. // Synopsis: Allocates a piece of data out of a memory heap
  326. //
  327. // Effects: updates _pBuf and _cbBuf
  328. //
  329. // Arguments: [cbNeeded] - number of byes of memory needed
  330. //
  331. // Returns: PVOID - a pointer to the allocated memory
  332. //
  333. // Signals: Throws E_OUTOFMEMORY if not enough memory is available.
  334. //
  335. // Notes: Allocated blocks must be less than 64Kb in size.
  336. // Allocated blocks may move in virtual memory (while
  337. // there are no outstanding pointers within them), but
  338. // the offset value saved for an item must always be valid.
  339. //
  340. // It is assumed that no locking need be done for multi-threaded
  341. // protection because higher-level callers will do their
  342. // own synchronization.
  343. //
  344. // TODO:
  345. // - Enforce memory allocation limit
  346. //
  347. // History:
  348. //
  349. //--------------------------------------------------------------------------
  350. PVOID CWindowDataAllocator::Allocate(
  351. ULONG cbNeeded
  352. ) {
  353. CSegmentHeader* pSegHdr = (CSegmentHeader*) _pBaseAddr;
  354. BYTE* pRetBuf = 0;
  355. CHeapHeader* pThisHeap;
  356. Win4Assert(cbNeeded < USHRT_MAX - 2*(sizeof (CHeapHeader)));
  357. // Reserve room for the header.
  358. cbNeeded += sizeof (CHeapHeader);
  359. // Only allocate on 8-byte boundaries
  360. cbNeeded = _RoundUpToChunk( cbNeeded, cbTblAllocAlignment );
  361. if (pSegHdr == 0)
  362. {
  363. ULONG cbSize = TblPageGrowSize(cbNeeded + sizeof (CSegmentHeader),
  364. TRUE);
  365. BYTE* pbNewData = (BYTE *)TblPageAlloc(cbSize,
  366. *_pcbPageUsed, TBL_SIG_VARDATA);
  367. tbDebugOut((DEB_TRACE,
  368. "First variable allocation segment,"
  369. " new segment = %08x, size = %06x\n",
  370. pbNewData, cbSize));
  371. Win4Assert(pbNewData != 0);
  372. _SetArena(pbNewData, cbSize);
  373. pSegHdr = _pBaseAddr;
  374. }
  375. do
  376. {
  377. //
  378. // If there's not enough free space in this segment, just
  379. // go on to the next one.
  380. //
  381. if (cbNeeded > pSegHdr->cbFree)
  382. continue;
  383. for (pThisHeap = (CHeapHeader*)(pSegHdr+1);
  384. pThisHeap;
  385. pThisHeap = pThisHeap->Next())
  386. {
  387. Win4Assert(pThisHeap->cbPrev != 0 &&
  388. pThisHeap->Size() < pSegHdr->cbSize &&
  389. (BYTE*)pThisHeap < ((BYTE*)pSegHdr) + pSegHdr->cbSize);
  390. if (pThisHeap->IsFree() && pThisHeap->Size() >= cbNeeded)
  391. {
  392. return _SplitHeap(pSegHdr, pThisHeap, cbNeeded);
  393. }
  394. }
  395. } while (pSegHdr = pSegHdr->pNextSegment);
  396. tbDebugOut((DEB_TRACE, "Need to grow available data for var allocation\n"));
  397. //
  398. // Not enough space in the set of currently allocated segments.
  399. // See if one can be grown to accomodate the new allocation.
  400. //
  401. for (pSegHdr = (CSegmentHeader*) _pBaseAddr;
  402. pSegHdr;
  403. pSegHdr = pSegHdr->pNextSegment)
  404. {
  405. if (cbNeeded >
  406. (TBL_PAGE_MAX_SEGMENT_SIZE -
  407. (pSegHdr->cbSize + sizeof (TBL_PAGE_SIGNATURE))))
  408. continue;
  409. ULONG cbNew = (cbNeeded + (TBL_PAGE_MASK)) & ~TBL_PAGE_MASK;
  410. Win4Assert(cbNew + pSegHdr->cbSize < 0xFFFF);
  411. tbDebugOut((DEB_TRACE,
  412. "Grow var allocation segment %x, new size %06x\n",
  413. pSegHdr, pSegHdr->cbSize + cbNew));
  414. TblPageRealloc(pSegHdr, *_pcbPageUsed, cbNew + pSegHdr->cbSize, 0);
  415. //
  416. // Now add the newly allocated data to the heap.
  417. //
  418. for (pThisHeap = (CHeapHeader*)(pSegHdr+1);
  419. !pThisHeap->IsLast();
  420. pThisHeap = pThisHeap->Next()) {
  421. }
  422. if (pThisHeap->IsFree())
  423. {
  424. //
  425. // Just add the size of the newly allocated data
  426. //
  427. pThisHeap->cbSize = (pThisHeap->Size() + (USHORT)cbNew) |
  428. CHeapHeader::HeapFree |
  429. CHeapHeader::HeapEnd;
  430. }
  431. else
  432. {
  433. //
  434. // Create a new arena header which is free and last
  435. //
  436. pThisHeap->cbSize &= ~CHeapHeader::HeapEnd;
  437. pThisHeap->Next()->cbSize = (USHORT)cbNew |
  438. CHeapHeader::HeapFree |
  439. CHeapHeader::HeapEnd;
  440. pThisHeap->Next()->cbPrev = pThisHeap->Size();
  441. pThisHeap = pThisHeap->Next();
  442. }
  443. pSegHdr->cbSize += cbNew;
  444. pSegHdr->cbFree += cbNew;
  445. return _SplitHeap(pSegHdr, pThisHeap, cbNeeded);
  446. }
  447. //
  448. // Not enough space in the available segments; allocate a new
  449. // segment and allocate from it.
  450. //
  451. {
  452. ULONG cbSize = TblPageGrowSize(cbNeeded + sizeof (CSegmentHeader),
  453. TRUE);
  454. BYTE* pbNewData = (BYTE *)TblPageAlloc(cbSize,
  455. *_pcbPageUsed, TBL_SIG_VARDATA);
  456. tbDebugOut((DEB_TRACE, "New variable allocation segment linked to %x,"
  457. " new segment = %08x, size = %06x\n",
  458. _pBaseAddr, pbNewData, cbSize));
  459. Win4Assert(pbNewData != 0);
  460. _SetArena(pbNewData, cbSize);
  461. pSegHdr = _pBaseAddr;
  462. pThisHeap = (CHeapHeader *)(pSegHdr+1);
  463. Win4Assert(pThisHeap->Size() >= cbNeeded && pThisHeap->IsFree());
  464. return _SplitHeap(pSegHdr, pThisHeap, cbNeeded);
  465. }
  466. return 0;
  467. }
  468. //+-------------------------------------------------------------------------
  469. //
  470. // Member: CWindowDataAllocator::_SplitHeap, private
  471. //
  472. // Synopsis: Allocates a piece of data out of a memory heap
  473. //
  474. // Arguments: [pSegHdr] - pointer to the memory segment header
  475. // [pThisHeap] - pointer to the arena header to be split
  476. // [cbNeeded] - count of bytes to be allocated
  477. //
  478. // Returns: PVOID - a pointer to the allocated memory
  479. //
  480. // Notes: The Heap pointer passed must have enough space
  481. // to accomodate the memory request.
  482. //
  483. // History:
  484. //
  485. //--------------------------------------------------------------------------
  486. PVOID CWindowDataAllocator::_SplitHeap(
  487. CSegmentHeader* pSegHdr,
  488. CHeapHeader* pThisHeap,
  489. size_t cbNeeded
  490. ) {
  491. CHeapHeader* pPrevHeap;
  492. Win4Assert(pThisHeap->IsFree() && pThisHeap->Size() >= cbNeeded);
  493. //
  494. // Found a suitable chunk of free memory. Carve off
  495. // a piece of memory to be returned; adjust the total
  496. // free size in the segment.
  497. //
  498. if (pThisHeap->Size() < cbNeeded + 2*sizeof (CHeapHeader)) {
  499. //
  500. // Not enough room to split the arena entry; just
  501. // return it all.
  502. //
  503. pSegHdr->cbFree -= pThisHeap->Size();
  504. pThisHeap->cbSize &= ~CHeapHeader::HeapFree;
  505. return pThisHeap+1;
  506. }
  507. //
  508. // Need to split the arena entry. We'll return the upper
  509. // portion as the allocated memory so the free memory
  510. // will be closer to the beginning of the arena.
  511. //
  512. pPrevHeap = pThisHeap;
  513. pThisHeap = (CHeapHeader*)(((BYTE*)pPrevHeap) +
  514. pPrevHeap->Size() - cbNeeded);
  515. pThisHeap->cbPrev = pPrevHeap->Size() - cbNeeded;
  516. pThisHeap->cbSize = (USHORT)cbNeeded;
  517. if (pPrevHeap->IsLast()) {
  518. pThisHeap->cbSize |= CHeapHeader::HeapEnd;
  519. } else {
  520. pPrevHeap->Next()->cbPrev = (USHORT)cbNeeded;
  521. }
  522. pPrevHeap->cbSize = (pPrevHeap->Size() - cbNeeded) |
  523. CHeapHeader::HeapFree;
  524. pSegHdr->cbFree -= pThisHeap->Size();
  525. return pThisHeap+1;
  526. }
  527. //+-------------------------------------------------------------------------
  528. //
  529. // Member: CWindowDataAllocator::Free, public
  530. //
  531. // Synopsis: Frees a previously allocated piece of data
  532. //
  533. // Arguments: [pMem] - pointer to the memory to be freed
  534. //
  535. // Returns: Nothing
  536. //
  537. // Notes: Coalesces freed block with previous and/or next if they
  538. // are freed.
  539. //
  540. // As with the alloc method, it is assumed that a higher-
  541. // level caller will have taken care of multi-threaded
  542. // synchronization.
  543. //
  544. // TODO: - check that freed block doesn't grow larger than
  545. // USHRT_MAX (if segment length is larger)
  546. // - Release freed memory if > 1 page at end of block
  547. // - Release freed mem if > 1 page at beginning or
  548. // middle of block and there's room for a page header
  549. // at beginning of next used block. (this may not
  550. // be worth doing due to additional complexity in
  551. // realloc case).
  552. //
  553. // History:
  554. //
  555. //--------------------------------------------------------------------------
  556. void CWindowDataAllocator::Free(
  557. PVOID pMem
  558. ) {
  559. Win4Assert( (((ULONG_PTR)pMem) & (sizeof (CHeapHeader) - 1)) == 0 );
  560. CHeapHeader* pHeader = ((CHeapHeader *) pMem) - 1;
  561. Win4Assert( pHeader->Size() >= (sizeof CHeapHeader)*2 &&
  562. !pHeader->IsFree());
  563. CHeapHeader* pPrev = pHeader;
  564. while (!pPrev->IsFirst()) {
  565. pPrev = pPrev->Prev();
  566. }
  567. CSegmentHeader* pSegHdr = ((CSegmentHeader*)pPrev) - 1;
  568. pSegHdr->cbFree += pHeader->Size();
  569. pHeader->cbSize |= CHeapHeader::HeapFree;
  570. //
  571. // Attempt to coalesce with next and previous blocks.
  572. //
  573. if (!(pHeader->IsLast() )) {
  574. CHeapHeader* pNext = pHeader->Next();
  575. if (pNext->IsFree()) {
  576. pHeader->cbSize = pHeader->Size();
  577. pHeader->cbSize += pNext->Size();
  578. pHeader->cbSize |= CHeapHeader::HeapFree;
  579. if (pNext->IsLast()) {
  580. pHeader->cbSize |= CHeapHeader::HeapEnd;
  581. } else {
  582. pNext = pHeader->Next();
  583. pNext->cbPrev = pHeader->Size();
  584. }
  585. }
  586. }
  587. if (!(pHeader->IsFirst() )) {
  588. CHeapHeader* pPrev = pHeader->Prev();
  589. if (pPrev->IsFree()) {
  590. pPrev->cbSize = pPrev->Size();
  591. pPrev->cbSize += pHeader->Size();
  592. pPrev->cbSize |= CHeapHeader::HeapFree;
  593. if (pHeader->IsLast()) {
  594. pPrev->cbSize |= CHeapHeader::HeapEnd;
  595. } else {
  596. pHeader = pPrev->Next();
  597. pHeader->cbPrev = pPrev->Size();
  598. }
  599. pHeader = pPrev;
  600. }
  601. }
  602. if (pHeader->IsFirst() && pHeader->IsLast()) {
  603. tbDebugOut((DEB_WARN, "Empty pool segment to be freed %x\n", pHeader));
  604. } else if (pHeader->Size() >= 2*TBL_PAGE_ALLOC_MIN) {
  605. tbDebugOut((DEB_WARN, "Pool page(s) can be deallocated,"
  606. " loc = %x, size = %x\n", pHeader, pHeader->Size()));
  607. }
  608. }
  609. //+-------------------------------------------------------------------------
  610. //
  611. // Member: CWindowDataAllocator::OffsetToPointer, public
  612. //
  613. // Synopsis: Convert a pointer offset to a pointer.
  614. //
  615. // Arguments: [oBuf] - buffer offset to be mapped
  616. //
  617. // Returns: PVOID - a pointer to the data buffer
  618. //
  619. // Notes:
  620. //
  621. //--------------------------------------------------------------------------
  622. PVOID CWindowDataAllocator::OffsetToPointer(
  623. TBL_OFF oBuf
  624. ) {
  625. CSegmentHeader* pSegHdr = _pBaseAddr;
  626. for (pSegHdr = _pBaseAddr; pSegHdr; pSegHdr = pSegHdr->pNextSegment) {
  627. if (oBuf < pSegHdr->oBaseOffset)
  628. continue;
  629. if ((ULONG_PTR)(oBuf - pSegHdr->oBaseOffset) < pSegHdr->cbSize) {
  630. return (oBuf - pSegHdr->oBaseOffset) + (BYTE *)pSegHdr;
  631. }
  632. }
  633. Win4Assert(! "CWindowDataAllocator::OffsetToPointer failed");
  634. return 0;
  635. }
  636. //+-------------------------------------------------------------------------
  637. //
  638. // Member: CWindowDataAllocator::PointerToOffset, public
  639. //
  640. // Synopsis: Convert a pointer to a pointer offset.
  641. //
  642. // Arguments: [pBuf] - buffer pointer to be mapped
  643. //
  644. // Returns: ULONG - a unique value for the buffer in the memory
  645. // arena
  646. //
  647. // Notes:
  648. //
  649. //--------------------------------------------------------------------------
  650. TBL_OFF CWindowDataAllocator::PointerToOffset(
  651. PVOID pBuf
  652. ) {
  653. CSegmentHeader* pSegHdr = _pBaseAddr;
  654. for (pSegHdr = _pBaseAddr; pSegHdr; pSegHdr = pSegHdr->pNextSegment) {
  655. if (pBuf < pSegHdr)
  656. continue;
  657. if ((TBL_OFF)((BYTE *)pBuf - (BYTE *)pSegHdr) < pSegHdr->cbSize) {
  658. return ((BYTE *)pBuf - (BYTE *)pSegHdr) + pSegHdr->oBaseOffset;
  659. }
  660. }
  661. Win4Assert(! "CWindowDataAllocator::PointerToOffset failed");
  662. return 0;
  663. }
  664. void CWindowDataAllocator::SetBase( BYTE* pbBase )
  665. {
  666. Win4Assert(! "CWindowDataAllocator::SetBase not supported");
  667. }
  668. #if CIDBG
  669. //+-------------------------------------------------------------------------
  670. //
  671. // Member: CWindowDataAllocator::WalkHeap, public
  672. //
  673. // Synopsis: Walks the memory arena, calling out to a caller-supplied
  674. // function for each memory area.
  675. //
  676. // Arguments: [pfnReport] - pointer to function for memory report
  677. //
  678. // Returns: Nothing
  679. //
  680. // Notes: For debugging support only.
  681. // The pfnReport is called with three parameters, giving the
  682. // memory address of the block, the size of the block, and the
  683. // free flag associated with the block. The block address and
  684. // size do not include the arena header.
  685. //
  686. // History:
  687. //
  688. //--------------------------------------------------------------------------
  689. void
  690. CWindowDataAllocator::WalkHeap(
  691. void (pfnReport)(PVOID pb, USHORT cb, USHORT fFree)
  692. ) {
  693. CSegmentHeader* pSegHdr = (CSegmentHeader*) _pBaseAddr;
  694. while (pSegHdr) {
  695. CHeapHeader *pPrevHeap = 0;
  696. CHeapHeader *pThisHeap;
  697. ULONG cbFree = 0;
  698. pThisHeap = (CHeapHeader*)(pSegHdr + 1);
  699. Win4Assert(pThisHeap->IsFirst());
  700. while ( TRUE ) {
  701. pfnReport(pThisHeap+1, pThisHeap->Size() - sizeof (CHeapHeader),
  702. (USHORT)pThisHeap->IsFree());
  703. if (pPrevHeap) {
  704. Win4Assert(pThisHeap->Prev() == pPrevHeap &&
  705. ! pThisHeap->IsFirst());
  706. }
  707. if (pThisHeap->IsFree())
  708. cbFree += pThisHeap->Size();
  709. if (pThisHeap->IsLast())
  710. break;
  711. pPrevHeap = pThisHeap;
  712. pThisHeap = pThisHeap->Next();
  713. }
  714. Win4Assert(cbFree == pSegHdr->cbFree);
  715. pSegHdr = pSegHdr->pNextSegment;
  716. }
  717. }
  718. #endif // CIDBG
  719. //+-------------------------------------------------------------------------
  720. //
  721. // Member: CFixedVarAllocator::~CFixedVarAllocator, public
  722. //
  723. // Synopsis: Destroys a window data allocator
  724. //
  725. // Notes:
  726. //
  727. //--------------------------------------------------------------------------
  728. CFixedVarAllocator::~CFixedVarAllocator ()
  729. {
  730. delete _VarAllocator;
  731. if (_pbBaseAddr)
  732. {
  733. if ( _fDidReInit )
  734. delete (BYTE *) _pbBaseAddr;
  735. else
  736. {
  737. TblPageDealloc( _pbBaseAddr,
  738. _cbPageUsed,
  739. 0 );
  740. Win4Assert( _cbPageUsed == 0 );
  741. }
  742. }
  743. }
  744. //+-------------------------------------------------------------------------
  745. //
  746. // Member: CFixedVarAllocator::Allocate, public
  747. //
  748. // Synopsis: Allocates a piece of variable data out of a memory buffer
  749. // Take it from the same buffer as the fixed data until there
  750. // is no more room available in the that buffer, then split
  751. // the fixed and variable portions and convert the variable
  752. // portion to a CVarDataAllocator which will handle subsequent
  753. // allocations.
  754. //
  755. // Effects: updates _cbBuf
  756. //
  757. // Arguments: [cbNeeded] - number of byes of memory needed
  758. //
  759. // Returns: PVOID - a pointer to the allocated memory
  760. //
  761. // Signals: Throws E_OUTOFMEMORY if not enough memory is available.
  762. //
  763. // Notes: Allocated blocks must be less than 64Kb in size.
  764. // Allocated blocks may move in virtual memory (while
  765. // there are no outstanding pointers within them), but
  766. // the offset value saved for an item must always be valid.
  767. //
  768. // It is assumed that a higher-level caller will take
  769. // care of any multi-thread synchronization issues.
  770. //
  771. // History: 22 Apr 1994 Alanw Created
  772. //
  773. //--------------------------------------------------------------------------
  774. PVOID CFixedVarAllocator::Allocate(
  775. ULONG cbNeeded
  776. ) {
  777. if ( 0 == _VarAllocator && !_fVarOffsets )
  778. {
  779. // Don't use offsets -- just pointers. Need an allocator from
  780. // which to allocate.
  781. _VarAllocator = new CWindowDataAllocator();
  782. }
  783. if (_VarAllocator)
  784. {
  785. Win4Assert( 0 != _VarAllocator );
  786. return _VarAllocator->Allocate(cbNeeded);
  787. }
  788. Win4Assert(cbNeeded <
  789. USHRT_MAX - 2*(sizeof (CWindowDataAllocator::CHeapHeader)));
  790. //
  791. // Only allocate on eight-byte boundaries
  792. //
  793. cbNeeded = (cbNeeded + (sizeof (CWindowDataAllocator::CHeapHeader)-1)) &
  794. ~(sizeof (CWindowDataAllocator::CHeapHeader) - 1);
  795. cbNeeded += sizeof (CWindowDataAllocator::CHeapHeader);
  796. if (_pbBaseAddr == 0)
  797. _GrowData(cbNeeded);
  798. size_t cbFree = FreeSpace();
  799. if (cbNeeded >= cbFree)
  800. {
  801. _SplitData(FALSE);
  802. Win4Assert(_VarAllocator != 0);
  803. return _VarAllocator->Allocate(cbNeeded -
  804. sizeof (CWindowDataAllocator::CHeapHeader));
  805. }
  806. //
  807. // Allocate the memory and prefix with a heap header so the
  808. // memory can be handed over to the Heap manager eventually.
  809. //
  810. CWindowDataAllocator::CHeapHeader* pThisHeap;
  811. CWindowDataAllocator::CHeapHeader* pPrevHeap;
  812. pThisHeap = (CWindowDataAllocator::CHeapHeader*)
  813. (_pbBaseAddr + _cbBuf - cbNeeded);
  814. pThisHeap->cbSize = (USHORT)cbNeeded;
  815. pThisHeap->cbPrev = CWindowDataAllocator::CHeapHeader::HeapEnd;
  816. if (_cbBuf != _cbTotal)
  817. {
  818. pPrevHeap = (CWindowDataAllocator::CHeapHeader *)(_pbBaseAddr+_cbBuf);
  819. pPrevHeap->cbPrev = ((USHORT)cbNeeded) |
  820. (pPrevHeap->cbPrev & (CWindowDataAllocator::CHeapHeader::HeapFree));
  821. }
  822. else
  823. {
  824. pThisHeap->cbSize |= CWindowDataAllocator::CHeapHeader::HeapEnd;
  825. }
  826. _cbBuf -= cbNeeded;
  827. Win4Assert(_cbBuf >= (unsigned)(_pbBuf - _pbBaseAddr));
  828. return (BYTE*)(pThisHeap + 1);
  829. }
  830. //+-------------------------------------------------------------------------
  831. //
  832. // Member: CFixedVarAllocator::Free, public
  833. //
  834. // Synopsis: Frees a previously allocated piece of data. Passed along
  835. // to the CVarDataAllocator if fixed and var data have been
  836. // split.
  837. //
  838. // Arguments: [pMem] - pointer to the memory to be freed
  839. //
  840. // Returns: Nothing
  841. //
  842. // Notes: Coalesces freed block with previous and/or next if they
  843. // are freed.
  844. //
  845. // It is assumed that a higher-level caller will take
  846. // care of any multi-thread synchronization issues.
  847. //
  848. // History:
  849. //
  850. //--------------------------------------------------------------------------
  851. void CFixedVarAllocator::Free(
  852. PVOID pMem
  853. ) {
  854. if (_VarAllocator) {
  855. _VarAllocator->Free(pMem);
  856. return;
  857. }
  858. Win4Assert( (((ULONG_PTR)pMem) & (sizeof (CWindowDataAllocator::CHeapHeader) - 1)) == 0 );
  859. CWindowDataAllocator::CHeapHeader* pHeader = ((CWindowDataAllocator::CHeapHeader *) pMem) - 1;
  860. Win4Assert( pHeader->Size() >= (sizeof CWindowDataAllocator::CHeapHeader)*2 &&
  861. !pHeader->IsFree());
  862. pHeader->cbSize |= CWindowDataAllocator::CHeapHeader::HeapFree;
  863. //
  864. // Attempt to coalesce with next and previous blocks.
  865. //
  866. if (!(pHeader->IsLast() )) {
  867. CWindowDataAllocator::CHeapHeader* pNext = pHeader->Next();
  868. if (pNext->IsFree()) {
  869. pHeader->cbSize = pHeader->Size();
  870. pHeader->cbSize += pNext->Size();
  871. pHeader->cbSize |= CWindowDataAllocator::CHeapHeader::HeapFree;
  872. if (pNext->IsLast()) {
  873. pHeader->cbSize |= CWindowDataAllocator::CHeapHeader::HeapEnd;
  874. } else {
  875. pNext = pHeader->Next();
  876. pNext->cbPrev = pHeader->Size();
  877. }
  878. }
  879. }
  880. if (!(pHeader->IsFirst() )) {
  881. CWindowDataAllocator::CHeapHeader* pPrev = pHeader->Prev();
  882. if (pPrev->IsFree()) {
  883. pPrev->cbSize = pPrev->Size();
  884. pPrev->cbSize += pHeader->Size();
  885. pPrev->cbSize |= CWindowDataAllocator::CHeapHeader::HeapFree;
  886. if (pHeader->IsLast()) {
  887. pPrev->cbSize |= CWindowDataAllocator::CHeapHeader::HeapEnd;
  888. } else {
  889. pHeader = pPrev->Next();
  890. pHeader->cbPrev = pPrev->Size();
  891. }
  892. pHeader = pPrev;
  893. }
  894. }
  895. if (pHeader->IsFirst()) {
  896. //
  897. // Free this memory for use by the fixed allocator
  898. //
  899. if (! pHeader->IsLast()) {
  900. pHeader->Next()->cbPrev =
  901. CWindowDataAllocator::CHeapHeader::HeapEnd;
  902. }
  903. _cbBuf += pHeader->Size();
  904. if (pHeader->IsLast()) {
  905. Win4Assert(_cbBuf == _cbTotal);
  906. }
  907. }
  908. }
  909. //+---------------------------------------------------------------------------
  910. //
  911. // Function: ResizeAndInitFixed
  912. //
  913. // Synopsis: Resizes the "Fixed Width" part of the buffer to hold atleast
  914. // as many as "cItems" entries.
  915. //
  916. // Arguments: [cbDataWidth] -- Width of the new fixed data.
  917. // [cItems] -- Starting number of items that will be added.
  918. //
  919. // History: 11-29-94 srikants Created
  920. //
  921. // Notes:
  922. //
  923. //----------------------------------------------------------------------------
  924. void CFixedVarAllocator::ResizeAndInitFixed( size_t cbDataWidth, ULONG cItems )
  925. {
  926. //
  927. // This method should be called only if the fixed portion is being
  928. // currently used.
  929. //
  930. Win4Assert( _cbTotal == _cbBuf );
  931. ULONG cbNewNeeded = (ULONG)(cbDataWidth * cItems + _cbReserved);
  932. //
  933. // Round up the size to be an integral number of "pages".
  934. //
  935. ULONG cbNewActual = TblPageGrowSize(cbNewNeeded, TRUE);
  936. _cbDataWidth = cbDataWidth;
  937. if ( cbNewActual == _cbBuf )
  938. {
  939. //
  940. // The old and new totals are the same. There is no need to do any
  941. // allocation. Just adjust the pointers and return.
  942. //
  943. _pbBuf = _pbBaseAddr+_cbReserved;
  944. return;
  945. }
  946. else
  947. {
  948. //
  949. // Reallocate the buffer to fit the new size.
  950. //
  951. BYTE* pbNewData;
  952. if (_pbBaseAddr && cbNewActual <= TBL_PAGE_MAX_SEGMENT_SIZE)
  953. {
  954. pbNewData = (BYTE *)TblPageRealloc(_pbBaseAddr, _cbPageUsed, cbNewActual, 0);
  955. }
  956. else
  957. {
  958. pbNewData = (BYTE *)TblPageAlloc( cbNewActual, _cbPageUsed, TBL_SIG_ROWDATA);
  959. }
  960. Win4Assert( cbNewActual > _cbReserved );
  961. if (_pbBaseAddr)
  962. {
  963. if ( _pbBaseAddr != pbNewData )
  964. {
  965. RtlCopyMemory( pbNewData, _pbBaseAddr, _cbReserved );
  966. TblPageDealloc(_pbBaseAddr, _cbPageUsed);
  967. }
  968. }
  969. else
  970. {
  971. if (_cbReserved)
  972. {
  973. RtlZeroMemory(pbNewData, _cbReserved);
  974. }
  975. }
  976. _pbBuf = pbNewData + _cbReserved;
  977. _pbBaseAddr = pbNewData;
  978. _cbTotal = _cbBuf = cbNewActual;
  979. _pbLastAddrPlusOne = _pbBaseAddr + _cbBuf;
  980. }
  981. }
  982. //+---------------------------------------------------------------------------
  983. //
  984. // Function: AllocMultipleFixed
  985. //
  986. // Synopsis: Allocates a buffer for the specified number of items
  987. // and returns its pointer.
  988. //
  989. // Arguments: [cItems] -- Number of "fixed width" items.
  990. //
  991. // Returns: A pointer to a buffer to hold the specified number of
  992. // "fixed width" items.
  993. //
  994. // History: 11-29-94 srikants Created
  995. //
  996. // Notes:
  997. //
  998. //----------------------------------------------------------------------------
  999. void * CFixedVarAllocator::AllocMultipleFixed( ULONG cItems )
  1000. {
  1001. ULONG cbNeeded = cItems * _cbDataWidth;
  1002. if ( cbNeeded > FreeSpace() )
  1003. {
  1004. if ( _cbTotal != _cbBuf )
  1005. _SplitData(TRUE);
  1006. }
  1007. BYTE * pRetBuf = 0;
  1008. //
  1009. // Need to grow the buffer to accommodate more fixed size allocations.
  1010. //
  1011. if ( cbNeeded > FreeSpace() )
  1012. {
  1013. Win4Assert( _cbTotal == _cbBuf );
  1014. _GrowData( cbNeeded );
  1015. }
  1016. if ( cbNeeded <= FreeSpace() )
  1017. {
  1018. pRetBuf = _pbBuf;
  1019. _pbBuf += cbNeeded;
  1020. }
  1021. return pRetBuf;
  1022. }
  1023. //+-------------------------------------------------------------------------
  1024. //
  1025. // Member: CFixedVarAllocator::_GrowData, private
  1026. //
  1027. // Synopsis: Grow the data area allocated to row data.
  1028. //
  1029. // Arguments: [cbNeeded] - number of bytes needed. If zero,
  1030. // assumed to be called for fixed allocation.
  1031. //
  1032. // Returns: Nothing
  1033. //
  1034. // Effects: _pbBaseAddr will be reallocated to a new size. Existing
  1035. // reserved and row data will be copied to the new location.
  1036. //
  1037. // Notes: _GrowData cannot be called if row data and variable data
  1038. // share the same buffer. Use _SplitData instead.
  1039. //
  1040. //--------------------------------------------------------------------------
  1041. void CFixedVarAllocator::_GrowData( size_t cbNeeded )
  1042. {
  1043. if (cbNeeded == 0)
  1044. cbNeeded = _cbDataWidth;
  1045. Win4Assert(!_pbBaseAddr || (_pbBuf - _pbBaseAddr) + cbNeeded >= _cbTotal);
  1046. Win4Assert(_cbBuf == _cbTotal); // can be no var data when growing
  1047. ULONG cbSize = TblPageGrowSize((ULONG)(_cbTotal + cbNeeded), TRUE);
  1048. BYTE* pbNewData;
  1049. if (_pbBaseAddr && cbSize <= TBL_PAGE_MAX_SEGMENT_SIZE)
  1050. {
  1051. pbNewData = (BYTE *)TblPageRealloc(_pbBaseAddr, _cbPageUsed, cbSize, 0);
  1052. }
  1053. else
  1054. {
  1055. pbNewData = (BYTE *)TblPageAlloc(cbSize, _cbPageUsed, TBL_SIG_ROWDATA);
  1056. }
  1057. Win4Assert(pbNewData != 0);
  1058. tbDebugOut((DEB_TRACE,
  1059. "Growing fixed data for allocation at %x, new size = %x, new data = %x\n",
  1060. _pbBaseAddr, cbSize, pbNewData));
  1061. if (_pbBaseAddr) {
  1062. Win4Assert(cbSize > _cbBuf);
  1063. if (_pbBaseAddr != pbNewData) {
  1064. memcpy(pbNewData, _pbBaseAddr, _cbBuf);
  1065. _pbBuf = (_pbBuf - _pbBaseAddr) + pbNewData;
  1066. TblPageDealloc(_pbBaseAddr, _cbPageUsed);
  1067. }
  1068. } else {
  1069. #if CIDBG == 1
  1070. BYTE *pByte = (BYTE *) pbNewData;
  1071. for ( unsigned i=0; i<_cbReserved; i++ )
  1072. Win4Assert( pByte[i] == 0 );
  1073. #endif
  1074. _pbBuf = pbNewData + _cbReserved;
  1075. }
  1076. _pbBaseAddr = pbNewData;
  1077. _cbTotal = _cbBuf = cbSize;
  1078. _pbLastAddrPlusOne = _pbBaseAddr + _cbBuf;
  1079. Win4Assert(_pbBaseAddr && (_pbBuf - _pbBaseAddr) + cbNeeded < _cbBuf);
  1080. }
  1081. //+-------------------------------------------------------------------------
  1082. //
  1083. // Member: CFixedVarAllocator::_SplitData, private
  1084. //
  1085. // Synopsis: Split the joint allocation of row and variable data
  1086. //
  1087. // Arguments: [fMoveRowData] - if TRUE, the row data is moved; else
  1088. // the variable data is moved.
  1089. //
  1090. // Returns: Nothing
  1091. //
  1092. // Effects: _pbBaseAddr will be realloced to a new size. Existing
  1093. // row data will be copied to the new location. If a
  1094. // data buffer was previously shared between row data and
  1095. // variable data, it will be no longer.
  1096. //
  1097. // Notes:
  1098. //
  1099. //--------------------------------------------------------------------------
  1100. void
  1101. CFixedVarAllocator::_SplitData( BOOL fMoveRowData )
  1102. {
  1103. Win4Assert(_pbBaseAddr != 0 && _VarAllocator == 0);
  1104. ULONG cbSize = _cbTotal;
  1105. ULONG cbVarSize = (ULONG)(_cbTotal - _cbBuf);
  1106. BYTE* pbNewData = (BYTE *)TblPageAlloc(cbSize, _cbPageUsed,
  1107. fMoveRowData ? TBL_SIG_ROWDATA : TBL_SIG_VARDATA);
  1108. //
  1109. // BROKENCODE - shouldn't pbNewData be in a smart pointer. o/w, there
  1110. // could be a memory leak.
  1111. //
  1112. Win4Assert(pbNewData != 0);
  1113. Win4Assert(cbVarSize != 0 || fMoveRowData);
  1114. tbDebugOut((DEB_TRACE,
  1115. "Splitting fixed data for window from variable data\n"));
  1116. tbDebugOut((DEB_ITRACE,
  1117. "Current fixed size = %x, var size = %x, new %s data = %x\n",
  1118. _cbBuf, _cbTotal - _cbBuf,
  1119. fMoveRowData? "fixed":"var", pbNewData));
  1120. if (fMoveRowData)
  1121. {
  1122. RtlCopyMemory(pbNewData, _pbBaseAddr, (_pbBuf - _pbBaseAddr));
  1123. CWindowDataAllocator* VarAllocator =
  1124. new CWindowDataAllocator (_pbBaseAddr, _cbTotal,
  1125. (CWindowDataAllocator::CHeapHeader*)(_pbBaseAddr + _cbBuf),
  1126. &_cbPageUsed);
  1127. _pbBuf = (_pbBuf - _pbBaseAddr) + pbNewData;
  1128. _pbBaseAddr = pbNewData;
  1129. _pbLastAddrPlusOne = _pbBaseAddr + _cbBuf;
  1130. _VarAllocator = VarAllocator;
  1131. }
  1132. else
  1133. {
  1134. CWindowDataAllocator::CHeapHeader* pHeap = 0;
  1135. if (cbVarSize)
  1136. {
  1137. RtlCopyMemory(pbNewData + _cbBuf, _pbBaseAddr + _cbBuf, _cbTotal - _cbBuf);
  1138. pHeap = (CWindowDataAllocator::CHeapHeader*)(pbNewData + _cbBuf);
  1139. }
  1140. CWindowDataAllocator* VarAllocator =
  1141. new CWindowDataAllocator (pbNewData, _cbTotal,
  1142. pHeap, &_cbPageUsed);
  1143. _VarAllocator = VarAllocator;
  1144. }
  1145. _cbBuf = _cbTotal;
  1146. }