windows-nt/Source/XPSP1/NT/base/mvdm/wow32/walloc16.c
2020-09-26 16:20:57 +08:00

376 lines
11 KiB
C

//*****************************************************************************
//
// MESSAGE HEAP 16 -
//
// Heap allocation functions for 32-16 message thunks.
//
// NOTE: these are NOT general purpose heap managment routines.
//
//
// 07-17-92 NanduriR Created.
//
//*****************************************************************************
#include "precomp.h"
#pragma hdrstop
MODNAME(walloc16.c);
//*****************************************************************************
// General Notes:
//
// This heap maanger is for specific 'performance gains' and is thus not
// intended for general purpose use and therfore much of the overhead has
// been eliminated.
//
// This heap manager is intended mainly for thunks - where we are sure that
// an alloced block will definitely be freed. Thus it is meant for our use.
//
// The heap is conceptually an array of constant-size blocks. The size of the
// block is predefined. The code is optimized for allocation requests of one
// blocksize or less. It is slower if the allocation request needs more than
// one block.
//
// The heap header is a static array. The header has two flags. One to note
// that a particular heapblock is in use and the other to note whether the
// block forms a part of a linked/chained set of contiguous blocks. The blocks
// are linked when the allocation request is for more than the predefined
// block size.
//
//*****************************************************************************
#define HEAP16_TOTALSIZE 0x2000
#define HEAP16_BLOCKSIZE 0x100 // We should set it to an optimum value
#define HEAP16_BLOCKCOUNT (HEAP16_TOTALSIZE/HEAP16_BLOCKSIZE)
#define HHDR16_FINUSE 0x01
#define HHDR16_FLINKED 0x02
#define ISBLOCKINUSE(block) ((block) & HHDR16_FINUSE)
#define ISBLOCKLINKED(block) ((block) & HHDR16_FLINKED)
//*****************************************************************************
//
// Globals -
//
// vahdr - is the heap header. This header is 32bit memory and not part of the
// 16bit heap - this is so that the 16bit heap is put to maximum use.
//
// vpHeap16 - far pointer to the start of 16bit heap
//
// viFreeIndex - the index from which we start searching for a freeblock.
// Normally this is set to the memoryblock that was most
// recently freed, thus increasing the chances of finding
// a freeblock instantly.
//*****************************************************************************
BYTE vahdr[HEAP16_BLOCKCOUNT];
LPBYTE vpHeap16 = (LPBYTE)NULL;
UINT viFreeIndex = 0; // First look for Free block here.
//*****************************************************************************
//
// malloc16 -
//
// Allocs memory from 16bit block.
// If heap is full, does normal GlobalAlloc
//
// Returns farpointer to memoryblock;
//
//*****************************************************************************
VPVOID FASTCALL malloc16(UINT cb)
{
INT i, j;
INT cBlocksRequired;
INT fContiguousFreeBlocks;
INT vpT;
if (vpHeap16 == (LPBYTE)NULL) {
vpHeap16 = (LPBYTE)GlobalAllocLock16(GMEM_MOVEABLE | GMEM_SHARE, HEAP16_TOTALSIZE,
NULL);
if (vpHeap16 != NULL) {
//
// Initialize heap header.
// LATER: is this necessary?. Heaphdr is a static array so
// is it already intialized to ZERO?
//
for(i = 0; i < HEAP16_BLOCKCOUNT ; i++) {
vahdr[i] = 0;
}
}
}
if (vpHeap16 != (LPBYTE)NULL) {
if (cb <= HEAP16_BLOCKSIZE && !ISBLOCKINUSE(vahdr[viFreeIndex])) {
//
// If 'single' block and the 'current' index is free.
//
vahdr[viFreeIndex] = HHDR16_FINUSE;
i = viFreeIndex++;
if (viFreeIndex == HEAP16_BLOCKCOUNT)
viFreeIndex = 0;
return (VPVOID)((LPBYTE)vpHeap16 + i * HEAP16_BLOCKSIZE);
}
else {
//
// if the 'current' index is not free or if 'multiple' blocks
//
cBlocksRequired = (cb / HEAP16_BLOCKSIZE) + 1;
for (i = 0; i < HEAP16_BLOCKCOUNT ; i++ ) {
if ((viFreeIndex + i + cBlocksRequired) <=
HEAP16_BLOCKCOUNT) {
fContiguousFreeBlocks = TRUE;
for (j = 0; j < cBlocksRequired; j++) {
if (ISBLOCKINUSE(vahdr[viFreeIndex + i + j])) {
fContiguousFreeBlocks = FALSE;
i += j;
break;
}
}
if (fContiguousFreeBlocks) {
for (j = 0; j < (cBlocksRequired - 1); j++) {
vahdr[viFreeIndex + i + j] =
(HHDR16_FINUSE | HHDR16_FLINKED);
}
vahdr[viFreeIndex + i + j] = HHDR16_FINUSE;
i += viFreeIndex;
viFreeIndex = i + cBlocksRequired;
if (viFreeIndex == HEAP16_BLOCKCOUNT)
viFreeIndex = 0;
return (VPVOID)((LPBYTE)vpHeap16 + i * HEAP16_BLOCKSIZE);
}
}
else {
//
// Outside the heaphdr range. Reset viFreeIndex, so that
// we search from the start of heaphdr.
//
viFreeIndex = -(i+1);
}
}
viFreeIndex = 0;
}
}
//
// Here - if allocation from heap failed
//
vpT = (VPVOID)GlobalAllocLock16(GMEM_MOVEABLE, cb, NULL);
if (vpT) {
return vpT;
}
else {
LOGDEBUG(0,("malloc16: failed\n"));
return (VPVOID)NULL;
}
}
//*****************************************************************************
//
// free16 -
//
// frees 16bit memory block.
// If the block is not part of the 16bit heap, does GlobalFree.
//
// Returns TRUE;
//
//*****************************************************************************
BOOL FASTCALL free16(VPVOID vp)
{
INT iStartIndex;
BOOL fLinked;
iStartIndex = ((LPBYTE)vp - (LPBYTE)vpHeap16) / HEAP16_BLOCKSIZE;
//
// Invalid iStartIndex implies that the block was GlobalAlloced
//
if (iStartIndex >= 0 && iStartIndex < HEAP16_BLOCKCOUNT) {
//
// If 'single' block: get out fast
// else 'multiple' block: loop for all the blocks
//
viFreeIndex = iStartIndex;
if (!ISBLOCKLINKED(vahdr[iStartIndex])) {
WOW32ASSERT(ISBLOCKINUSE(vahdr[iStartIndex]));
vahdr[iStartIndex] = 0;
}
else {
while (ISBLOCKINUSE(vahdr[iStartIndex])) {
fLinked = ISBLOCKLINKED(vahdr[iStartIndex]);
vahdr[iStartIndex] = 0;
if (fLinked)
iStartIndex++;
else
break;
}
}
}
else {
WOW32ASSERT(LOWORD(vp)==0); // GlobalAlloced pointers have offset = 0
GlobalUnlockFree16(vp);
}
return (BOOL)TRUE;
}
//*****************************************************************************
//
// stackalloc16 -
//
// Allocs memory from current task's 16bit stack.
// Returns farpointer to memoryblock;
//
// NOTES!!!!!:
// - This is not intended to be a full blown memory manager. It is intended to
// replace the TDF_INITCALLBACKSTACKFLAG to avoid problems with ptd->vpCBStack
// getting hosed by multiple stackalloc16 calls. (See bug #393267 et al)
// - All calls to stackalloc16() and stackfree16() must be properly nested.
// If you can't assure that your usage is properly nested, you'd better use
// GlobalAllocLock16() & GlobalUnlockFree16() instead.
// Beware individual message thunks may have calls to stackalloc16() that
// aren't readily apparent.
// - The request size passed to stackfree16() needs to be the same as the size
// of the corresponding stackalloc16() call.
// - Run your changes involving stackalloc16() under debug WOW32.DLL. The
// built-in sanity checking will help you catch any gotcha's
// - ptd->vpCBStack *SHOULD NOT* be referenced or used outside of stackalloc16()
// stackfree16(), and callback16().
// - If this mechanism gets out of whack, chances are the symptom will be
// a 16-bit stack fault message.
//*****************************************************************************
VPVOID FASTCALL stackalloc16(UINT cb)
{
#ifdef DEBUG
VPVOID vp;
DWORD *psig, cb16;
#endif
register PTD ptd;
// get current task's 16bit stack
ptd = CURRENTPTD();
#ifdef DEBUG
// Save requested allocation size. Assume it will always be less than 64K
cb16 = (DWORD)cb;
// Add a dword (for signature) to the requested size
cb += sizeof(DWORD);
// Get the current callback sp
if (ptd->cStackAlloc16 == 0) {
vp = ptd->vpStack;
} else {
vp = ptd->vpCBStack;
}
#endif
// grow ss:sp and return this imaginary pointer.
if (ptd->cStackAlloc16 == 0) {
ptd->vpCBStack = ptd->vpStack - cb;
}
else {
ptd->vpCBStack -= cb;
}
#ifdef DEBUG
// Slide our DWORD signature in after the allocated request
vp -= sizeof(DWORD);
GETVDMPTR(vp, sizeof(DWORD), psig);
// The signature hiword is the offset (sp) we're returning.
// The signature loword is the requested size.
*psig = ((ptd->vpCBStack & 0x0000FFFF) << 16) | cb16;
FLUSHVDMPTR(vp, sizeof(DWORD), psig);
FREEVDMPTR(psig);
#endif
ptd->cStackAlloc16++;
WOW32ASSERT((ptd->cStackAlloc16 >= 1));
return (VPVOID)ptd->vpCBStack;
}
//*****************************************************************************
//
// StackFree16 -
//
// Decrements count of memory alloc'd by stackalloc16
//
// NOTES:
// - This is #define'd as stackfree16(vp,cb) StackFree16(cb) in free builds
// and stackfree16(vp,cb) StackFree16(vp, cb) in DEBUG builds (wcall16.h)
// - See stackalloc16() NOTES above
//
//*****************************************************************************
#ifdef DEBUG
VOID FASTCALL StackFree16(VPVOID vp, UINT cb)
#else
VOID FASTCALL StackFree16(UINT cb)
#endif
{
register PTD ptd;
#ifdef DEBUG
DWORD *psig, sig;
// reconstruct what our signature should be
sig = ((vp & 0x0000FFFFF) << 16) | cb;
#endif
ptd = CURRENTPTD();
ptd->vpCBStack += cb;
#ifdef DEBUG
// vpCBStack should now be pointing at our signature.
GETVDMPTR(ptd->vpCBStack, sizeof(DWORD), psig);
// you are hitting this assertion for one of the following reasons:
// - calls to stackalloc16() & stackfree16() are not properly nested
// - the signature got overwritten
// - somebody changed ptd->vpCBStack incorrectly
WOW32ASSERTMSG((*psig == sig), ("WOW::StackFree16 out of synch!!\n"));
// adjust for the signature DWORD we added to the request
ptd->vpCBStack += sizeof(DWORD);
#endif
if(ptd->cStackAlloc16 > 0) {
ptd->cStackAlloc16--;
} else {
WOW32ASSERTMSG((FALSE), ("WOW::StackFree16:cStackAlloc16 <= 0!\n"));
ptd->cStackAlloc16 = 0; // if it was less than 0 somehow
}
}