/* Copyright (c) Microsoft Corporation. All rights reserved. */ #define OPTIMIZE /* enable Base.h optimizations, since we're the "base" */ #include <mmlite.h> #include <stdio.h> #include <assert.h> #include <string.h> //#include <machdep.h> // #include "xxx.h" /* for CurrentHeapDelayedFree */ // #include "optims.h" #include "heap.h" #include <s_NullHeap_v.c> #include <s_NullHeapFactory_v.c> #define DPRINT(x) #define EPRINT(x) /* Minimal heap. * */ #if _UINTSIZE == 16 #define HB_ALIGN 4 /* Allocation alignment */ #else #define HB_ALIGN 8 /* Allocation alignment */ #endif #define HB_ROUNDOFF (HB_ALIGN-1) /* Used to round up allocation size */ typedef struct { ADDR_SIZE Reserve; /* amount of address space reserved for the heap */ ADDR_SIZE Used; /* of that, how much is actually allocated */ ADDR_SIZE Avail; /* ..and how much is left free. */ } HEAP_STATUS; /* Heap header */ typedef struct _HEAPINFO { /* Per-heap information */ const struct IHeapVtbl *Vtbl; /* Reserved for IHEAP vtbl */ UINT Refs; /* Number of references */ UINT Flags; /* Passed to CreatHeap */ MUTEX Mx; /* Serialize access to the heap. */ HEAP_STATUS Status; /* Reserve, Commit, etc fields */ } HEAPINFO, *PHEAPINFO; #define pHP(pHeap) ((PHEAPINFO)(pHeap)) #ifdef _MSC_VER #pragma warning(disable:4127) /* conditional expression is constant */ #pragma warning(disable:4702) /* unreachable code */ #endif #define IncUsedCnt(_phi_,_size_) \ { \ (_phi_)->Status.Used += (_size_); \ (_phi_)->Status.Avail -= (_size_); \ } /* Lock/Unlock functions */ #define LockHeap(_phi_,_Flags_) \ { \ if (!((_Flags_) & HEAP_NO_SERIALIZE)) \ Mutex_Lock(&(_phi_)->Mx); \ } #define UnlockHeap(_phi_,_Flags_) \ { \ if (!((_Flags_) & HEAP_NO_SERIALIZE)) \ Mutex_Unlock(&(_phi_)->Mx); \ } /* *** HPAlloc * * Allocates a heap block of at least Size bytes from the heap pointed * by pHeap. If Flags contains HEAP_ZERO_MEMORY also zero fills the new block. * Returns pointer to the block of memory, NULL if error. */ PRIVATE PTR MCT HPAlloc(IHeap *pHeap, UINT Flags, UINT Size, UINT Alignment) { PHEAPINFO phi; BYTE *pMem = NULL; SCODE Error; UINT Frag; if (Flags & HEAP_CACHE_ALIGN) Alignment = _DCACHELINESIZE; if (Alignment > 1) { /* Check that it is a power of two */ if ((Alignment-1) & Alignment) { Error = E_INVALID_PARAMETER; goto ErrorExit; } } if (Alignment < HB_ALIGN) Alignment = HB_ALIGN; DPRINT(("HPAlloc: pHeap %x, Flags %x, Size %x\n", (UINT) pHeap, Flags, Size)); phi = (PHEAPINFO) pHeap; Flags |= phi->Flags; /* Might need cache-aligned buffer. Calculate minimum amount of * memory to allocate, assuming ideal alignment of free block. */ Size = ((Size + (Alignment-1)) & ~(Alignment-1)); /* Lock heap if necessary */ LockHeap(phi, Flags); /* See if the proposed pointer is suitably aligned * NB: This knows the heap is contig with descriptor. */ pMem = ((BYTE*)phi) + phi->Status.Used; Frag = (((ADDRESS)pMem) & (Alignment-1)); if (Frag) { /* Nope, roundup. */ Frag = Alignment - Frag; Size += Frag; pMem += Frag; } /* Do we have room for it. */ if (Size <= phi->Status.Avail) { /* Yes, record this allocation; */ IncUsedCnt(phi,Size); Error = NO_ERROR; } else { Error = E_NOT_ENOUGH_MEMORY; pMem = NULL; } /* Let lock go iff. */ UnlockHeap(phi, Flags); /* Done, one way or the other. */ ErrorExit: return (PTR) pMem; } /* *** HPStatus * * Returns status information about this heap. */ PRIVATE SCODE MCT HPStatus(IHeap *pHeap, ADDR_SIZE *pReserve, ADDR_SIZE *pCommit, ADDR_SIZE *pUsed, ADDR_SIZE *pMaxUsed) { PHEAPINFO phi; phi = (PHEAPINFO) pHeap; if (pReserve) *pReserve = phi->Status.Reserve; if (pCommit) *pCommit = phi->Status.Reserve; if (pUsed) *pUsed = phi->Status.Used; if (pMaxUsed) { *pMaxUsed = phi->Status.Used; } return NO_ERROR; } /* *** Constructor: HeapCreate * * Creates heap from a block of memory. pmem points to a block of memory * in the appropriate address space to be used. InitSize is the number of * bytes already commited at the beginning of memory block. MaxSize is * total number of bytes in memory block. Flags passes HEAP_ZERO_MEMORY etc. * Returns pointer to the heap, NULL if failed. * */ SCODE NHCCreate( PIHEAPFACTORY iThis, ADDRESS Mem, UINT Flags, UINT InitSize, UINT MaxSize, /*out*/ PIHEAP *ppHeap) { PHEAPINFO phi; SCODE Error = E_INVALID_PARAMETER; DPRINT(("Enter CreatHeap Mem %08x, InitSize %08x, MaxSize %08x, Flags %08x\n",Mem,InitSize,MaxSize,Flags)); assert(Mem != 0); /* On some machines this might be ok..but slow */ assert((Mem & (sizeof(void *) - 1)) == 0); /* Calculate overhead, no point creating a useless heap. */ #define MinHeapSize (sizeof(HEAPINFO) + HB_ALIGN) /* Make sure the block passed in is big enough to hold a heap, * committed size less or equal reserved size. */ if ((MaxSize < MinHeapSize) || (MaxSize < InitSize)) { /* Reserved block too small or * commit size greater then reserved size. */ goto ErrorExit; } #undef MinHeapSize /* Initialize HEAPINFO structure (per-heap information). */ phi = (PHEAPINFO) Mem; phi->Vtbl = &NullHeapVtbl; phi->Refs = 1; phi->Flags = Flags; phi->Status.Reserve = MaxSize; phi->Status.Used = sizeof(HEAPINFO); phi->Status.Avail = MaxSize - sizeof(HEAPINFO); Mutex_Init(&phi->Mx); DPRINT(("Exit CreatHeap\n")); *ppHeap = (PIHEAP) phi; return S_OK; ErrorExit: EPRINT(("Error exit CreatHeap\n")); return E_FAIL; } /* * Exported methods */ PRIVATE UINT MCT HPAddRef(PIHEAP pThis) { PHEAPINFO phi = (PHEAPINFO) pThis; return AtomicInc(&phi->Refs); } PRIVATE UINT MCT HPRelease(PIHEAP pThis) { PHEAPINFO phi = (PHEAPINFO) pThis; UINT newrefs; PIHEAP cur = CurrentHeap(); newrefs = AtomicDec(&phi->Refs); if (newrefs == 0 && pThis != cur) { cur->v->Free(cur,0,pThis); } return newrefs; } PRIVATE SCODE MCT HPQueryInterface(PIHEAP pThis, REFIID pIid, void* *ppUnk) { return GenericQueryInterface((IUnknown *)pThis,pIid,ppUnk,&IID_IHeap); } PRIVATE struct HEAPCOB NullHeapCobObject = { &NullHeapFactoryVtbl, 1 }; PIUNKNOWN NullHeapCobMain(void) { return (PIUNKNOWN) &NullHeapCobObject; }