Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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