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.

397 lines
11 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1994.
  5. //
  6. // File: stalloc.cxx
  7. //
  8. // Contents: CStackAllocator
  9. //
  10. // History: 29-Sep-94 DrewB Created
  11. //
  12. // Notes: Loosely based on BobDay's original PSTACK implementation
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "headers.cxx"
  16. #pragma hdrstop
  17. // Pad a count to the given alignment
  18. // Alignment must be 2^n-1
  19. #define ALIGN_CB(cb, align) \
  20. (((cb)+(align)) & ~(align))
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Structure: SStackBlock (sb)
  24. //
  25. // Purpose: Header information for stack blocks
  26. //
  27. // History: 29-Sep-94 DrewB Created
  28. //
  29. //----------------------------------------------------------------------------
  30. struct SStackBlock
  31. {
  32. DWORD dwNextBlock;
  33. DWORD dwStackTop;
  34. };
  35. #define BLOCK_OVERHEAD (sizeof(SStackBlock))
  36. #define BLOCK_START(mem) ((mem)+BLOCK_OVERHEAD)
  37. #define BLOCK_AVAILABLE(cb) ((cb)-BLOCK_OVERHEAD)
  38. //+---------------------------------------------------------------------------
  39. //
  40. // Function: CStackAllocator::CStackAllocator, public
  41. //
  42. // Arguments: [pmm] - Memory model to use
  43. // [cbBlock] - Size of chunk to allocate when necessary
  44. // [cbAlignment] - Alignment size, must be 2^N
  45. //
  46. // History: 29-Sep-94 DrewB Created
  47. //
  48. //----------------------------------------------------------------------------
  49. CStackAllocator::CStackAllocator(CMemoryModel *pmm,
  50. DWORD cbBlock,
  51. DWORD cbAlignment)
  52. {
  53. thkAssert(BLOCK_AVAILABLE(cbBlock) > 0);
  54. // Ensure that the alignment is a power of two
  55. thkAssert((cbAlignment & (cbAlignment-1)) == 0);
  56. // Store alignment - 1 since that's the actual value we need for
  57. // alignment computations
  58. _cbAlignment = cbAlignment-1;
  59. // Ensure that overhead and tracking will not affect alignment
  60. thkAssert(ALIGN_CB(BLOCK_OVERHEAD, _cbAlignment) == BLOCK_OVERHEAD &&
  61. ALIGN_CB(sizeof(SStackMemTrace), _cbAlignment) ==
  62. sizeof(SStackMemTrace));
  63. _pmm = pmm;
  64. _cbBlock = cbBlock;
  65. _dwBlocks = 0;
  66. _dwCurrent = 0;
  67. _cbAvailable = 0;
  68. _psaNext = NULL;
  69. _fActive = TRUE;
  70. }
  71. //+---------------------------------------------------------------------------
  72. //
  73. // Member: CStackAllocator::~CStackAllocator, public virtual
  74. //
  75. // History: 29-Sep-94 DrewB Created
  76. //
  77. //----------------------------------------------------------------------------
  78. CStackAllocator::~CStackAllocator(void)
  79. {
  80. Reset();
  81. }
  82. //+---------------------------------------------------------------------------
  83. //
  84. // Function: CStackAllocator::Alloc, public
  85. //
  86. // Synopsis: Allocates a chunk of memory from the stack
  87. //
  88. // Arguments: [cb] - Amount of memory to allocate
  89. //
  90. // Returns: Pointer to memory or NULL
  91. //
  92. // History: 29-Sep-94 DrewB Created
  93. //
  94. //----------------------------------------------------------------------------
  95. DWORD CStackAllocator::Alloc(DWORD cb)
  96. {
  97. DWORD dwMem;
  98. thkAssert(cb > 0);
  99. // Round size up to maintain alignment of stack
  100. cb = ALIGN_CB(cb, _cbAlignment);
  101. #if DBG == 1
  102. // Reserve space to record caller
  103. cb += sizeof(SStackMemTrace);
  104. #endif
  105. thkAssert(cb <= BLOCK_AVAILABLE(_cbBlock));
  106. // Check to see if the current block can hold the new allocation
  107. if (cb > _cbAvailable)
  108. {
  109. DWORD dwBlock;
  110. SStackBlock UNALIGNED *psb;
  111. // It's too big, so allocate a new block
  112. dwBlock = _pmm->AllocMemory(_cbBlock);
  113. if (dwBlock == 0)
  114. {
  115. return 0;
  116. }
  117. if (_dwBlocks != 0)
  118. {
  119. // Update current top block
  120. psb = (SStackBlock UNALIGNED *)
  121. _pmm->ResolvePtr(_dwBlocks, sizeof(SStackBlock));
  122. psb->dwStackTop = _dwCurrent;
  123. _pmm->ReleasePtr(_dwBlocks);
  124. }
  125. // Make the new block the top block
  126. psb = (SStackBlock UNALIGNED *)
  127. _pmm->ResolvePtr(dwBlock, sizeof(SStackBlock));
  128. psb->dwNextBlock = _dwBlocks;
  129. _dwBlocks = dwBlock;
  130. _pmm->ReleasePtr(dwBlock);
  131. _dwCurrent = BLOCK_START(dwBlock);
  132. _cbAvailable = BLOCK_AVAILABLE(_cbBlock);
  133. }
  134. thkAssert(_cbAvailable >= cb);
  135. dwMem = _dwCurrent;
  136. _dwCurrent += cb;
  137. _cbAvailable -= cb;
  138. #if DBG == 1
  139. void *pvMem;
  140. // Fill memory to show reuse problems
  141. pvMem = _pmm->ResolvePtr(dwMem, cb);
  142. memset(pvMem, 0xED, cb);
  143. _pmm->ReleasePtr(dwMem);
  144. #endif
  145. #if DBG == 1
  146. SStackMemTrace UNALIGNED *psmt;
  147. psmt = (SStackMemTrace UNALIGNED *)
  148. _pmm->ResolvePtr(_dwCurrent-sizeof(SStackMemTrace),
  149. sizeof(SStackMemTrace));
  150. psmt->cbSize = cb-sizeof(SStackMemTrace);
  151. #if !defined(_CHICAGO_)
  152. //
  153. // On RISC platforms, psmt points to an unaligned structure.
  154. // Use a temp variable so we don't get an alignment fault
  155. // when RtlGetCallersAddress returns the value.
  156. //
  157. void *pv;
  158. void *pvCaller;
  159. RtlGetCallersAddress(&pvCaller, &pv);
  160. psmt->pvCaller = pvCaller;
  161. #else
  162. // Depends on return address being directly below first argument
  163. psmt->pvCaller = *((void **)&cb-1);
  164. #endif
  165. thkDebugOut((DEB_MEMORY, "Stack: %p alloc 0x%08lX:%3d, avail %d\n",
  166. psmt->pvCaller, dwMem, cb, _cbAvailable));
  167. _pmm->ReleasePtr(_dwCurrent-sizeof(SStackMemTrace));
  168. #endif
  169. return dwMem;
  170. }
  171. //+---------------------------------------------------------------------------
  172. //
  173. // Function: CStackAllocator::Free, public
  174. //
  175. // Synopsis: Frees allocated memory
  176. //
  177. // Arguments: [dwMem] - Memory
  178. // [cb] - Amount of memory allocated
  179. //
  180. // History: 29-Sep-94 DrewB Created
  181. //
  182. //----------------------------------------------------------------------------
  183. void CStackAllocator::Free(DWORD dwMem, DWORD cb)
  184. {
  185. thkAssert(dwMem != 0);
  186. thkAssert(cb > 0);
  187. // Round size up to maintain alignment of stack
  188. cb = ALIGN_CB(cb, _cbAlignment);
  189. #if DBG == 1
  190. cb += sizeof(SStackMemTrace);
  191. #endif
  192. thkAssert(cb <= BLOCK_AVAILABLE(_cbBlock));
  193. #if DBG == 1
  194. void *pvCaller;
  195. #if !defined(_CHICAGO_)
  196. void *pv;
  197. RtlGetCallersAddress(&pvCaller, &pv);
  198. #else
  199. // Depends on return address being directly below first argument
  200. pvCaller = *((void **)&dwMem-1);
  201. #endif
  202. thkDebugOut((DEB_MEMORY, "Stack: %p frees 0x%08lX:%3d, avail %d\n",
  203. pvCaller, dwMem, cb, _cbAvailable));
  204. #endif
  205. #if DBG == 1
  206. if (_dwCurrent-cb != dwMem)
  207. {
  208. thkDebugOut((DEB_ERROR, "Free of %d:%d is not TOS (0x%08lX)\n",
  209. dwMem, cb, _dwCurrent));
  210. thkAssert(_dwCurrent-cb == dwMem);
  211. }
  212. #endif
  213. _dwCurrent -= cb;
  214. _cbAvailable += cb;
  215. #if DBG == 1
  216. void *pvMem;
  217. // Fill memory to show reuse problems
  218. pvMem = _pmm->ResolvePtr(dwMem, cb);
  219. memset(pvMem, 0xDD, cb);
  220. _pmm->ReleasePtr(dwMem);
  221. #endif
  222. if (_dwCurrent == BLOCK_START(_dwBlocks))
  223. {
  224. SStackBlock UNALIGNED *psb;
  225. DWORD dwBlock;
  226. // If we've just freed up an entire block and it's not the
  227. // only block for the stack, free the block itself and
  228. // restore stack state from the next block
  229. // We keep the first block around forever to avoid memory
  230. // thrashing
  231. psb = (SStackBlock UNALIGNED *)
  232. _pmm->ResolvePtr(_dwBlocks, sizeof(SStackBlock));
  233. dwBlock = psb->dwNextBlock;
  234. _pmm->ReleasePtr(_dwBlocks);
  235. if (dwBlock != 0)
  236. {
  237. _pmm->FreeMemory(_dwBlocks);
  238. _dwBlocks = dwBlock;
  239. psb = (SStackBlock UNALIGNED *)
  240. _pmm->ResolvePtr(_dwBlocks, sizeof(SStackBlock));
  241. _dwCurrent = psb->dwStackTop;
  242. _cbAvailable = _cbBlock-(_dwCurrent-_dwBlocks);
  243. _pmm->ReleasePtr(_dwBlocks);
  244. }
  245. }
  246. }
  247. //+---------------------------------------------------------------------------
  248. //
  249. // Member: CStackAllocator::Reset, public
  250. //
  251. // Synopsis: Releases all memory in the stack
  252. //
  253. // History: 29-Sep-94 DrewB Created
  254. //
  255. //----------------------------------------------------------------------------
  256. void CStackAllocator::Reset(void)
  257. {
  258. DWORD dwBlock;
  259. SStackBlock UNALIGNED *psb;
  260. while (_dwBlocks != 0)
  261. {
  262. psb = (SStackBlock UNALIGNED *)
  263. _pmm->ResolvePtr(_dwBlocks, sizeof(SStackBlock));
  264. dwBlock = psb->dwNextBlock;
  265. _pmm->ReleasePtr(_dwBlocks);
  266. _pmm->FreeMemory(_dwBlocks);
  267. _dwBlocks = dwBlock;
  268. }
  269. _dwCurrent = 0;
  270. _cbAvailable = 0;
  271. }
  272. //+---------------------------------------------------------------------------
  273. //
  274. // Function: CStackAllocator::RecordState, public debug
  275. //
  276. // Synopsis: Records the current state of the stack
  277. //
  278. // Arguments: [psr] - Storage space for information
  279. //
  280. // Modifies: [psr]
  281. //
  282. // History: 28-Apr-94 DrewB Created
  283. //
  284. //----------------------------------------------------------------------------
  285. #if DBG == 1
  286. void CStackAllocator::RecordState(SStackRecord *psr)
  287. {
  288. psr->dwStackPointer = _dwCurrent;
  289. psr->dwThreadId = GetCurrentThreadId();
  290. }
  291. #endif
  292. //+---------------------------------------------------------------------------
  293. //
  294. // Function: CStackAllocator::CheckState, public debug
  295. //
  296. // Synopsis: Checks recorded information about the stack against its
  297. // current state
  298. //
  299. // Arguments: [psr] - Recorded information
  300. //
  301. // History: 28-Apr-94 DrewB Created
  302. //
  303. //----------------------------------------------------------------------------
  304. #if DBG == 1
  305. void CStackAllocator::CheckState(SStackRecord *psr)
  306. {
  307. thkAssert(psr->dwThreadId == GetCurrentThreadId());
  308. if ((psr->dwStackPointer != 0 && psr->dwStackPointer != _dwCurrent) ||
  309. (psr->dwStackPointer == 0 &&
  310. _dwCurrent != 0 && _dwCurrent != BLOCK_START(_dwBlocks)))
  311. {
  312. thkDebugOut((DEB_ERROR, "Stack alloc change: 0x%08lX to 0x%08lX\n",
  313. psr->dwStackPointer, _dwCurrent));
  314. if (_dwCurrent > BLOCK_START(_dwBlocks))
  315. {
  316. SStackMemTrace UNALIGNED *psmt;
  317. psmt = (SStackMemTrace UNALIGNED *)
  318. _pmm->ResolvePtr(_dwCurrent-sizeof(SStackMemTrace),
  319. sizeof(SStackMemTrace));
  320. thkDebugOut((DEB_ERROR, "Top alloc: %d bytes by %p\n",
  321. psmt->cbSize, psmt->pvCaller));
  322. _pmm->ReleasePtr(_dwCurrent-sizeof(SStackMemTrace));
  323. }
  324. thkAssert(!((psr->dwStackPointer != 0 &&
  325. psr->dwStackPointer != _dwCurrent) ||
  326. (psr->dwStackPointer == 0 &&
  327. _dwCurrent != 0 ||
  328. _dwCurrent != BLOCK_START(_dwBlocks))));
  329. }
  330. }
  331. #endif