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.

387 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. //
  152. // On RISC platforms, psmt points to an unaligned structure.
  153. // Use a temp variable so we don't get an alignment fault
  154. // when RtlGetCallersAddress returns the value.
  155. //
  156. void *pv;
  157. void *pvCaller;
  158. RtlGetCallersAddress(&pvCaller, &pv);
  159. psmt->pvCaller = pvCaller;
  160. thkDebugOut((DEB_MEMORY, "Stack: %p alloc 0x%08lX:%3d, avail %d\n",
  161. psmt->pvCaller, dwMem, cb, _cbAvailable));
  162. _pmm->ReleasePtr(_dwCurrent-sizeof(SStackMemTrace));
  163. #endif
  164. return dwMem;
  165. }
  166. //+---------------------------------------------------------------------------
  167. //
  168. // Function: CStackAllocator::Free, public
  169. //
  170. // Synopsis: Frees allocated memory
  171. //
  172. // Arguments: [dwMem] - Memory
  173. // [cb] - Amount of memory allocated
  174. //
  175. // History: 29-Sep-94 DrewB Created
  176. //
  177. //----------------------------------------------------------------------------
  178. void CStackAllocator::Free(DWORD dwMem, DWORD cb)
  179. {
  180. thkAssert(dwMem != 0);
  181. thkAssert(cb > 0);
  182. // Round size up to maintain alignment of stack
  183. cb = ALIGN_CB(cb, _cbAlignment);
  184. #if DBG == 1
  185. cb += sizeof(SStackMemTrace);
  186. #endif
  187. thkAssert(cb <= BLOCK_AVAILABLE(_cbBlock));
  188. #if DBG == 1
  189. void *pvCaller;
  190. void *pv;
  191. RtlGetCallersAddress(&pvCaller, &pv);
  192. thkDebugOut((DEB_MEMORY, "Stack: %p frees 0x%08lX:%3d, avail %d\n",
  193. pvCaller, dwMem, cb, _cbAvailable));
  194. #endif
  195. #if DBG == 1
  196. if (_dwCurrent-cb != dwMem)
  197. {
  198. thkDebugOut((DEB_ERROR, "Free of %d:%d is not TOS (0x%08lX)\n",
  199. dwMem, cb, _dwCurrent));
  200. thkAssert(_dwCurrent-cb == dwMem);
  201. }
  202. #endif
  203. _dwCurrent -= cb;
  204. _cbAvailable += cb;
  205. #if DBG == 1
  206. void *pvMem;
  207. // Fill memory to show reuse problems
  208. pvMem = _pmm->ResolvePtr(dwMem, cb);
  209. memset(pvMem, 0xDD, cb);
  210. _pmm->ReleasePtr(dwMem);
  211. #endif
  212. if (_dwCurrent == BLOCK_START(_dwBlocks))
  213. {
  214. SStackBlock UNALIGNED *psb;
  215. DWORD dwBlock;
  216. // If we've just freed up an entire block and it's not the
  217. // only block for the stack, free the block itself and
  218. // restore stack state from the next block
  219. // We keep the first block around forever to avoid memory
  220. // thrashing
  221. psb = (SStackBlock UNALIGNED *)
  222. _pmm->ResolvePtr(_dwBlocks, sizeof(SStackBlock));
  223. dwBlock = psb->dwNextBlock;
  224. _pmm->ReleasePtr(_dwBlocks);
  225. if (dwBlock != 0)
  226. {
  227. _pmm->FreeMemory(_dwBlocks);
  228. _dwBlocks = dwBlock;
  229. psb = (SStackBlock UNALIGNED *)
  230. _pmm->ResolvePtr(_dwBlocks, sizeof(SStackBlock));
  231. _dwCurrent = psb->dwStackTop;
  232. _cbAvailable = _cbBlock-(_dwCurrent-_dwBlocks);
  233. _pmm->ReleasePtr(_dwBlocks);
  234. }
  235. }
  236. }
  237. //+---------------------------------------------------------------------------
  238. //
  239. // Member: CStackAllocator::Reset, public
  240. //
  241. // Synopsis: Releases all memory in the stack
  242. //
  243. // History: 29-Sep-94 DrewB Created
  244. //
  245. //----------------------------------------------------------------------------
  246. void CStackAllocator::Reset(void)
  247. {
  248. DWORD dwBlock;
  249. SStackBlock UNALIGNED *psb;
  250. while (_dwBlocks != 0)
  251. {
  252. psb = (SStackBlock UNALIGNED *)
  253. _pmm->ResolvePtr(_dwBlocks, sizeof(SStackBlock));
  254. dwBlock = psb->dwNextBlock;
  255. _pmm->ReleasePtr(_dwBlocks);
  256. _pmm->FreeMemory(_dwBlocks);
  257. _dwBlocks = dwBlock;
  258. }
  259. _dwCurrent = 0;
  260. _cbAvailable = 0;
  261. }
  262. //+---------------------------------------------------------------------------
  263. //
  264. // Function: CStackAllocator::RecordState, public debug
  265. //
  266. // Synopsis: Records the current state of the stack
  267. //
  268. // Arguments: [psr] - Storage space for information
  269. //
  270. // Modifies: [psr]
  271. //
  272. // History: 28-Apr-94 DrewB Created
  273. //
  274. //----------------------------------------------------------------------------
  275. #if DBG == 1
  276. void CStackAllocator::RecordState(SStackRecord *psr)
  277. {
  278. psr->dwStackPointer = _dwCurrent;
  279. psr->dwThreadId = GetCurrentThreadId();
  280. }
  281. #endif
  282. //+---------------------------------------------------------------------------
  283. //
  284. // Function: CStackAllocator::CheckState, public debug
  285. //
  286. // Synopsis: Checks recorded information about the stack against its
  287. // current state
  288. //
  289. // Arguments: [psr] - Recorded information
  290. //
  291. // History: 28-Apr-94 DrewB Created
  292. //
  293. //----------------------------------------------------------------------------
  294. #if DBG == 1
  295. void CStackAllocator::CheckState(SStackRecord *psr)
  296. {
  297. thkAssert(psr->dwThreadId == GetCurrentThreadId());
  298. if ((psr->dwStackPointer != 0 && psr->dwStackPointer != _dwCurrent) ||
  299. (psr->dwStackPointer == 0 &&
  300. _dwCurrent != 0 && _dwCurrent != BLOCK_START(_dwBlocks)))
  301. {
  302. thkDebugOut((DEB_ERROR, "Stack alloc change: 0x%08lX to 0x%08lX\n",
  303. psr->dwStackPointer, _dwCurrent));
  304. if (_dwCurrent > BLOCK_START(_dwBlocks))
  305. {
  306. SStackMemTrace UNALIGNED *psmt;
  307. psmt = (SStackMemTrace UNALIGNED *)
  308. _pmm->ResolvePtr(_dwCurrent-sizeof(SStackMemTrace),
  309. sizeof(SStackMemTrace));
  310. thkDebugOut((DEB_ERROR, "Top alloc: %d bytes by %p\n",
  311. psmt->cbSize, psmt->pvCaller));
  312. _pmm->ReleasePtr(_dwCurrent-sizeof(SStackMemTrace));
  313. }
  314. thkAssert(!((psr->dwStackPointer != 0 &&
  315. psr->dwStackPointer != _dwCurrent) ||
  316. (psr->dwStackPointer == 0 &&
  317. _dwCurrent != 0 ||
  318. _dwCurrent != BLOCK_START(_dwBlocks))));
  319. }
  320. }
  321. #endif