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.

1283 lines
33 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1994.
  5. //
  6. // File: smalloc.cxx
  7. //
  8. // Contents: Shared memory heap implementation
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 29-Mar-94 PhilipLa Created
  15. // 05-Feb-95 KentCe Use Win95 Shared Heap.
  16. // 10-May-95 KentCe Defer Heap Destruction to the last
  17. // process detach.
  18. //
  19. //----------------------------------------------------------------------------
  20. #include <dfhead.cxx>
  21. #pragma hdrstop
  22. #include <smalloc.hxx>
  23. #include <dfdeb.hxx>
  24. #ifdef NEWPROPS
  25. #define FULLIMPL
  26. #endif
  27. //
  28. // Take advantage of unique Win95 support of a shared heap.
  29. //
  30. #if defined(_CHICAGO_)
  31. #define HEAP_SHARED 0x04000000 // Secret feature of Win95 only.
  32. //
  33. // Locate the following in a shared data segment.
  34. //
  35. #pragma data_seg(".sdata")
  36. HANDLE gs_hSharedHeap = NULL; // hSharedHeap Handle for Win95.
  37. DFLUID gs_dfluid = LUID_BASE; // shared docfile global LUID
  38. #pragma data_seg()
  39. #define PRINTSTATS
  40. #else // defined(_CHICAGO_)
  41. #ifdef MULTIHEAP
  42. DFLUID gs_dfluid = LUID_BASE; // task memory heap support
  43. INT gs_iSharedHeaps = 0;
  44. #endif
  45. #define DLL
  46. #define DEB_STATS 0x00010000
  47. #define DEB_PRINT 0x00020000
  48. #ifdef DLL
  49. #define PERCENT(a,b,c) (int)((((double)a + (double)b) / (double)c) * 100.0)
  50. #define PRINTSTATS \
  51. memDebugOut((DEB_STATS, \
  52. "Total size: %lu, Space: Free: %lu, Alloced: %lu"\
  53. " Blocks: Free: %lu, Alloced: %lu"\
  54. " Efficiency: %.2f%%\n",\
  55. _cbSize,\
  56. GetHeader()->_ulFreeBytes,\
  57. GetHeader()->_ulAllocedBytes,\
  58. GetHeader()->_ulFreeBlocks,\
  59. GetHeader()->GetAllocedBlocks(),\
  60. PERCENT(GetHeader()->_ulFreeBytes,\
  61. GetHeader()->_ulAllocedBytes, _cbSize)));
  62. #else
  63. #define PRINTSTATS \
  64. printf( \
  65. "Total size: %lu, Free space: %lu, Alloced space: %lu"\
  66. " Efficiency: %.2f%%\n",\
  67. _cbSize,\
  68. GetHeader()->_ulFreeBytes,\
  69. GetHeader()->_ulAllocedBytes,\
  70. ((double)(GetHeader()->_ulFreeBytes +\
  71. GetHeader()->_ulAllocedBytes) / \
  72. (double)_cbSize) * (double)100);
  73. #endif
  74. #if DBG == 1
  75. inline BOOL IsAligned(void *pv)
  76. {
  77. return !((ULONG_PTR)pv & 7);
  78. }
  79. #else
  80. #define IsAligned(x) TRUE
  81. #endif
  82. #define SHAREDMEMBASE NULL
  83. #endif // !defined(_CHICAGO_)
  84. //+---------------------------------------------------------------------------
  85. //
  86. // Member: CSmAllocator::Init, public
  87. //
  88. // Synopsis: Initialize heap for use
  89. //
  90. // Arguments: [pszName] -- Name of shared memory heap to use
  91. //
  92. // Returns: Appropriate status code
  93. //
  94. // History: 29-Mar-94 PhilipLa Created
  95. // 05-Feb-95 KentCe Use Win95 Shared Heap.
  96. //
  97. // Remarks: Review the class destructor if you change this code.
  98. //
  99. //----------------------------------------------------------------------------
  100. #if !defined(MULTIHEAP)
  101. SCODE CSmAllocator::Init(LPWSTR pszName)
  102. #else
  103. SCODE CSmAllocator::Init(ULONG ulHeapName, BOOL fUnmarshal)
  104. #endif
  105. {
  106. SCODE sc = S_OK;
  107. #if !defined(MULTIHEAP)
  108. // Initialize the mutex
  109. sc = _dmtx.Init(TEXT("DocfileAllocatorMutex"));
  110. if (FAILED(sc))
  111. {
  112. return sc;
  113. }
  114. sc = _dmtx.Take(DFM_TIMEOUT);
  115. if (FAILED(sc))
  116. {
  117. return sc;
  118. }
  119. #endif
  120. #if defined(_CHICAGO_)
  121. //
  122. // Create a new shared heap if this is the first time thru.
  123. //
  124. if (gs_hSharedHeap == NULL)
  125. {
  126. gs_hSharedHeap = HeapCreate(HEAP_SHARED, 0, 0);
  127. #if DBG == 1
  128. ModifyResLimit(DBRQ_HEAPS, 1);
  129. #endif
  130. }
  131. //
  132. // We keep a copy of the shared heap as a flag so the destructor logic
  133. // does the right thing.
  134. //
  135. //
  136. m_hSharedHeap = gs_hSharedHeap;
  137. #else
  138. CSharedMemoryBlock *psmb = NULL;
  139. #ifdef MULTIHEAP
  140. _cbSize = 0;
  141. if (!fUnmarshal && g_pteb == NtCurrentTeb()) // only for main thread
  142. {
  143. if (g_ulHeapName != 0) // the global shared memory block is active
  144. {
  145. _psmb = &g_smb; // needed for GetHeader
  146. _pbBase = (BYTE *)(_psmb->GetBase()); // needed for GetHeader
  147. if (_pbBase != NULL && GetHeader()->GetAllocedBlocks() == 0)
  148. { // its' empty reuse it
  149. psmb = _psmb;
  150. _ulHeapName = g_ulHeapName;
  151. memDebugOut ((DEB_ITRACE, "Out CSmAllocator::Init "
  152. " reuse %x\n", g_ulHeapName));
  153. return sc;
  154. }
  155. }
  156. else
  157. {
  158. psmb = _psmb = &g_smb; // initialize g_smb
  159. }
  160. }
  161. if (psmb == NULL)
  162. {
  163. psmb = _psmb = new CSharedMemoryBlock ();
  164. if (psmb == NULL)
  165. return STG_E_INSUFFICIENTMEMORY;
  166. }
  167. WCHAR pszName[DOCFILE_SM_NAMELEN];
  168. wsprintf(pszName, L"DfSharedHeap%X", ulHeapName);
  169. #else
  170. psmb = &_smb;
  171. #endif
  172. #if WIN32 == 100 || WIN32 > 200
  173. CGlobalSecurity gs;
  174. if (SUCCEEDED(sc = gs.Init(TRUE)))
  175. {
  176. #else
  177. LPSECURITY_ATTRIBUTES gs = NULL;
  178. #endif
  179. // the SMB needs a few bytes for its own header. If we request
  180. // a page sized allocation, those few header bytes will cause an
  181. // extra page to be allocated, so to prevent that we subtract off
  182. // the header space from our requests.
  183. sc = psmb->Init(pszName,
  184. DOCFILE_SM_SIZE - psmb->GetHdrSize(), // reserve size
  185. INITIALHEAPSIZE - psmb->GetHdrSize(), // commit size
  186. SHAREDMEMBASE, // base address
  187. (SECURITY_DESCRIPTOR *)gs, // security descriptor
  188. TRUE); // create if doesn't exist
  189. // Always pass in TRUE for "fOKToCreate", since passing FALSE
  190. // will open an existing mapping in read-only mode, but we need read-write
  191. #if WIN32 == 100 || WIN32 > 200
  192. }
  193. #endif
  194. if (SUCCEEDED(sc))
  195. {
  196. #if DBG == 1
  197. ModifyResLimit(DBRQ_HEAPS, 1);
  198. #endif
  199. _cbSize = psmb->GetSize();
  200. _pbBase = (BYTE *)(psmb->GetBase());
  201. #ifdef MULTIHEAP
  202. gs_iSharedHeaps++;
  203. _ulHeapName = ulHeapName;
  204. #endif
  205. if (psmb->Created())
  206. {
  207. if (fUnmarshal) // do not allow creates for unmarshals
  208. {
  209. Uninit();
  210. memErr (EH_Err, STG_E_INVALIDFUNCTION);
  211. }
  212. else
  213. {
  214. Reset();
  215. }
  216. }
  217. #ifdef MULTIHEAP
  218. if (psmb == &g_smb)
  219. g_ulHeapName = ulHeapName; // store global heap name
  220. #endif
  221. PRINTSTATS;
  222. }
  223. #endif
  224. #if defined(MULTIHEAP)
  225. memDebugOut ((DEB_ITRACE, "Out CSmAllocator::Init sc=%x %x\n",
  226. sc, ulHeapName));
  227. #else
  228. _dmtx.Release();
  229. memDebugOut ((DEB_ITRACE, "Out CSmAllocator::Init sc=%x\n",
  230. sc));
  231. #endif
  232. EH_Err:
  233. return sc;
  234. }
  235. //+---------------------------------------------------------------------------
  236. //
  237. // Member: CSmAllocator::QueryInterface, public
  238. //
  239. // Synopsis: Standard QI
  240. //
  241. // Arguments: [iid] - Interface ID
  242. // [ppvObj] - Object return
  243. //
  244. // Returns: Appropriate status code
  245. //
  246. // History: 29-Mar-94 PhilipLa Created
  247. //
  248. //----------------------------------------------------------------------------
  249. STDMETHODIMP CSmAllocator::QueryInterface(REFIID iid, void **ppvObj)
  250. {
  251. SCODE sc = S_OK;
  252. memDebugOut((DEB_ITRACE, "In CSmAllocator::QueryInterface:%p()\n", this));
  253. if (IsEqualIID(iid, IID_IMalloc) || IsEqualIID(iid, IID_IUnknown))
  254. {
  255. *ppvObj = (IMalloc *) this;
  256. CSmAllocator::AddRef();
  257. }
  258. else
  259. sc = E_NOINTERFACE;
  260. memDebugOut((DEB_ITRACE, "Out CSmAllocator::QueryInterface\n"));
  261. return sc;
  262. }
  263. //+---------------------------------------------------------------------------
  264. //
  265. // Member: CSmAllocator::AddRef, public
  266. //
  267. // Synopsis: Add reference
  268. //
  269. // History: 29-Mar-94 PhilipLa Created
  270. //
  271. //----------------------------------------------------------------------------
  272. STDMETHODIMP_(ULONG) CSmAllocator::AddRef(void)
  273. {
  274. #ifdef MULTIHEAP
  275. return ++_cRefs;
  276. #else
  277. return 1;
  278. #endif
  279. }
  280. //+---------------------------------------------------------------------------
  281. //
  282. // Member: CSmAllocator::Release, public
  283. //
  284. // Synopsis: Release
  285. //
  286. // History: 29-Mar-94 PhilipLa Created
  287. //
  288. //----------------------------------------------------------------------------
  289. STDMETHODIMP_(ULONG) CSmAllocator::Release(void)
  290. {
  291. #ifdef MULTIHEAP
  292. ULONG cRefs = --_cRefs;
  293. if (cRefs <= 0 && this != &g_ErrorSmAllocator)
  294. delete this;
  295. return cRefs;
  296. #else
  297. return 0;
  298. #endif
  299. }
  300. #if !defined(_CHICAGO_)
  301. //+---------------------------------------------------------------------------
  302. //
  303. // Member: CSmAllocator::FindBlock, private
  304. //
  305. // Synopsis: Find an appropriately sized block in the heap.
  306. //
  307. // Arguments: [cb] -- Size of block required
  308. //
  309. // Returns: Pointer to block, NULL on failure
  310. //
  311. // History: 29-Mar-94 PhilipLa Created
  312. //
  313. //----------------------------------------------------------------------------
  314. CBlockHeader * CSmAllocator::FindBlock(SIZE_T cb, CBlockHeader **ppbhPrev)
  315. {
  316. CBlockHeader *pbhCurrent = GetAddress(GetHeader()->GetFirstFree());
  317. *ppbhPrev = NULL;
  318. while (pbhCurrent != NULL)
  319. {
  320. memAssert(IsAligned(pbhCurrent));
  321. if ((pbhCurrent->GetSize() >= cb) && (pbhCurrent->IsFree()))
  322. {
  323. memAssert(pbhCurrent->GetSize() < _cbSize); //MULTIHEAP
  324. memAssert((BYTE *)pbhCurrent >= _pbBase &&
  325. (BYTE *)pbhCurrent < _pbBase + _cbSize); // MULTIHEAP
  326. break;
  327. }
  328. else
  329. {
  330. memAssert (pbhCurrent->GetNext() <= _cbSize); // MULITHEAP
  331. *ppbhPrev = pbhCurrent;
  332. pbhCurrent = GetAddress(pbhCurrent->GetNext());
  333. }
  334. }
  335. return pbhCurrent;
  336. }
  337. //+---------------------------------------------------------------------------
  338. //
  339. // Member: CSmAllocator::Reset, private
  340. //
  341. // Synopsis: Reset the heap to its original empty state.
  342. //
  343. // Returns: Appropriate status code
  344. //
  345. // History: 04-Apr-94 PhilipLa Created
  346. //
  347. // Notes:
  348. //
  349. //----------------------------------------------------------------------------
  350. inline SCODE CSmAllocator::Reset(void)
  351. {
  352. memDebugOut((DEB_ITRACE, "In CSmAllocator::Reset:%p()\n", this));
  353. CBlockHeader *pbh = (CBlockHeader *)
  354. (_pbBase + sizeof(CHeapHeader));
  355. memAssert(IsAligned(pbh));
  356. pbh->SetFree();
  357. pbh->SetSize(_cbSize - sizeof(CHeapHeader));
  358. pbh->SetNext(0);
  359. memAssert((BYTE *)pbh + pbh->GetSize() == _pbBase + _cbSize);
  360. GetHeader()->SetFirstFree(GetOffset(pbh));
  361. GetHeader()->SetCompacted();
  362. GetHeader()->ResetAllocedBlocks();
  363. GetHeader()->ResetLuid();
  364. #if DBG == 1
  365. GetHeader()->_ulAllocedBytes = 0;
  366. GetHeader()->_ulFreeBytes =
  367. pbh->GetSize() - sizeof(CBlockPreHeader);
  368. GetHeader()->_ulFreeBlocks = 1;
  369. #endif
  370. memDebugOut((DEB_ITRACE, "Out CSmAllocator::Reset\n"));
  371. return S_OK;
  372. }
  373. #endif // !defined(_CHICAGO_)
  374. //+---------------------------------------------------------------------------
  375. //
  376. // Member: CSmAllocator::Alloc, public
  377. //
  378. // Synopsis: Allocate memory
  379. //
  380. // Arguments: [cb] -- Number of bytes to allocate
  381. //
  382. // Returns: Pointer to block, NULL if failure
  383. //
  384. // History: 29-Mar-94 PhilipLa Created
  385. //
  386. //----------------------------------------------------------------------------
  387. STDMETHODIMP_(void *) CSmAllocator::Alloc (
  388. SIZE_T cb )
  389. {
  390. void *pv = NULL;
  391. #if DBG == 1
  392. SIZE_T cbSize = cb;
  393. #endif
  394. #if !defined(_CHICAGO_)
  395. CBlockHeader *pbh = NULL;
  396. CBlockHeader *pbhPrev = NULL;
  397. SCODE sc;
  398. #endif
  399. memDebugOut((DEB_ITRACE, "In CSmAllocator::Alloc:%p(%lu)\n", this, cb));
  400. #if defined(_CHICAGO_)
  401. pv = HeapAlloc(m_hSharedHeap, 0, cb);
  402. #else // !defined(_CHICAGO_)
  403. #if !defined(MULTIHEAP)
  404. CLockDfMutex lckdmtx(_dmtx);
  405. #endif
  406. #ifdef MULTIHEAP
  407. if (_pbBase == NULL)
  408. {
  409. memAssert (g_pTaskAllocator != NULL);
  410. return g_pTaskAllocator->Alloc (cb);
  411. }
  412. #endif
  413. Sync();
  414. //The block must be at least large enough to hold the standard
  415. // header (size and free bit) and a pointer to the next block.
  416. if (cb < sizeof(CBlockHeader) - sizeof(CBlockPreHeader))
  417. {
  418. cb = sizeof(CBlockHeader) - sizeof(CBlockPreHeader);
  419. }
  420. cb = cb + sizeof(CBlockPreHeader);
  421. //Make cb 8 byte aligned.
  422. if (cb & 7)
  423. {
  424. cb += (8 - (cb & 7));
  425. }
  426. memAssert((cb >= CBLOCKMIN) && "Undersized block requested.");
  427. pbh = FindBlock(cb, &pbhPrev);
  428. if (pbh == NULL)
  429. {
  430. if (!(GetHeader()->IsCompacted()))
  431. {
  432. //Do a heap merge and try to allocate again.
  433. CSmAllocator::HeapMinimize();
  434. pbh = FindBlock(cb, &pbhPrev);
  435. }
  436. if (pbh == NULL)
  437. {
  438. #ifdef MULTIHEAP
  439. CSharedMemoryBlock *psmb = _psmb;
  440. #else
  441. CSharedMemoryBlock *psmb = &_smb;
  442. #endif
  443. #if DBG == 1
  444. ULONG ulOldSize = psmb->GetSize();
  445. #endif
  446. sc = (ULONG)psmb->Commit(_cbSize + (ULONG)max(cb, MINHEAPGROWTH));
  447. if (SUCCEEDED(sc))
  448. {
  449. //Attach newly committed space to free list.
  450. CBlockHeader *pbhNew = (CBlockHeader *)
  451. (_pbBase + _cbSize);
  452. _cbSize = psmb->GetSize();
  453. memAssert((pbhPrev == NULL) || (pbhPrev->GetNext() == 0));
  454. memAssert(_cbSize > ulOldSize);
  455. if (pbhPrev != NULL)
  456. {
  457. pbhPrev->SetNext(GetOffset(pbhNew));
  458. }
  459. else
  460. {
  461. GetHeader()->SetFirstFree(GetOffset(pbhNew));
  462. }
  463. pbhNew->SetNext(0);
  464. pbhNew->SetSize(max(cb, MINHEAPGROWTH));
  465. pbhNew->SetFree();
  466. memAssert((BYTE *)pbhNew + pbhNew->GetSize() ==
  467. _pbBase + _cbSize);
  468. #if DBG == 1
  469. GetHeader()->_ulFreeBytes +=
  470. pbhNew->GetSize() - sizeof(CBlockPreHeader);
  471. GetHeader()->_ulFreeBlocks += 1;
  472. #endif
  473. pbh = pbhNew;
  474. }
  475. #if DBG == 1
  476. else
  477. {
  478. memDebugOut((DEB_ERROR, "Can't grow shared memory\n"));
  479. PrintAllocatedBlocks();
  480. }
  481. #endif
  482. }
  483. }
  484. if (pbh != NULL)
  485. {
  486. //Allocate the found block.
  487. if ((pbh->GetSize() > cb) &&
  488. (pbh->GetSize() - cb > CBLOCKMIN))
  489. {
  490. //Split an existing block. No free list update required.
  491. CBlockHeader *pbhNew =
  492. (CBlockHeader *)((BYTE *)pbh + (pbh->GetSize() - cb));
  493. pbhNew->SetSize(cb);
  494. pbhNew->ResetFree();
  495. pbhNew->SetNext(0);
  496. pbh->SetSize(pbh->GetSize() - cb);
  497. #if DBG == 1
  498. cbSize = cb;
  499. GetHeader()->_ulAllocedBytes += (cb - sizeof(CBlockPreHeader));
  500. //The number of available free bytes decreases by the number
  501. // of bytes allocated
  502. GetHeader()->_ulFreeBytes -= cb;
  503. #endif
  504. memAssert(IsAligned(pbhNew));
  505. memAssert(IsAligned(pbh));
  506. pbh = pbhNew;
  507. }
  508. else
  509. {
  510. //Use an entire block. Update free list appropriately.
  511. memAssert(IsAligned(pbh));
  512. pbh->ResetFree();
  513. if (pbhPrev != NULL)
  514. {
  515. pbhPrev->SetNext(pbh->GetNext());
  516. }
  517. else
  518. {
  519. GetHeader()->SetFirstFree(pbh->GetNext());
  520. }
  521. #if DBG == 1
  522. cbSize = pbh->GetSize() - sizeof(CBlockPreHeader);
  523. GetHeader()->_ulAllocedBytes += cbSize;
  524. GetHeader()->_ulFreeBytes -= cbSize;
  525. GetHeader()->_ulFreeBlocks--;
  526. #endif
  527. pbh->SetNext(0);
  528. }
  529. }
  530. if (pbh != NULL)
  531. {
  532. pv = (BYTE *)pbh + sizeof(CBlockPreHeader);
  533. GetHeader()->IncrementAllocedBlocks();
  534. }
  535. #endif // !defined(_CHICAGO_)
  536. memDebugOut((DEB_ITRACE, "Out CSmAllocator::Alloc=> %p\n", pv));
  537. #if !defined(_CHICAGO_)
  538. memAssert(IsAligned(pv));
  539. #endif // !defined(_CHICAGO_)
  540. PRINTSTATS;
  541. #if DBG == 1
  542. if (pv == NULL)
  543. {
  544. #if defined(_CHICAGO_)
  545. memDebugOut((DEB_ERROR,
  546. "Failed allocation of %lu bytes.\n",
  547. cb));
  548. #else // !defined(_CHICAGO_)
  549. memDebugOut((DEB_ERROR,
  550. "Failed allocation of %lu bytes. Heap size is %lu\n",
  551. cb,
  552. _cbSize));
  553. #endif // !defined(_CHICAGO_)
  554. }
  555. else
  556. {
  557. //Allocated some bytes. Record this for leak tracking.
  558. ModifyResLimit(DBRQ_MEMORY_ALLOCATED, (LONG)pbh->GetSize());
  559. }
  560. #endif
  561. return pv;
  562. }
  563. //+---------------------------------------------------------------------------
  564. //
  565. // Member: CSmAllocator::Realloc, public
  566. //
  567. // Synopsis: Resize the block given
  568. //
  569. // Arguments: [pv] -- Pointer to block to realloc
  570. // [cb] -- New size for block
  571. //
  572. // Returns: Pointer to new block, NULL if failure
  573. //
  574. // History: 29-Mar-94 PhilipLa Created
  575. //
  576. //----------------------------------------------------------------------------
  577. STDMETHODIMP_(void *) CSmAllocator::Realloc(
  578. void *pv,
  579. SIZE_T cb )
  580. {
  581. void *pvNew = NULL;
  582. #ifdef FULLIMPL
  583. memDebugOut((DEB_ITRACE, "In CSmAllocator::Realloc:%p()\n", this));
  584. #if defined(_CHICAGO_)
  585. pvNew = HeapReAlloc(m_hSharedHeap, 0, pv, cb);
  586. #else
  587. #if !defined(MULTIHEAP)
  588. CLockDfMutex lckdmtx(_dmtx);
  589. #endif
  590. #ifdef MULTIHEAP
  591. if (_pbBase == NULL)
  592. {
  593. memAssert (g_pTaskAllocator != NULL);
  594. return g_pTaskAllocator->Realloc (pv, cb);
  595. }
  596. #endif
  597. if ((pv != NULL) && (cb == 0))
  598. {
  599. CSmAllocator::Free(pv);
  600. return NULL;
  601. }
  602. pvNew = CSmAllocator::Alloc(cb);
  603. if (pvNew != NULL && pv != NULL)
  604. {
  605. //Copy contents
  606. memcpy(pvNew, pv, min(cb, CSmAllocator::GetSize(pv)));
  607. CSmAllocator::Free(pv);
  608. }
  609. #endif
  610. memDebugOut((DEB_ITRACE, "Out CSmAllocator::Realloc\n"));
  611. #endif
  612. PRINTSTATS;
  613. return pvNew;
  614. }
  615. //+---------------------------------------------------------------------------
  616. //
  617. // Member: CSmAllocator::DoFree, private
  618. //
  619. // Synopsis: Free a memory block
  620. //
  621. // Arguments: [pv] -- Pointer to block to free
  622. //
  623. // Returns: void
  624. //
  625. // History: 26-Jul-95 SusiA Created
  626. //
  627. //----------------------------------------------------------------------------
  628. inline void CSmAllocator::DoFree(void *pv)
  629. {
  630. #ifdef MULTIHEAP
  631. if (_pbBase == NULL)
  632. {
  633. memAssert (g_pTaskAllocator != NULL);
  634. g_pTaskAllocator->Free (pv);
  635. return;
  636. }
  637. #endif
  638. memDebugOut((DEB_ITRACE, "In CSmAllocator::DoFree:%p(%p)\n", this, pv));
  639. #if DBG == 1
  640. SSIZE_T cbSize = 0;
  641. #endif
  642. #if defined(_CHICAGO_)
  643. if (pv != NULL)
  644. {
  645. #if DBG == 1
  646. cbSize = HeapSize(m_hSharedHeap, 0, pv);
  647. #endif
  648. HeapFree(m_hSharedHeap, 0, pv);
  649. }
  650. #else
  651. Sync();
  652. if (pv != NULL)
  653. {
  654. CBlockHeader *pbh = (CBlockHeader *)
  655. ((BYTE *)pv - sizeof(CBlockPreHeader));
  656. #ifdef MULTIHEAP
  657. SIZE_T ulSize = pbh->GetSize(); // temporary to hold size for debug
  658. #if DBG == 1
  659. cbSize = ulSize;
  660. #endif
  661. #endif
  662. memAssert(IsAligned(pbh));
  663. memAssert((BYTE*)pbh >= _pbBase &&
  664. (BYTE*)pbh < _pbBase + _cbSize); // MULTIHEAP
  665. pbh->SetFree();
  666. pbh->SetNext(GetHeader()->GetFirstFree());
  667. GetHeader()->SetFirstFree(GetOffset(pbh));
  668. GetHeader()->ResetCompacted();
  669. if (GetHeader()->DecrementAllocedBlocks() == 0)
  670. {
  671. #ifdef MULTIHEAP
  672. Uninit();
  673. #else
  674. Reset();
  675. #endif
  676. }
  677. #if DBG == 1
  678. else
  679. {
  680. GetHeader()->_ulAllocedBytes -=
  681. (pbh->GetSize() - sizeof(CBlockPreHeader));
  682. memAssert (GetHeader()->_ulAllocedBytes <= _cbSize);
  683. GetHeader()->_ulFreeBytes +=
  684. (pbh->GetSize() - sizeof(CBlockPreHeader));
  685. GetHeader()->_ulFreeBlocks++;
  686. }
  687. #endif
  688. #ifdef MULTIHEAP
  689. memDebugOut((DEB_ITRACE, "Out CSmAllocator::DoFree. Freed %lu\n",
  690. ulSize)); // don't access shared memory
  691. #else
  692. memDebugOut((DEB_ITRACE, "Out CSmAllocator::DoFree. Freed %lu\n",
  693. pbh->GetSize()));
  694. #endif
  695. }
  696. #endif
  697. #if !defined(MULTIHEAP)
  698. // the shared heap may have been unmapped, mustn't read it now
  699. PRINTSTATS;
  700. #endif
  701. #if DBG == 1
  702. //Freed some bytes, so record that.
  703. ModifyResLimit(DBRQ_MEMORY_ALLOCATED, (LONG)-cbSize);
  704. #endif
  705. }
  706. //+---------------------------------------------------------------------------
  707. //
  708. // Member: CSmAllocator::Free, public
  709. //
  710. // Synopsis: Free a memory block
  711. //
  712. // Arguments: [pv] -- Pointer to block to free
  713. //
  714. // Returns: void
  715. //
  716. // History: 29-Mar-94 PhilipLa Created
  717. // 26-Jul-95 SusiA Moved bulk of work to DoFree to
  718. // share code between Free and
  719. // FreeNoMutex
  720. //
  721. //----------------------------------------------------------------------------
  722. STDMETHODIMP_(void) CSmAllocator::Free(void *pv)
  723. {
  724. memDebugOut((DEB_ITRACE, "In CSmAllocator::Free:%p(%p)\n", this, pv));
  725. #if !defined(_CHICAGO_)
  726. #if !defined(MULTIHEAP)
  727. CLockDfMutex lckdmtx(_dmtx);
  728. #endif
  729. #endif
  730. DoFree(pv);
  731. }
  732. //+---------------------------------------------------------------------------
  733. //
  734. // Member: CSmAllocator::FreeNoMutex, public
  735. //
  736. // Synopsis: Free a memory block without first aquiring the mutex.
  737. // This function is equivalent to Free above, except that is does
  738. // not attempt to first aquire the mutex. It should be used OLNY
  739. // when the calling function guarantees to already have the mutex.
  740. //
  741. //
  742. // Arguments: [pv] -- Pointer to block to free
  743. //
  744. // Returns: void
  745. //
  746. // History: 19-Jul-95 SusiA Created
  747. //
  748. //----------------------------------------------------------------------------
  749. void CSmAllocator::FreeNoMutex(void *pv)
  750. {
  751. memDebugOut((DEB_ITRACE, "In CSmAllocator::FreeNoMutex:%p(%p)\n", this, pv));
  752. #if !defined(_CHICAGO_)
  753. #if !defined(MULTIHEAP)
  754. //ensure we already have the mutex
  755. memAssert(_dmtx.HaveMutex());
  756. #endif
  757. #endif
  758. DoFree(pv);
  759. }
  760. //+---------------------------------------------------------------------------
  761. //
  762. // Member: CSmAllocator::GetSize, public
  763. //
  764. // Synopsis: Return the size of the given block
  765. //
  766. // Arguments: [pv] -- Block to get size of
  767. //
  768. // Returns: Size of block pointer to by pv
  769. //
  770. // History: 29-Mar-94 PhilipLa Created
  771. //
  772. //----------------------------------------------------------------------------
  773. STDMETHODIMP_(SIZE_T) CSmAllocator::GetSize(void * pv)
  774. {
  775. #if !defined(_CHICAGO_)
  776. #if !defined(MULTIHEAP)
  777. CLockDfMutex lckdmtx(_dmtx);
  778. #endif
  779. #endif
  780. #ifdef MULTIHEAP
  781. if (_pbBase == NULL)
  782. {
  783. memAssert (g_pTaskAllocator != NULL);
  784. return g_pTaskAllocator->GetSize (pv);
  785. }
  786. #endif
  787. Sync();
  788. SIZE_T ulSize = (SIZE_T)-1;
  789. #ifdef FULLIMPL
  790. memDebugOut((DEB_ITRACE, "In CSmAllocator::GetSize:%p()\n", this));
  791. if (pv != NULL)
  792. {
  793. #if defined(_CHICAGO_)
  794. ulSize = HeapSize(m_hSharedHeap, 0, pv);
  795. #else
  796. CBlockHeader *pbh;
  797. pbh = (CBlockHeader *)((BYTE *)pv - sizeof(CBlockPreHeader));
  798. ulSize = pbh->GetSize() - sizeof(CBlockPreHeader);
  799. #endif
  800. }
  801. memDebugOut((DEB_ITRACE, "Out CSmAllocator::GetSize\n"));
  802. #endif
  803. return ulSize;
  804. }
  805. //+---------------------------------------------------------------------------
  806. //
  807. // Member: CSmAllocator::DidAlloc, public
  808. //
  809. // Synopsis: Return '1' if this heap allocated pointer at pv
  810. //
  811. // Arguments: [pv] -- Pointer to block
  812. //
  813. // Returns: '1' == This heap allocated block.
  814. // '0' == This heap did not allocate block.
  815. // '-1' == Could not determine if this heap allocated block.
  816. //
  817. // History: 29-Mar-94 PhilipLa Created
  818. //
  819. //----------------------------------------------------------------------------
  820. STDMETHODIMP_(int) CSmAllocator::DidAlloc(void FAR * pv)
  821. {
  822. #ifdef MULTIHEAP
  823. if (_pbBase == NULL)
  824. {
  825. memAssert (g_pTaskAllocator != NULL);
  826. return g_pTaskAllocator->DidAlloc (pv);
  827. }
  828. #endif
  829. int i = -1;
  830. #ifdef FULLIMPL
  831. memDebugOut((DEB_ITRACE, "In CSmAllocator::DidAlloc:%p()\n", this));
  832. #if defined(_CHICAGO_)
  833. if (HeapValidate(m_hSharedHeap, 0, pv))
  834. {
  835. i = 1;
  836. }
  837. else
  838. {
  839. i = 0;
  840. }
  841. #else // !defined(_CHICAGO_)
  842. #if !defined(MULTIHEAP)
  843. CLockDfMutex lckdmtx(_dmtx);
  844. #endif
  845. i = ((BYTE *)pv >= _pbBase) && ((BYTE *)pv <= (_pbBase + _cbSize));
  846. #endif // !defined(_CHICAGO_)
  847. memDebugOut((DEB_ITRACE, "Out CSmAllocator::DidAlloc\n"));
  848. #endif
  849. return i;
  850. }
  851. //+---------------------------------------------------------------------------
  852. //
  853. // Member: CSmAllocator::HeapMinimize, public
  854. //
  855. // Synopsis: Minimize the heap
  856. //
  857. // Arguments: None.
  858. //
  859. // Returns: void.
  860. //
  861. // History: 29-Mar-94 PhilipLa Created
  862. //
  863. //----------------------------------------------------------------------------
  864. STDMETHODIMP_(void) CSmAllocator::HeapMinimize(void)
  865. {
  866. #if !defined(_CHICAGO_)
  867. #if !defined(MULTIHEAP)
  868. CLockDfMutex lckdmtx(_dmtx);
  869. #endif
  870. #endif
  871. #ifdef MULTIHEAP
  872. if (_pbBase == NULL)
  873. {
  874. memAssert (g_pTaskAllocator != NULL);
  875. g_pTaskAllocator->HeapMinimize ();
  876. return;
  877. }
  878. #endif
  879. memDebugOut((DEB_ITRACE, "In CSmAllocator::HeapMinimize:%p()\n", this));
  880. PRINTSTATS;
  881. #if defined(_CHICAGO_)
  882. HeapCompact(m_hSharedHeap, 0);
  883. #else // !defined(_CHICAGO_)
  884. CBlockHeader *pbhCurrent;
  885. CBlockHeader *pbhLast = NULL;
  886. BYTE *pbEnd = _pbBase + _cbSize;
  887. #if DBG == 1
  888. PrintFreeBlocks();
  889. GetHeader()->_ulAllocedBytes = 0;
  890. GetHeader()->_ulFreeBytes = 0;
  891. GetHeader()->_ulFreeBlocks = 0;
  892. #endif
  893. pbhCurrent = (CBlockHeader *)(_pbBase + sizeof(CHeapHeader));
  894. while ((BYTE *)pbhCurrent < pbEnd)
  895. {
  896. memAssert(IsAligned(pbhCurrent));
  897. memAssert((pbhCurrent->GetSize() != 0) &&
  898. "Zero size block found.");
  899. if (pbhCurrent->IsFree())
  900. {
  901. //Check last block. If adjacent, merge them. If not,
  902. // update pbhNext.
  903. if (pbhLast == NULL)
  904. {
  905. GetHeader()->SetFirstFree(GetOffset(pbhCurrent));
  906. #if DBG == 1
  907. GetHeader()->_ulFreeBlocks = 1;
  908. #endif
  909. }
  910. else
  911. {
  912. if (pbhLast->GetSize() + GetOffset(pbhLast) ==
  913. GetOffset(pbhCurrent))
  914. {
  915. //Merge the blocks.
  916. pbhLast->SetSize(pbhLast->GetSize() +
  917. pbhCurrent->GetSize());
  918. pbhCurrent = pbhLast;
  919. }
  920. else
  921. {
  922. #if DBG == 1
  923. GetHeader()->_ulFreeBytes +=
  924. (pbhLast->GetSize() - sizeof(CBlockPreHeader));
  925. GetHeader()->_ulFreeBlocks++;
  926. #endif
  927. pbhLast->SetNext(GetOffset(pbhCurrent));
  928. }
  929. }
  930. pbhLast = pbhCurrent;
  931. }
  932. #if DBG == 1
  933. else
  934. {
  935. GetHeader()->_ulAllocedBytes +=
  936. (pbhCurrent->GetSize() - sizeof(CBlockPreHeader));
  937. }
  938. #endif
  939. //Move to next block.
  940. pbhCurrent =
  941. (CBlockHeader *)((BYTE *)pbhCurrent + pbhCurrent->GetSize());
  942. }
  943. if (pbhLast != NULL)
  944. {
  945. #if DBG == 1
  946. GetHeader()->_ulFreeBytes +=
  947. (pbhLast->GetSize() - sizeof(CBlockPreHeader));
  948. #endif
  949. pbhLast->SetNext(0);
  950. }
  951. else
  952. {
  953. GetHeader()->SetFirstFree(0);
  954. }
  955. GetHeader()->SetCompacted();
  956. #if DBG == 1
  957. PrintFreeBlocks();
  958. #endif
  959. #endif // !defined(_CHICAGO_)
  960. memDebugOut((DEB_ITRACE, "Out CSmAllocator::HeapMinimize\n"));
  961. PRINTSTATS;
  962. }
  963. #if !defined(_CHICAGO_)
  964. #if DBG == 1
  965. //+---------------------------------------------------------------------------
  966. //
  967. // Member: CSmAllocator::PrintFreeBlocks, private
  968. //
  969. // Synopsis: Debug code to print sizes of free blocks
  970. //
  971. // History: 25-Apr-94 PhilipLa Created
  972. //
  973. //----------------------------------------------------------------------------
  974. void CSmAllocator::PrintFreeBlocks(void)
  975. {
  976. CBlockHeader *pbhCurrent = GetAddress(GetHeader()->GetFirstFree());
  977. memDebugOut((DEB_PRINT, "There are %lu total free blocks\n",
  978. GetHeader()->_ulFreeBlocks));
  979. while (pbhCurrent != NULL)
  980. {
  981. memDebugOut((DEB_PRINT, "Free block %p has size %lu\n", pbhCurrent,
  982. pbhCurrent->GetSize()));
  983. pbhCurrent = GetAddress(pbhCurrent->GetNext());
  984. }
  985. }
  986. #endif
  987. #ifdef MULTIHEAP
  988. #if DBG == 1
  989. //+---------------------------------------------------------------------------
  990. //
  991. // Member: CSmAllocator::PrintAllocatedBlocks, private
  992. //
  993. // Synopsis: Debug code to find allocated block(s) that leaked
  994. //
  995. // History: 25-Nov-95 HenryLee Created
  996. //
  997. //----------------------------------------------------------------------------
  998. void CSmAllocator::PrintAllocatedBlocks(void)
  999. {
  1000. CBlockHeader *pbhCurrent;
  1001. CBlockHeader *pbhLast = NULL;
  1002. BYTE *pbEnd = _pbBase + _cbSize;
  1003. ULONG *pul;
  1004. if (_psmb != NULL)
  1005. {
  1006. pbhCurrent = (CBlockHeader *)(_pbBase + sizeof(CHeapHeader));
  1007. while ((BYTE *)pbhCurrent < pbEnd)
  1008. {
  1009. memAssert(IsAligned(pbhCurrent));
  1010. memAssert((pbhCurrent->GetSize() != 0) && "Zero size block found.");
  1011. if (!pbhCurrent->IsFree())
  1012. {
  1013. pul = (ULONG *)((BYTE *)pbhCurrent + sizeof(CBlockPreHeader));
  1014. memDebugOut((DEB_ERROR, "Allocated Block %p %8x %8x (size %lu)\n",
  1015. pul, *pul, *(pul+1), pbhCurrent->GetSize()));
  1016. }
  1017. else
  1018. {
  1019. pul = (ULONG *)pbhCurrent;
  1020. memDebugOut((DEB_ERROR, "Free Block %p %8x %8x (size %lu)\n",
  1021. pul, *pul, *(pul+1), pbhCurrent->GetSize()));
  1022. }
  1023. pbhCurrent =
  1024. (CBlockHeader *)((BYTE *)pbhCurrent + pbhCurrent->GetSize());
  1025. }
  1026. }
  1027. }
  1028. #endif // DBG == 1
  1029. //+---------------------------------------------------------------------------
  1030. //
  1031. // Member: CSmAllocator::SetState
  1032. //
  1033. // Synopsis: replace thread local state by PerContext state
  1034. //
  1035. // History: 20-Nov-95 Henrylee Created
  1036. //
  1037. //----------------------------------------------------------------------------
  1038. void CSmAllocator::SetState (CSharedMemoryBlock *psmb, BYTE * pbBase,
  1039. ULONG ulHeapName, CPerContext ** ppcPrev,
  1040. CPerContext *ppcOwner)
  1041. {
  1042. memDebugOut((DEB_ITRACE, "In CSmAllocator::SetState(%p, %p, %lx, %p, %p, %p) (this == %p)\n", psmb, pbBase, ulHeapName, ppcPrev, ppcOwner, _ppcOwner, this));
  1043. _psmb = psmb;
  1044. _pbBase = pbBase;
  1045. _cbSize = (_psmb) ? _psmb->GetSize() : 0;
  1046. _ulHeapName = ulHeapName;
  1047. DFBASEPTR = _pbBase;
  1048. if (ppcPrev != NULL)
  1049. *ppcPrev = _ppcOwner;
  1050. _ppcOwner = ppcOwner;
  1051. // memAssert (g_smAllocator.GetBase() == DFBASEPTR);
  1052. memDebugOut((DEB_ITRACE, "Out CSmAllocator::SetState()\n"));
  1053. }
  1054. //+---------------------------------------------------------------------------
  1055. //
  1056. // Member: CSmAllocator::GetState
  1057. //
  1058. // Synopsis: retrive thread local allocator state into percontext
  1059. //
  1060. // History: 20-Nov-95 Henrylee Created
  1061. //
  1062. //----------------------------------------------------------------------------
  1063. void CSmAllocator::GetState (CSharedMemoryBlock **ppsmb,
  1064. BYTE ** ppbBase, ULONG *pulHeapName)
  1065. {
  1066. *ppsmb = _psmb;
  1067. *ppbBase = _pbBase;
  1068. *pulHeapName = _ulHeapName;
  1069. }
  1070. //+---------------------------------------------------------------------------
  1071. //
  1072. // Member: CSmAllocator::Uninit
  1073. //
  1074. // Synopsis: unmap the shared memory region
  1075. //
  1076. // History: 20-Nov-95 Henrylee Created
  1077. //
  1078. //----------------------------------------------------------------------------
  1079. SCODE CSmAllocator::Uninit ()
  1080. {
  1081. memDebugOut((DEB_ITRACE, "In CSmAllocator::Uninit\n"));
  1082. if (_psmb != NULL)
  1083. {
  1084. if (_psmb != &g_smb)
  1085. {
  1086. // This is last block in the heap, so we can close the heap
  1087. // now. There must be no shared heap accesses after this.
  1088. delete _psmb;
  1089. #if DBG == 1
  1090. ModifyResLimit(DBRQ_HEAPS, -1);
  1091. #endif
  1092. gs_iSharedHeaps--;
  1093. }
  1094. else
  1095. {
  1096. if (GetHeader()->GetAllocedBlocks() == 0)
  1097. Reset(); // for g_smb
  1098. }
  1099. _psmb = NULL;
  1100. }
  1101. _pbBase = NULL;
  1102. memDebugOut((DEB_ITRACE, "Out CSmAllocator::Uninit %x\n", _ulHeapName));
  1103. _ulHeapName = 0;
  1104. return S_OK;
  1105. }
  1106. #endif // MULTIHEAP
  1107. #endif // !defined(_CHICAGO_)