#include "brfprv.h" //========== Memory Management ============================================= #ifndef WIN32 #define MAX_WORD 0xffff DECLARE_HANDLE(HHEAP); typedef struct { // maps to the bottom of a 16bit DS WORD reserved[8]; WORD cAlloc; WORD cbAllocFailed; HHEAP hhpFirst; HHEAP hhpNext; } HEAP; #define PHEAP(hhp) ((HEAP *)MAKELP(hhp, 0)) #define MAKEHP(sel, off) ((void _huge*)MAKELP((sel), (off))) #define CBSUBALLOCMAX 0x0000f000L HHEAP g_hhpFirst = NULL; BOOL DestroyHeap(HHEAP hhp); void Mem_Terminate() { while (g_hhpFirst) DestroyHeap(g_hhpFirst); } BOOL CreateHeap(WORD cbInitial) { HHEAP hhp; if (cbInitial < 1024) cbInitial = 1024; hhp = (HHEAP)GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_SHARE, cbInitial); if (!hhp) return FALSE; if (!LocalInit((WORD)hhp, sizeof(HEAP), cbInitial - 1)) { GlobalFree(hhp); return FALSE; } PHEAP(hhp)->cAlloc = 0; PHEAP(hhp)->cbAllocFailed = MAX_WORD; PHEAP(hhp)->hhpNext = g_hhpFirst; g_hhpFirst = hhp; DebugMsg(DM_TRACE, TEXT("CreateHeap: added new local heap %x"), hhp); return TRUE; } #pragma optimize("o", off) // linked list removals don't optimize correctly BOOL DestroyHeap(HHEAP hhp) { ASSERT(hhp); ASSERT(g_hhpFirst); if (g_hhpFirst == hhp) { g_hhpFirst = PHEAP(hhp)->hhpNext; } else { HHEAP hhpT = g_hhpFirst; while (PHEAP(hhpT)->hhpNext != hhp) { hhpT = PHEAP(hhpT)->hhpNext; if (!hhpT) return FALSE; } PHEAP(hhpT)->hhpNext = PHEAP(hhp)->hhpNext; } if (GlobalFree((HGLOBAL)hhp) != NULL) return FALSE; return TRUE; } #pragma optimize("", on) // back to default optimizations #pragma optimize("lge", off) // Suppress warnings associated with use of _asm... void * HeapAlloc(HHEAP hhp, WORD cb) { void * pb; _asm { push ds mov ds,hhp } pb = (void *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, cb); if (pb) ((HEAP *)0)->cAlloc++; _asm { pop ds } return pb; } #pragma optimize("o", off) // linked list removals don't optimize correctly void _huge* WINAPI SharedAlloc(long cb) { void * pb; HHEAP hhp; HHEAP hhpPrev; // If this is a big allocation, just do a global alloc. // if (cb > CBSUBALLOCMAX) { void * lpb = MAKEHP(GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT | GMEM_SHARE, cb), 0); if (!lpb) DebugMsg(DM_ERROR, TEXT("Alloc: out of memory")); return lpb; } hhp = g_hhpFirst; while (TRUE) { if (hhp == NULL) { if (!CreateHeap(0)) { DebugMsg(DM_ERROR, TEXT("Alloc: out of memory")); return NULL; } hhp = g_hhpFirst; } pb = HeapAlloc(hhp, (WORD)cb); if (pb) return MAKEHP(hhp, pb); // Record the size of the allocation that failed. // Later attempts to allocate more than this amount // will not succeed. This gets reset anytime anything // is freed in the heap. // PHEAP(hhp)->cbAllocFailed = (WORD)cb; // First heap is full... see if there's room in any other heap... // for (hhpPrev = hhp; hhp = PHEAP(hhp)->hhpNext; hhpPrev = hhp) { // If the last allocation to fail in this heap // is not larger than cb, don't even try an allocation. // if ((WORD)cb >= PHEAP(hhp)->cbAllocFailed) continue; pb = HeapAlloc(hhp, (WORD)cb); if (pb) { // This heap had room: move it to the front... // PHEAP(hhpPrev)->hhpNext = PHEAP(hhp)->hhpNext; PHEAP(hhp)->hhpNext = g_hhpFirst; g_hhpFirst = hhp; return MAKEHP(hhp, pb); } else { // The alloc failed. Set cbAllocFailed... // PHEAP(hhp)->cbAllocFailed = (WORD)cb; } } } } #pragma optimize("", on) // back to default optimizations #pragma optimize("lge", off) // Suppress warnings associated with use of _asm... void _huge* WINAPI SharedReAlloc(void _huge* pb, long cb) { void * pbNew; void _huge* lpbNew; UINT cbOld; // FEATURE, does not work with cb > 64k if (!pb) return SharedAlloc(cb); if (OFFSETOF(pb) == 0) return MAKEHP(GlobalReAlloc((HGLOBAL)SELECTOROF(pb), cb, GMEM_MOVEABLE | GMEM_ZEROINIT), 0); _asm { push ds mov ds,word ptr [pb+2] } pbNew = (void *)LocalReAlloc((HLOCAL)OFFSETOF(pb), (int)cb, LMEM_MOVEABLE | LMEM_ZEROINIT); if (!pbNew) cbOld = LocalSize((HLOCAL)OFFSETOF(pb)); _asm { pop ds } if (pbNew) return MAKEHP(SELECTOROF(pb), pbNew); lpbNew = SharedAlloc(cb); if (lpbNew) { hmemcpy((void *)lpbNew, (void *)pb, cbOld); Free(pb); } else { DebugMsg(DM_ERROR, TEXT("ReAlloc: out of memory")); } return lpbNew; } BOOL WINAPI SharedFree(void _huge* * ppb) { BOOL fSuccess; UINT cAlloc; void _huge * pb = *ppb; if (!pb) return FALSE; *ppb = 0; if (OFFSETOF(pb) == 0) return (GlobalFree((HGLOBAL)SELECTOROF(pb)) == NULL); _asm { push ds mov ds,word ptr [pb+2] } fSuccess = (LocalFree((HLOCAL)OFFSETOF(pb)) ? FALSE : TRUE); cAlloc = 1; if (fSuccess) { cAlloc = --((HEAP *)0)->cAlloc; ((HEAP *)0)->cbAllocFailed = MAX_WORD; } _asm { pop ds } if (cAlloc == 0) DestroyHeap((HHEAP)SELECTOROF(pb)); return fSuccess; } DWORD WINAPI SharedGetSize(void _huge* pb) { WORD wSize; if (OFFSETOF(pb) == 0) return GlobalSize((HGLOBAL)SELECTOROF(pb)); _asm { push ds mov ds,word ptr [pb+2] } wSize = LocalSize((HLOCAL)OFFSETOF(pb)); _asm { pop ds } return (DWORD)wSize; } #if 0 // hmemcpy() is faster (says davidds) void WINAPI MemCopy(void * pTo, const void * pFrom, UINT cb) { _asm { mov cx,cb jcxz mcexit ;; push si ;; push di mov dx,ds lds si,pFrom les di,pTo cmp si,di jae mccopyup mov ax,cx dec ax dec ax add si,ax add di,ax std shr cx,1 rep movsw jnc mc100 inc si inc di movsb mc100: cld jmp short mcexit mccopyup: cld shr cx,1 rep movsw jnc mc200 movsb mc200: mcexit: mov ds,dx ;; pop di ;; pop si } } #endif #pragma optimize("", on) #else // WIN32 // Define a Global Shared Heap that we use allocate memory out of that we // Need to share between multiple instances. HANDLE g_hSharedHeap = NULL; #define MAXHEAPSIZE 2097152 #define HEAP_SHARED 0x04000000 /* put heap in shared memory */ //---------------------------------------------------------------------------- void PUBLIC Mem_Terminate() { // Assuming that everything else has exited // if (g_hSharedHeap != NULL) HeapDestroy(g_hSharedHeap); g_hSharedHeap = NULL; } //---------------------------------------------------------------------------- void * WINAPI SharedAlloc(long cb) { // I will assume that this is the only one that needs the checks to // see if the heap has been previously created or not if (g_hSharedHeap == NULL) { ENTEREXCLUSIVE(); if (g_hSharedHeap == NULL) { g_hSharedHeap = HeapCreate(0, 1, MAXHEAPSIZE); } LEAVEEXCLUSIVE(); // If still NULL we have problems! if (g_hSharedHeap == NULL) return(NULL); } return HeapAlloc(g_hSharedHeap, HEAP_ZERO_MEMORY, cb); } //---------------------------------------------------------------------------- void * WINAPI SharedReAlloc(void * pb, long cb) { if (pb==NULL) { return SharedAlloc(cb); } return HeapReAlloc(g_hSharedHeap, HEAP_ZERO_MEMORY, pb, cb); } //---------------------------------------------------------------------------- BOOL WINAPI SharedFree(void ** ppb) { void * pb = *ppb; if (!pb) return FALSE; *ppb = 0; return HeapFree(g_hSharedHeap, 0, pb); } //---------------------------------------------------------------------------- DWORD WINAPI SharedGetSize(void * pb) { return (DWORD)HeapSize(g_hSharedHeap, 0, pb); } //---------------------------------------------------------------------------- // The following functions are for debug only and are used to try to // calculate memory usage. // #ifdef DEBUG typedef struct _HEAPTRACE { DWORD cAlloc; DWORD cFailure; DWORD cReAlloc; DWORD cbMaxTotal; DWORD cCurAlloc; DWORD cbCurTotal; } HEAPTRACE; HEAPTRACE g_htSync = {0}; // Start of zero... LPVOID WINAPI MemAlloc(HANDLE hheap, DWORD cb) { LPVOID lp; lp = HeapAlloc(hheap, HEAP_ZERO_MEMORY, cb); if (lp == NULL) { g_htSync.cFailure++; return NULL; } // Update counts. g_htSync.cAlloc++; g_htSync.cCurAlloc++; g_htSync.cbCurTotal += cb; if (g_htSync.cbCurTotal > g_htSync.cbMaxTotal) g_htSync.cbMaxTotal = g_htSync.cbCurTotal; return lp; } LPVOID WINAPI MemReAlloc(HANDLE hheap, LPVOID pb, DWORD cb) { LPVOID lp; DWORD cbOld; cbOld = HeapSize(hheap, 0, pb); lp = HeapReAlloc(hheap, HEAP_ZERO_MEMORY, pb,cb); if (lp == NULL) { g_htSync.cFailure++; return NULL; } // Update counts. g_htSync.cReAlloc++; g_htSync.cbCurTotal += cb - cbOld; if (g_htSync.cbCurTotal > g_htSync.cbMaxTotal) g_htSync.cbMaxTotal = g_htSync.cbCurTotal; return lp; } BOOL WINAPI MemFree(HANDLE hheap, LPVOID pb) { BOOL fRet; DWORD cbOld; cbOld = HeapSize(hheap, 0, pb); fRet = HeapFree(hheap, 0, pb); if (fRet) { // Update counts. g_htSync.cCurAlloc--; g_htSync.cbCurTotal -= cbOld; } return(fRet); } DWORD WINAPI MemSize(HANDLE hheap, LPVOID pb) { return HeapSize(hheap, 0, pb); } #endif #endif // WIN32