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.

375 lines
12 KiB

  1. //*****************************************************************************
  2. //
  3. // MESSAGE HEAP 16 -
  4. //
  5. // Heap allocation functions for 32-16 message thunks.
  6. //
  7. // NOTE: these are NOT general purpose heap managment routines.
  8. //
  9. //
  10. // 07-17-92 NanduriR Created.
  11. //
  12. //*****************************************************************************
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. MODNAME(walloc16.c);
  16. //*****************************************************************************
  17. // General Notes:
  18. //
  19. // This heap maanger is for specific 'performance gains' and is thus not
  20. // intended for general purpose use and therfore much of the overhead has
  21. // been eliminated.
  22. //
  23. // This heap manager is intended mainly for thunks - where we are sure that
  24. // an alloced block will definitely be freed. Thus it is meant for our use.
  25. //
  26. // The heap is conceptually an array of constant-size blocks. The size of the
  27. // block is predefined. The code is optimized for allocation requests of one
  28. // blocksize or less. It is slower if the allocation request needs more than
  29. // one block.
  30. //
  31. // The heap header is a static array. The header has two flags. One to note
  32. // that a particular heapblock is in use and the other to note whether the
  33. // block forms a part of a linked/chained set of contiguous blocks. The blocks
  34. // are linked when the allocation request is for more than the predefined
  35. // block size.
  36. //
  37. //*****************************************************************************
  38. #define HEAP16_TOTALSIZE 0x2000
  39. #define HEAP16_BLOCKSIZE 0x100 // We should set it to an optimum value
  40. #define HEAP16_BLOCKCOUNT (HEAP16_TOTALSIZE/HEAP16_BLOCKSIZE)
  41. #define HHDR16_FINUSE 0x01
  42. #define HHDR16_FLINKED 0x02
  43. #define ISBLOCKINUSE(block) ((block) & HHDR16_FINUSE)
  44. #define ISBLOCKLINKED(block) ((block) & HHDR16_FLINKED)
  45. //*****************************************************************************
  46. //
  47. // Globals -
  48. //
  49. // vahdr - is the heap header. This header is 32bit memory and not part of the
  50. // 16bit heap - this is so that the 16bit heap is put to maximum use.
  51. //
  52. // vpHeap16 - far pointer to the start of 16bit heap
  53. //
  54. // viFreeIndex - the index from which we start searching for a freeblock.
  55. // Normally this is set to the memoryblock that was most
  56. // recently freed, thus increasing the chances of finding
  57. // a freeblock instantly.
  58. //*****************************************************************************
  59. BYTE vahdr[HEAP16_BLOCKCOUNT];
  60. LPBYTE vpHeap16 = (LPBYTE)NULL;
  61. UINT viFreeIndex = 0; // First look for Free block here.
  62. //*****************************************************************************
  63. //
  64. // malloc16 -
  65. //
  66. // Allocs memory from 16bit block.
  67. // If heap is full, does normal GlobalAlloc
  68. //
  69. // Returns farpointer to memoryblock;
  70. //
  71. //*****************************************************************************
  72. VPVOID FASTCALL malloc16(UINT cb)
  73. {
  74. INT i, j;
  75. INT cBlocksRequired;
  76. INT fContiguousFreeBlocks;
  77. INT vpT;
  78. if (vpHeap16 == (LPBYTE)NULL) {
  79. vpHeap16 = (LPBYTE)GlobalAllocLock16(GMEM_MOVEABLE | GMEM_SHARE, HEAP16_TOTALSIZE,
  80. NULL);
  81. if (vpHeap16 != NULL) {
  82. //
  83. // Initialize heap header.
  84. // LATER: is this necessary?. Heaphdr is a static array so
  85. // is it already intialized to ZERO?
  86. //
  87. for(i = 0; i < HEAP16_BLOCKCOUNT ; i++) {
  88. vahdr[i] = 0;
  89. }
  90. }
  91. }
  92. if (vpHeap16 != (LPBYTE)NULL) {
  93. if (cb <= HEAP16_BLOCKSIZE && !ISBLOCKINUSE(vahdr[viFreeIndex])) {
  94. //
  95. // If 'single' block and the 'current' index is free.
  96. //
  97. vahdr[viFreeIndex] = HHDR16_FINUSE;
  98. i = viFreeIndex++;
  99. if (viFreeIndex == HEAP16_BLOCKCOUNT)
  100. viFreeIndex = 0;
  101. return (VPVOID)((LPBYTE)vpHeap16 + i * HEAP16_BLOCKSIZE);
  102. }
  103. else {
  104. //
  105. // if the 'current' index is not free or if 'multiple' blocks
  106. //
  107. cBlocksRequired = (cb / HEAP16_BLOCKSIZE) + 1;
  108. for (i = 0; i < HEAP16_BLOCKCOUNT ; i++ ) {
  109. if ((viFreeIndex + i + cBlocksRequired) <=
  110. HEAP16_BLOCKCOUNT) {
  111. fContiguousFreeBlocks = TRUE;
  112. for (j = 0; j < cBlocksRequired; j++) {
  113. if (ISBLOCKINUSE(vahdr[viFreeIndex + i + j])) {
  114. fContiguousFreeBlocks = FALSE;
  115. i += j;
  116. break;
  117. }
  118. }
  119. if (fContiguousFreeBlocks) {
  120. for (j = 0; j < (cBlocksRequired - 1); j++) {
  121. vahdr[viFreeIndex + i + j] =
  122. (HHDR16_FINUSE | HHDR16_FLINKED);
  123. }
  124. vahdr[viFreeIndex + i + j] = HHDR16_FINUSE;
  125. i += viFreeIndex;
  126. viFreeIndex = i + cBlocksRequired;
  127. if (viFreeIndex == HEAP16_BLOCKCOUNT)
  128. viFreeIndex = 0;
  129. return (VPVOID)((LPBYTE)vpHeap16 + i * HEAP16_BLOCKSIZE);
  130. }
  131. }
  132. else {
  133. //
  134. // Outside the heaphdr range. Reset viFreeIndex, so that
  135. // we search from the start of heaphdr.
  136. //
  137. viFreeIndex = -(i+1);
  138. }
  139. }
  140. viFreeIndex = 0;
  141. }
  142. }
  143. //
  144. // Here - if allocation from heap failed
  145. //
  146. vpT = (VPVOID)GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL);
  147. if (vpT) {
  148. return vpT;
  149. }
  150. else {
  151. LOGDEBUG(0,("malloc16: failed\n"));
  152. return (VPVOID)NULL;
  153. }
  154. }
  155. //*****************************************************************************
  156. //
  157. // free16 -
  158. //
  159. // frees 16bit memory block.
  160. // If the block is not part of the 16bit heap, does GlobalFree.
  161. //
  162. // Returns TRUE;
  163. //
  164. //*****************************************************************************
  165. BOOL FASTCALL free16(VPVOID vp)
  166. {
  167. INT iStartIndex;
  168. BOOL fLinked;
  169. iStartIndex = ((LPBYTE)vp - (LPBYTE)vpHeap16) / HEAP16_BLOCKSIZE;
  170. //
  171. // Invalid iStartIndex implies that the block was GlobalAlloced
  172. //
  173. if (iStartIndex >= 0 && iStartIndex < HEAP16_BLOCKCOUNT) {
  174. //
  175. // If 'single' block: get out fast
  176. // else 'multiple' block: loop for all the blocks
  177. //
  178. viFreeIndex = iStartIndex;
  179. if (!ISBLOCKLINKED(vahdr[iStartIndex])) {
  180. WOW32ASSERT(ISBLOCKINUSE(vahdr[iStartIndex]));
  181. vahdr[iStartIndex] = 0;
  182. }
  183. else {
  184. while (ISBLOCKINUSE(vahdr[iStartIndex])) {
  185. fLinked = ISBLOCKLINKED(vahdr[iStartIndex]);
  186. vahdr[iStartIndex] = 0;
  187. if (fLinked)
  188. iStartIndex++;
  189. else
  190. break;
  191. }
  192. }
  193. }
  194. else {
  195. WOW32ASSERT(LOWORD(vp)==0); // GlobalAlloced pointers have offset = 0
  196. GlobalUnlockFree16(vp);
  197. }
  198. return (BOOL)TRUE;
  199. }
  200. //*****************************************************************************
  201. //
  202. // stackalloc16 -
  203. //
  204. // Allocs memory from current task's 16bit stack.
  205. // Returns farpointer to memoryblock;
  206. //
  207. // NOTES!!!!!:
  208. // - This is not intended to be a full blown memory manager. It is intended to
  209. // replace the TDF_INITCALLBACKSTACKFLAG to avoid problems with ptd->vpCBStack
  210. // getting hosed by multiple stackalloc16 calls. (See bug #393267 et al)
  211. // - All calls to stackalloc16() and stackfree16() must be properly nested.
  212. // If you can't assure that your usage is properly nested, you'd better use
  213. // GlobalAllocLock16() & GlobalUnlockFree16() instead.
  214. // Beware individual message thunks may have calls to stackalloc16() that
  215. // aren't readily apparent.
  216. // - The request size passed to stackfree16() needs to be the same as the size
  217. // of the corresponding stackalloc16() call.
  218. // - Run your changes involving stackalloc16() under debug WOW32.DLL. The
  219. // built-in sanity checking will help you catch any gotcha's
  220. // - ptd->vpCBStack *SHOULD NOT* be referenced or used outside of stackalloc16()
  221. // stackfree16(), and callback16().
  222. // - If this mechanism gets out of whack, chances are the symptom will be
  223. // a 16-bit stack fault message.
  224. //*****************************************************************************
  225. VPVOID FASTCALL stackalloc16(UINT cb)
  226. {
  227. #ifdef DEBUG
  228. VPVOID vp;
  229. DWORD *psig, cb16;
  230. #endif
  231. register PTD ptd;
  232. // get current task's 16bit stack
  233. ptd = CURRENTPTD();
  234. #ifdef DEBUG
  235. // Save requested allocation size. Assume it will always be less than 64K
  236. cb16 = (DWORD)cb;
  237. // Add a dword (for signature) to the requested size
  238. cb += sizeof(DWORD);
  239. // Get the current callback sp
  240. if (ptd->cStackAlloc16 == 0) {
  241. vp = ptd->vpStack;
  242. } else {
  243. vp = ptd->vpCBStack;
  244. }
  245. #endif
  246. // grow ss:sp and return this imaginary pointer.
  247. if (ptd->cStackAlloc16 == 0) {
  248. ptd->vpCBStack = ptd->vpStack - cb;
  249. }
  250. else {
  251. ptd->vpCBStack -= cb;
  252. }
  253. #ifdef DEBUG
  254. // Slide our DWORD signature in after the allocated request
  255. vp -= sizeof(DWORD);
  256. GETVDMPTR(vp, sizeof(DWORD), psig);
  257. // The signature hiword is the offset (sp) we're returning.
  258. // The signature loword is the requested size.
  259. *psig = ((ptd->vpCBStack & 0x0000FFFF) << 16) | cb16;
  260. FLUSHVDMPTR(vp, sizeof(DWORD), psig);
  261. FREEVDMPTR(psig);
  262. #endif
  263. ptd->cStackAlloc16++;
  264. WOW32ASSERT((ptd->cStackAlloc16 >= 1));
  265. return (VPVOID)ptd->vpCBStack;
  266. }
  267. //*****************************************************************************
  268. //
  269. // StackFree16 -
  270. //
  271. // Decrements count of memory alloc'd by stackalloc16
  272. //
  273. // NOTES:
  274. // - This is #define'd as stackfree16(vp,cb) StackFree16(cb) in free builds
  275. // and stackfree16(vp,cb) StackFree16(vp, cb) in DEBUG builds (wcall16.h)
  276. // - See stackalloc16() NOTES above
  277. //
  278. //*****************************************************************************
  279. #ifdef DEBUG
  280. VOID FASTCALL StackFree16(VPVOID vp, UINT cb)
  281. #else
  282. VOID FASTCALL StackFree16(UINT cb)
  283. #endif
  284. {
  285. register PTD ptd;
  286. #ifdef DEBUG
  287. DWORD *psig, sig;
  288. // reconstruct what our signature should be
  289. sig = ((vp & 0x0000FFFFF) << 16) | cb;
  290. #endif
  291. ptd = CURRENTPTD();
  292. ptd->vpCBStack += cb;
  293. #ifdef DEBUG
  294. // vpCBStack should now be pointing at our signature.
  295. GETVDMPTR(ptd->vpCBStack, sizeof(DWORD), psig);
  296. // you are hitting this assertion for one of the following reasons:
  297. // - calls to stackalloc16() & stackfree16() are not properly nested
  298. // - the signature got overwritten
  299. // - somebody changed ptd->vpCBStack incorrectly
  300. WOW32ASSERTMSG((*psig == sig), ("WOW::StackFree16 out of synch!!\n"));
  301. // adjust for the signature DWORD we added to the request
  302. ptd->vpCBStack += sizeof(DWORD);
  303. #endif
  304. if(ptd->cStackAlloc16 > 0) {
  305. ptd->cStackAlloc16--;
  306. } else {
  307. WOW32ASSERTMSG((FALSE), ("WOW::StackFree16:cStackAlloc16 <= 0!\n"));
  308. ptd->cStackAlloc16 = 0; // if it was less than 0 somehow
  309. }
  310. }