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.

493 lines
11 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1993.
  5. //
  6. // File: stdalloc.cxx
  7. //
  8. // Contents: 16-bit OLE allocator
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 3-07-94 kevinro Ported from ole2.01 (16-bit)
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <headers.cxx>
  18. #pragma hdrstop
  19. #include <ole2sp.h>
  20. /****** Standard Task/Shared Allocator **********************************/
  21. #define NULLSAB ((__segment)0)
  22. typedef __segment SAB;
  23. // amount of space windows reserves at start of segment
  24. #define cbWinRes 16
  25. // amount of space LocalInit takes (somewhat empirical)
  26. #define cbWinOH (6+10+46)
  27. // total overhead per global block
  28. #define cbTotalOH (cbWinRes + sizeof(StdAllocHdr) + cbWinOH + 32)
  29. // maximum sized object in a SAB (fudged to include space for per-block
  30. // overhead and most anything else we missed).
  31. #define cbMaxSAB (0xfffe - cbTotalOH)
  32. //+---------------------------------------------------------------------------
  33. //
  34. // Class: CStdMalloc ()
  35. //
  36. // Purpose: Standard task allocator
  37. //
  38. // History: 3-04-94 kevinro Created
  39. //
  40. // Notes:
  41. //
  42. //----------------------------------------------------------------------------
  43. class FAR CStdMalloc : public IMalloc
  44. {
  45. public:
  46. CStdMalloc(DWORD memctx)
  47. {
  48. m_refs = 1;
  49. m_pStdAllocHead = NULL;
  50. m_flags = (memctx == MEMCTX_TASK)? GMEM_MOVEABLE :
  51. GMEM_MOVEABLE|GMEM_SHARE;
  52. }
  53. STDMETHOD(QueryInterface)(REFIID iid, void FAR* FAR* ppvObj)
  54. {
  55. VDATEPTROUT( ppvObj, LPVOID );
  56. *ppvObj = NULL;
  57. VDATEIID( iid );
  58. if (iid == IID_IUnknown || iid == IID_IMalloc) {
  59. *ppvObj = this;
  60. ++m_refs;
  61. return NOERROR;
  62. } else {
  63. *ppvObj = NULL;
  64. return ReportResult(0, E_NOINTERFACE, 0, 0);
  65. }
  66. }
  67. STDMETHOD_(ULONG,AddRef)(void) { return ++m_refs; }
  68. STDMETHOD_(ULONG,Release)(void)
  69. {
  70. if (--m_refs == 0) {
  71. // free all memory (includes the memory for this class)
  72. FreeAllMem();
  73. return 0;
  74. } else
  75. return m_refs;
  76. }
  77. STDMETHOD_(void FAR*, Alloc) (ULONG cb);
  78. STDMETHOD_(void FAR*, Realloc) (void FAR* pv, ULONG cb);
  79. STDMETHOD_(void, Free) (void FAR* pv);
  80. STDMETHOD_(ULONG, GetSize) (void FAR* pv);
  81. STDMETHOD_(int, DidAlloc) (void FAR* pv);
  82. STDMETHOD_(void, HeapMinimize) ();
  83. private:
  84. ULONG m_refs;
  85. UINT m_flags;
  86. #define STDALLOC_SIG 0x4D445453 // 'STDM'
  87. struct StdAllocHdr
  88. {
  89. ULONG m_Signature;
  90. HTASK m_hTask; // task which owns this block
  91. StdAllocHdr FAR* m_pStdAllocNext;
  92. };
  93. StdAllocHdr FAR* m_pStdAllocHead;
  94. INTERNAL_(StdAllocHdr FAR*) MapBlockToSA(SAB sab) { return (StdAllocHdr FAR*)MAKELONG(cbWinRes, sab); }
  95. INTERNAL_(SAB) MapSAToBlock(StdAllocHdr FAR* pSA) { return (__segment)pSA; }
  96. INTERNAL_(void FAR*) AllocInBlock(SAB seg, UINT cb);
  97. INTERNAL_(SAB) AllocNewBlock(UINT cb);
  98. INTERNAL_(SAB) MapPtrToBlock(void FAR* pv);
  99. INTERNAL_(CStdMalloc FAR*) MoveSelf(LPVOID lpv);
  100. friend HRESULT STDAPICALLTYPE CoCreateStandardMalloc(DWORD memctx, IMalloc FAR* FAR* ppMalloc);
  101. INTERNAL_(void) FreeAllMem(void);
  102. };
  103. INTERNAL_(void FAR*) CStdMalloc::AllocInBlock(SAB sab, UINT cb)
  104. {
  105. #ifdef _DEBUG
  106. WINDEBUGINFO Olddebuginfo, debuginfo;
  107. //get initial debug state
  108. GetWinDebugInfo(&debuginfo, WDI_OPTIONS);
  109. Olddebuginfo = debuginfo;
  110. //turn off alerts (see bug 3502)
  111. debuginfo.dwOptions |= DBO_SILENT;
  112. SetWinDebugInfo(&debuginfo);
  113. #endif // _DEBUG
  114. // must make alloc of 0 mean alloc something; LocalAlloc fails on cb == 0
  115. if (0==cb)
  116. cb = 2;
  117. _asm push DS;
  118. _asm mov DS, sab;
  119. void NEAR *npv = (void NEAR*)LocalAlloc(LMEM_FIXED, cb);
  120. _asm pop DS;
  121. #ifdef _DEBUG
  122. //restore Debug state
  123. SetWinDebugInfo(&Olddebuginfo);
  124. #endif // _DEBUG
  125. if (npv == NULL) // npv is near pointer
  126. return NULL; // returned value is far pointer
  127. return (void FAR*)MAKELONG(npv, sab);
  128. }
  129. INTERNAL_(SAB) CStdMalloc::AllocNewBlock(UINT cb)
  130. {
  131. if (cb > cbMaxSAB)
  132. // overflow
  133. return NULLSAB;
  134. if (cb < 4096 - cbTotalOH)
  135. // minimum is 4k global block
  136. cb = 4096;
  137. else
  138. // size will be larger than 4K; must include total overhead
  139. cb += cbTotalOH;
  140. // allocate block and get segment value
  141. HGLOBAL h;
  142. if ((h = GlobalAlloc(m_flags, cb)) == NULL)
  143. return NULLSAB;
  144. UINT segment;
  145. segment = HIWORD(GlobalHandle(h));
  146. // init windows local heap
  147. if (!LocalInit(segment, cbWinRes + sizeof(StdAllocHdr), cb)) {
  148. GlobalFree(h);
  149. return NULLSAB;
  150. }
  151. // init block and put it on front of list
  152. StdAllocHdr FAR* pSA;
  153. pSA = MapBlockToSA((SAB)segment);
  154. pSA->m_Signature = STDALLOC_SIG;
  155. pSA->m_hTask = (m_flags & GMEM_SHARE) != 0 ? NULL : GetCurrentTask();
  156. pSA->m_pStdAllocNext = m_pStdAllocHead;
  157. m_pStdAllocHead = pSA;
  158. return (SAB)segment;
  159. }
  160. INTERNAL_(SAB) CStdMalloc::MapPtrToBlock(void FAR* pv)
  161. {
  162. if (pv == NULL)
  163. return NULLSAB;
  164. StdAllocHdr FAR* pSA;
  165. pSA = MapBlockToSA((SAB)pv);
  166. if (pSA->m_Signature != STDALLOC_SIG)
  167. return NULLSAB;
  168. #ifdef DOESNTWORK
  169. UINT flags = GlobalFlags((HGLOBAL)GlobalHandle((SAB)pv));
  170. #endif
  171. if (m_flags & GMEM_SHARE) {
  172. if (pSA->m_hTask != NULL)
  173. // owned by task; not shared memory
  174. return NULLSAB;
  175. #ifdef DOESNTWORK
  176. if ((flags & GMEM_SHARE) == 0)
  177. // flags not shared, not shared memory
  178. return NULLSAB;
  179. #endif
  180. } else {
  181. if (pSA->m_hTask != GetCurrentTask()) {
  182. // if not same task, not this allocator; if different task,
  183. // something is wrong.
  184. AssertSz(pSA->m_hTask == NULL, "pointer used in wrong task");
  185. return NULLSAB;
  186. }
  187. #ifdef DOESNTWORK
  188. if ((flags & GMEM_SHARE) != 0)
  189. // flags shared, not task memory
  190. return NULLSAB;
  191. #endif
  192. }
  193. return MapSAToBlock(pSA);
  194. }
  195. STDMETHODIMP_(void FAR*) CStdMalloc::Alloc(ULONG cb)
  196. {
  197. if (cb > cbMaxSAB)
  198. // can't deal with objects larger than 64k
  199. return NULL;
  200. // try all sab in order (newest allocated sab on front)
  201. StdAllocHdr FAR* pSA = m_pStdAllocHead;
  202. while (pSA != NULL) {
  203. // try allocating the memory; if successful, return
  204. void FAR* pv;
  205. if ((pv = AllocInBlock(MapSAToBlock(pSA), (UINT)cb)) != NULL)
  206. return pv;
  207. pSA = pSA->m_pStdAllocNext;
  208. }
  209. SAB sab;
  210. if ((sab = AllocNewBlock((UINT)cb)) == NULLSAB)
  211. return NULL;
  212. // this should really succeed (i.e., an assert would be better)
  213. return AllocInBlock(sab, (UINT)cb);
  214. }
  215. STDMETHODIMP_(void FAR*) CStdMalloc::Realloc(void FAR* pv, ULONG cb)
  216. {
  217. if (cb > cbMaxSAB)
  218. // can't deal with objects larger than 64k
  219. return NULL;
  220. SAB sab;
  221. if (pv == NULL)
  222. // same as allocating a new pointer
  223. return Alloc(cb);
  224. //VDATEPTRIN rejects NULL (changed by alexgo 8/3/93)
  225. GEN_VDATEPTRIN( pv, int, (LPVOID)NULL );
  226. if ((sab = MapPtrToBlock(pv)) == NULLSAB)
  227. // attempt to realloc a pointer from some other allocator
  228. return NULL;
  229. else if (cb == 0) {
  230. // Realloc(pv, 0) -> frees and returns NULL; this is C library behavior
  231. Free(pv);
  232. return NULL;
  233. }
  234. void NEAR* npv;
  235. npv = (void NEAR*)(ULONG)pv;
  236. // first try realloc within same sab
  237. Assert(sab != NULLSAB);
  238. {
  239. void NEAR* npvT;
  240. _asm push DS;
  241. _asm mov DS, sab;
  242. npvT = (void NEAR*)LocalReAlloc((HLOCAL)npv, (UINT)cb, LMEM_MOVEABLE);
  243. _asm pop DS;
  244. if (npvT != NULL)
  245. return (void FAR*)MAKELONG(npvT, sab);
  246. }
  247. // now try allocating new sab and copying
  248. void FAR* pvT;
  249. if ((pvT = Alloc(cb)) == NULL)
  250. return NULL;
  251. // only copy the smaller of the old and new size
  252. _asm push ds;
  253. _asm mov ds,sab;
  254. UINT cbCopy = LocalSize((HLOCAL)npv);
  255. _asm pop ds;
  256. if ((UINT)cb < cbCopy)
  257. // new size smaller
  258. cbCopy = (UINT)cb;
  259. _fmemcpy(pvT, pv, cbCopy);
  260. Free(pv);
  261. return pvT;
  262. }
  263. STDMETHODIMP_(void) CStdMalloc::Free(void FAR* pv)
  264. {
  265. SAB sab;
  266. if (pv == NULL)
  267. return;
  268. //VDATEPTRIN rejects NULL (changed by alexgo 8/3/93)
  269. VOID_VDATEPTRIN( pv, int );
  270. if ((sab = MapPtrToBlock(pv)) == NULLSAB) {
  271. #ifdef _DEBUG
  272. AssertSz(FALSE, "Pointer freed by wrong allocator; filling with 0xcc");
  273. // we don't own block; this is an error; fill it with 0xcccc anyway
  274. UINT cb = (UINT)GlobalSize((HGLOBAL)GlobalHandle((__segment)pv));
  275. cb -= (UINT)(ULONG)pv;
  276. _fmemset(pv, 0xcc, (size_t)cb);
  277. #endif
  278. } else {
  279. #ifdef _DEBUG
  280. // we own block; fill it with 0xcccc
  281. _fmemset(pv, 0xcc, (size_t)GetSize(pv));
  282. #endif
  283. _asm push ds;
  284. _asm mov ds,sab;
  285. LocalFree((HLOCAL)(void NEAR*)(ULONG)pv);
  286. _asm pop ds;
  287. }
  288. }
  289. STDMETHODIMP_(ULONG) CStdMalloc::GetSize(void FAR* pv)
  290. {
  291. ULONG size = 0;
  292. SAB sab;
  293. //VDATEPTRIN rejects NULL (added by alexgo 8/3/93)
  294. if( pv == NULL )
  295. return -1;
  296. GEN_VDATEPTRIN( pv , int, 0 );
  297. if ((sab = MapPtrToBlock(pv)) != NULLSAB) {
  298. _asm push ds;
  299. _asm mov ds,sab;
  300. size = LocalSize((HLOCAL)(void NEAR*)(ULONG)pv);
  301. _asm pop ds;
  302. }
  303. return size;
  304. }
  305. STDMETHODIMP_(int) CStdMalloc::DidAlloc(void FAR* pv)
  306. {
  307. if (pv == NULL)
  308. return -1;
  309. //VDATEPTRIN rejects NULL (added by alexgo 8/3/93)
  310. GEN_VDATEPTRIN( pv , int, 0 );
  311. // returns 1 if we allocated, 0 if not; this impl never returns -1.
  312. return MapPtrToBlock(pv) != NULLSAB;
  313. }
  314. STDMETHODIMP_(void) CStdMalloc::HeapMinimize()
  315. {
  316. // LATER : could do local compact here
  317. }
  318. // move this instance of stdmalloc to lpv (which must be large enough)
  319. INTERNAL_(CStdMalloc FAR*) CStdMalloc::MoveSelf(LPVOID lpv)
  320. {
  321. _fmemcpy(lpv, this, sizeof(*this));
  322. m_pStdAllocHead = NULL;
  323. return (CStdMalloc FAR*)lpv;
  324. }
  325. INTERNAL_(void) CStdMalloc::FreeAllMem(void)
  326. {
  327. // get/null out head of list; null now in case we are freeing self.
  328. StdAllocHdr FAR* pSA = m_pStdAllocHead;
  329. m_pStdAllocHead = NULL;
  330. // free all blocks
  331. while (pSA != NULL) {
  332. StdAllocHdr FAR* pSANext = pSA->m_pStdAllocNext;
  333. pSA->m_pStdAllocNext = NULL; // to prevent incorrect compiler opt
  334. GlobalFree(LOWORD(GlobalHandle((UINT)MapSAToBlock(pSA))));
  335. pSA = pSANext;
  336. }
  337. }
  338. /****** Global API for creating *****************************************/
  339. // create and return an impl of IMalloc of given memctx
  340. //+---------------------------------------------------------------------------
  341. //
  342. // Function: CoCreateStandardMalloc, Local
  343. //
  344. // Synopsis:
  345. //
  346. // Effects:
  347. //
  348. // Arguments: [memctx] --
  349. // [ppMalloc] --
  350. //
  351. // Requires:
  352. //
  353. // Returns:
  354. //
  355. // Signals:
  356. //
  357. // Modifies:
  358. //
  359. // Algorithm:
  360. //
  361. // History: 2-28-94 kevinro Created
  362. //
  363. // Notes:
  364. //
  365. //----------------------------------------------------------------------------
  366. STDAPI CoCreateStandardMalloc(DWORD memctx, IMalloc FAR* FAR* ppMalloc)
  367. {
  368. thkDebugOut((DEB_ITRACE, " CoCreateStandardMalloc\n"));
  369. *ppMalloc = NULL;
  370. switch (memctx) {
  371. case MEMCTX_TASK:
  372. case MEMCTX_SHARED:
  373. {
  374. CStdMalloc sm(memctx); // local one
  375. void FAR* lpv;
  376. if ((lpv = sm.Alloc(sizeof(CStdMalloc))) == NULL)
  377. return ResultFromScode(E_OUTOFMEMORY);
  378. *ppMalloc = sm.MoveSelf(lpv); // move to newly allocated memory
  379. return NOERROR;
  380. }
  381. default:
  382. return ResultFromScode(E_INVALIDARG);
  383. }
  384. }