Divide libcox by Symisc into smaller logical chunks
This commit is contained in:
825
engine/lib/memory.c
Normal file
825
engine/lib/memory.c
Normal file
@@ -0,0 +1,825 @@
|
||||
#include "ph7int.h"
|
||||
|
||||
PH7_PRIVATE void SyZero(void *pSrc, sxu32 nSize) {
|
||||
register unsigned char *zSrc = (unsigned char *)pSrc;
|
||||
unsigned char *zEnd;
|
||||
#if defined(UNTRUST)
|
||||
if(zSrc == 0 || nSize <= 0) {
|
||||
return ;
|
||||
}
|
||||
#endif
|
||||
zEnd = &zSrc[nSize];
|
||||
for(;;) {
|
||||
if(zSrc >= zEnd) {
|
||||
break;
|
||||
}
|
||||
zSrc[0] = 0;
|
||||
zSrc++;
|
||||
if(zSrc >= zEnd) {
|
||||
break;
|
||||
}
|
||||
zSrc[0] = 0;
|
||||
zSrc++;
|
||||
if(zSrc >= zEnd) {
|
||||
break;
|
||||
}
|
||||
zSrc[0] = 0;
|
||||
zSrc++;
|
||||
if(zSrc >= zEnd) {
|
||||
break;
|
||||
}
|
||||
zSrc[0] = 0;
|
||||
zSrc++;
|
||||
}
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyMemcmp(const void *pB1, const void *pB2, sxu32 nSize) {
|
||||
sxi32 rc;
|
||||
if(nSize <= 0) {
|
||||
return 0;
|
||||
}
|
||||
if(pB1 == 0 || pB2 == 0) {
|
||||
return pB1 != 0 ? 1 : (pB2 == 0 ? 0 : -1);
|
||||
}
|
||||
SX_MACRO_FAST_CMP(pB1, pB2, nSize, rc);
|
||||
return rc;
|
||||
}
|
||||
PH7_PRIVATE sxu32 SyMemcpy(const void *pSrc, void *pDest, sxu32 nLen) {
|
||||
#if defined(UNTRUST)
|
||||
if(pSrc == 0 || pDest == 0) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if(pSrc == (const void *)pDest) {
|
||||
return nLen;
|
||||
}
|
||||
SX_MACRO_FAST_MEMCPY(pSrc, pDest, nLen);
|
||||
return nLen;
|
||||
}
|
||||
static void *MemOSAlloc(sxu32 nBytes) {
|
||||
sxu32 *pChunk;
|
||||
pChunk = (sxu32 *)SyOSHeapAlloc(nBytes + sizeof(sxu32));
|
||||
if(pChunk == 0) {
|
||||
return 0;
|
||||
}
|
||||
pChunk[0] = nBytes;
|
||||
return (void *)&pChunk[1];
|
||||
}
|
||||
static void *MemOSRealloc(void *pOld, sxu32 nBytes) {
|
||||
sxu32 *pOldChunk;
|
||||
sxu32 *pChunk;
|
||||
pOldChunk = (sxu32 *)(((char *)pOld) - sizeof(sxu32));
|
||||
if(pOldChunk[0] >= nBytes) {
|
||||
return pOld;
|
||||
}
|
||||
pChunk = (sxu32 *)SyOSHeapRealloc(pOldChunk, nBytes + sizeof(sxu32));
|
||||
if(pChunk == 0) {
|
||||
return 0;
|
||||
}
|
||||
pChunk[0] = nBytes;
|
||||
return (void *)&pChunk[1];
|
||||
}
|
||||
static void MemOSFree(void *pBlock) {
|
||||
void *pChunk;
|
||||
pChunk = (void *)(((char *)pBlock) - sizeof(sxu32));
|
||||
SyOSHeapFree(pChunk);
|
||||
}
|
||||
static sxu32 MemOSChunkSize(void *pBlock) {
|
||||
sxu32 *pChunk;
|
||||
pChunk = (sxu32 *)(((char *)pBlock) - sizeof(sxu32));
|
||||
return pChunk[0];
|
||||
}
|
||||
/* Export OS allocation methods */
|
||||
static const SyMemMethods sOSAllocMethods = {
|
||||
MemOSAlloc,
|
||||
MemOSRealloc,
|
||||
MemOSFree,
|
||||
MemOSChunkSize,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
static void *MemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte) {
|
||||
SyMemBlock *pBlock;
|
||||
sxi32 nRetry = 0;
|
||||
/* Append an extra block so we can tracks allocated chunks and avoid memory
|
||||
* leaks.
|
||||
*/
|
||||
nByte += sizeof(SyMemBlock);
|
||||
for(;;) {
|
||||
pBlock = (SyMemBlock *)pBackend->pMethods->xAlloc(nByte);
|
||||
if(pBlock != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY
|
||||
|| SXERR_RETRY != pBackend->xMemError(pBackend->pUserData)) {
|
||||
break;
|
||||
}
|
||||
nRetry++;
|
||||
}
|
||||
if(pBlock == 0) {
|
||||
return 0;
|
||||
}
|
||||
pBlock->pNext = pBlock->pPrev = 0;
|
||||
/* Link to the list of already tracked blocks */
|
||||
MACRO_LD_PUSH(pBackend->pBlocks, pBlock);
|
||||
#if defined(UNTRUST)
|
||||
pBlock->nGuard = SXMEM_BACKEND_MAGIC;
|
||||
#endif
|
||||
pBackend->nBlock++;
|
||||
return (void *)&pBlock[1];
|
||||
}
|
||||
PH7_PRIVATE void *SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte) {
|
||||
void *pChunk;
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
pChunk = MemBackendAlloc(&(*pBackend), nByte);
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
return pChunk;
|
||||
}
|
||||
static void *MemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nByte) {
|
||||
SyMemBlock *pBlock, *pNew, *pPrev, *pNext;
|
||||
sxu32 nRetry = 0;
|
||||
if(pOld == 0) {
|
||||
return MemBackendAlloc(&(*pBackend), nByte);
|
||||
}
|
||||
pBlock = (SyMemBlock *)(((char *)pOld) - sizeof(SyMemBlock));
|
||||
#if defined(UNTRUST)
|
||||
if(pBlock->nGuard != SXMEM_BACKEND_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
nByte += sizeof(SyMemBlock);
|
||||
pPrev = pBlock->pPrev;
|
||||
pNext = pBlock->pNext;
|
||||
for(;;) {
|
||||
pNew = (SyMemBlock *)pBackend->pMethods->xRealloc(pBlock, nByte);
|
||||
if(pNew != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY ||
|
||||
SXERR_RETRY != pBackend->xMemError(pBackend->pUserData)) {
|
||||
break;
|
||||
}
|
||||
nRetry++;
|
||||
}
|
||||
if(pNew == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(pNew != pBlock) {
|
||||
if(pPrev == 0) {
|
||||
pBackend->pBlocks = pNew;
|
||||
} else {
|
||||
pPrev->pNext = pNew;
|
||||
}
|
||||
if(pNext) {
|
||||
pNext->pPrev = pNew;
|
||||
}
|
||||
#if defined(UNTRUST)
|
||||
pNew->nGuard = SXMEM_BACKEND_MAGIC;
|
||||
#endif
|
||||
}
|
||||
return (void *)&pNew[1];
|
||||
}
|
||||
PH7_PRIVATE void *SyMemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nByte) {
|
||||
void *pChunk;
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
pChunk = MemBackendRealloc(&(*pBackend), pOld, nByte);
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
return pChunk;
|
||||
}
|
||||
static sxi32 MemBackendFree(SyMemBackend *pBackend, void *pChunk) {
|
||||
SyMemBlock *pBlock;
|
||||
pBlock = (SyMemBlock *)(((char *)pChunk) - sizeof(SyMemBlock));
|
||||
#if defined(UNTRUST)
|
||||
if(pBlock->nGuard != SXMEM_BACKEND_MAGIC) {
|
||||
return SXERR_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
/* Unlink from the list of active blocks */
|
||||
if(pBackend->nBlock > 0) {
|
||||
/* Release the block */
|
||||
#if defined(UNTRUST)
|
||||
/* Mark as stale block */
|
||||
pBlock->nGuard = 0x635B;
|
||||
#endif
|
||||
MACRO_LD_REMOVE(pBackend->pBlocks, pBlock);
|
||||
pBackend->nBlock--;
|
||||
pBackend->pMethods->xFree(pBlock);
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyMemBackendFree(SyMemBackend *pBackend, void *pChunk) {
|
||||
sxi32 rc;
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend)) {
|
||||
return SXERR_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
if(pChunk == 0) {
|
||||
return SXRET_OK;
|
||||
}
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
rc = MemBackendFree(&(*pBackend), pChunk);
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#if defined(PH7_ENABLE_THREADS)
|
||||
PH7_PRIVATE sxi32 SyMemBackendMakeThreadSafe(SyMemBackend *pBackend, const SyMutexMethods *pMethods) {
|
||||
SyMutex *pMutex;
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend) || pMethods == 0 || pMethods->xNew == 0) {
|
||||
return SXERR_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST);
|
||||
if(pMutex == 0) {
|
||||
return SXERR_OS;
|
||||
}
|
||||
/* Attach the mutex to the memory backend */
|
||||
pBackend->pMutex = pMutex;
|
||||
pBackend->pMutexMethods = pMethods;
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyMemBackendDisbaleMutexing(SyMemBackend *pBackend) {
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend)) {
|
||||
return SXERR_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
if(pBackend->pMutex == 0) {
|
||||
/* There is no mutex subsystem at all */
|
||||
return SXRET_OK;
|
||||
}
|
||||
SyMutexRelease(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
pBackend->pMutexMethods = 0;
|
||||
pBackend->pMutex = 0;
|
||||
return SXRET_OK;
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* Memory pool allocator
|
||||
*/
|
||||
#define SXMEM_POOL_MAGIC 0xDEAD
|
||||
#define SXMEM_POOL_MAXALLOC (1<<(SXMEM_POOL_NBUCKETS+SXMEM_POOL_INCR))
|
||||
#define SXMEM_POOL_MINALLOC (1<<(SXMEM_POOL_INCR))
|
||||
static sxi32 MemPoolBucketAlloc(SyMemBackend *pBackend, sxu32 nBucket) {
|
||||
char *zBucket, *zBucketEnd;
|
||||
SyMemHeader *pHeader;
|
||||
sxu32 nBucketSize;
|
||||
/* Allocate one big block first */
|
||||
zBucket = (char *)MemBackendAlloc(&(*pBackend), SXMEM_POOL_MAXALLOC);
|
||||
if(zBucket == 0) {
|
||||
return SXERR_MEM;
|
||||
}
|
||||
zBucketEnd = &zBucket[SXMEM_POOL_MAXALLOC];
|
||||
/* Divide the big block into mini bucket pool */
|
||||
nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
|
||||
pBackend->apPool[nBucket] = pHeader = (SyMemHeader *)zBucket;
|
||||
for(;;) {
|
||||
if(&zBucket[nBucketSize] >= zBucketEnd) {
|
||||
break;
|
||||
}
|
||||
pHeader->pNext = (SyMemHeader *)&zBucket[nBucketSize];
|
||||
/* Advance the cursor to the next available chunk */
|
||||
pHeader = pHeader->pNext;
|
||||
zBucket += nBucketSize;
|
||||
}
|
||||
pHeader->pNext = 0;
|
||||
return SXRET_OK;
|
||||
}
|
||||
static void *MemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte) {
|
||||
SyMemHeader *pBucket, *pNext;
|
||||
sxu32 nBucketSize;
|
||||
sxu32 nBucket;
|
||||
if(nByte + sizeof(SyMemHeader) >= SXMEM_POOL_MAXALLOC) {
|
||||
/* Allocate a big chunk directly */
|
||||
pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend), nByte + sizeof(SyMemHeader));
|
||||
if(pBucket == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* Record as big block */
|
||||
pBucket->nBucket = (sxu32)(SXMEM_POOL_MAGIC << 16) | SXU16_HIGH;
|
||||
return (void *)(pBucket + 1);
|
||||
}
|
||||
/* Locate the appropriate bucket */
|
||||
nBucket = 0;
|
||||
nBucketSize = SXMEM_POOL_MINALLOC;
|
||||
while(nByte + sizeof(SyMemHeader) > nBucketSize) {
|
||||
nBucketSize <<= 1;
|
||||
nBucket++;
|
||||
}
|
||||
pBucket = pBackend->apPool[nBucket];
|
||||
if(pBucket == 0) {
|
||||
sxi32 rc;
|
||||
rc = MemPoolBucketAlloc(&(*pBackend), nBucket);
|
||||
if(rc != SXRET_OK) {
|
||||
return 0;
|
||||
}
|
||||
pBucket = pBackend->apPool[nBucket];
|
||||
}
|
||||
/* Remove from the free list */
|
||||
pNext = pBucket->pNext;
|
||||
pBackend->apPool[nBucket] = pNext;
|
||||
/* Record bucket&magic number */
|
||||
pBucket->nBucket = (SXMEM_POOL_MAGIC << 16) | nBucket;
|
||||
return (void *)&pBucket[1];
|
||||
}
|
||||
PH7_PRIVATE void *SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte) {
|
||||
void *pChunk;
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
pChunk = MemBackendPoolAlloc(&(*pBackend), nByte);
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
return pChunk;
|
||||
}
|
||||
static sxi32 MemBackendPoolFree(SyMemBackend *pBackend, void *pChunk) {
|
||||
SyMemHeader *pHeader;
|
||||
sxu32 nBucket;
|
||||
/* Get the corresponding bucket */
|
||||
pHeader = (SyMemHeader *)(((char *)pChunk) - sizeof(SyMemHeader));
|
||||
/* Sanity check to avoid misuse */
|
||||
if((pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC) {
|
||||
return SXERR_CORRUPT;
|
||||
}
|
||||
nBucket = pHeader->nBucket & 0xFFFF;
|
||||
if(nBucket == SXU16_HIGH) {
|
||||
/* Free the big block */
|
||||
MemBackendFree(&(*pBackend), pHeader);
|
||||
} else {
|
||||
/* Return to the free list */
|
||||
pHeader->pNext = pBackend->apPool[nBucket & 0x0f];
|
||||
pBackend->apPool[nBucket & 0x0f] = pHeader;
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyMemBackendPoolFree(SyMemBackend *pBackend, void *pChunk) {
|
||||
sxi32 rc;
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend) || pChunk == 0) {
|
||||
return SXERR_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
rc = MemBackendPoolFree(&(*pBackend), pChunk);
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#if 0
|
||||
static void *MemBackendPoolRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nByte) {
|
||||
sxu32 nBucket, nBucketSize;
|
||||
SyMemHeader *pHeader;
|
||||
void *pNew;
|
||||
if(pOld == 0) {
|
||||
/* Allocate a new pool */
|
||||
pNew = MemBackendPoolAlloc(&(*pBackend), nByte);
|
||||
return pNew;
|
||||
}
|
||||
/* Get the corresponding bucket */
|
||||
pHeader = (SyMemHeader *)(((char *)pOld) - sizeof(SyMemHeader));
|
||||
/* Sanity check to avoid misuse */
|
||||
if((pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC) {
|
||||
return 0;
|
||||
}
|
||||
nBucket = pHeader->nBucket & 0xFFFF;
|
||||
if(nBucket == SXU16_HIGH) {
|
||||
/* Big block */
|
||||
return MemBackendRealloc(&(*pBackend), pHeader, nByte);
|
||||
}
|
||||
nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR);
|
||||
if(nBucketSize >= nByte + sizeof(SyMemHeader)) {
|
||||
/* The old bucket can honor the requested size */
|
||||
return pOld;
|
||||
}
|
||||
/* Allocate a new pool */
|
||||
pNew = MemBackendPoolAlloc(&(*pBackend), nByte);
|
||||
if(pNew == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* Copy the old data into the new block */
|
||||
SyMemcpy(pOld, pNew, nBucketSize);
|
||||
/* Free the stale block */
|
||||
MemBackendPoolFree(&(*pBackend), pOld);
|
||||
return pNew;
|
||||
}
|
||||
PH7_PRIVATE void *SyMemBackendPoolRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nByte) {
|
||||
void *pChunk;
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
pChunk = MemBackendPoolRealloc(&(*pBackend), pOld, nByte);
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
return pChunk;
|
||||
}
|
||||
#endif
|
||||
PH7_PRIVATE sxi32 SyMemBackendInit(SyMemBackend *pBackend, ProcMemError xMemErr, void *pUserData) {
|
||||
#if defined(UNTRUST)
|
||||
if(pBackend == 0) {
|
||||
return SXERR_EMPTY;
|
||||
}
|
||||
#endif
|
||||
/* Zero the allocator first */
|
||||
SyZero(&(*pBackend), sizeof(SyMemBackend));
|
||||
pBackend->xMemError = xMemErr;
|
||||
pBackend->pUserData = pUserData;
|
||||
/* Switch to the OS memory allocator */
|
||||
pBackend->pMethods = &sOSAllocMethods;
|
||||
if(pBackend->pMethods->xInit) {
|
||||
/* Initialize the backend */
|
||||
if(SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData)) {
|
||||
return SXERR_ABORT;
|
||||
}
|
||||
}
|
||||
#if defined(UNTRUST)
|
||||
pBackend->nMagic = SXMEM_BACKEND_MAGIC;
|
||||
#endif
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyMemBackendInitFromOthers(SyMemBackend *pBackend, const SyMemMethods *pMethods, ProcMemError xMemErr, void *pUserData) {
|
||||
#if defined(UNTRUST)
|
||||
if(pBackend == 0 || pMethods == 0) {
|
||||
return SXERR_EMPTY;
|
||||
}
|
||||
#endif
|
||||
if(pMethods->xAlloc == 0 || pMethods->xRealloc == 0 || pMethods->xFree == 0 || pMethods->xChunkSize == 0) {
|
||||
/* mandatory methods are missing */
|
||||
return SXERR_INVALID;
|
||||
}
|
||||
/* Zero the allocator first */
|
||||
SyZero(&(*pBackend), sizeof(SyMemBackend));
|
||||
pBackend->xMemError = xMemErr;
|
||||
pBackend->pUserData = pUserData;
|
||||
/* Switch to the host application memory allocator */
|
||||
pBackend->pMethods = pMethods;
|
||||
if(pBackend->pMethods->xInit) {
|
||||
/* Initialize the backend */
|
||||
if(SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData)) {
|
||||
return SXERR_ABORT;
|
||||
}
|
||||
}
|
||||
#if defined(UNTRUST)
|
||||
pBackend->nMagic = SXMEM_BACKEND_MAGIC;
|
||||
#endif
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyMemBackendInitFromParent(SyMemBackend *pBackend, SyMemBackend *pParent) {
|
||||
sxu8 bInheritMutex;
|
||||
#if defined(UNTRUST)
|
||||
if(pBackend == 0 || SXMEM_BACKEND_CORRUPT(pParent)) {
|
||||
return SXERR_CORRUPT;
|
||||
}
|
||||
#endif
|
||||
/* Zero the allocator first */
|
||||
SyZero(&(*pBackend), sizeof(SyMemBackend));
|
||||
pBackend->pMethods = pParent->pMethods;
|
||||
pBackend->xMemError = pParent->xMemError;
|
||||
pBackend->pUserData = pParent->pUserData;
|
||||
bInheritMutex = pParent->pMutexMethods ? TRUE : FALSE;
|
||||
if(bInheritMutex) {
|
||||
pBackend->pMutexMethods = pParent->pMutexMethods;
|
||||
/* Create a private mutex */
|
||||
pBackend->pMutex = pBackend->pMutexMethods->xNew(SXMUTEX_TYPE_FAST);
|
||||
if(pBackend->pMutex == 0) {
|
||||
return SXERR_OS;
|
||||
}
|
||||
}
|
||||
#if defined(UNTRUST)
|
||||
pBackend->nMagic = SXMEM_BACKEND_MAGIC;
|
||||
#endif
|
||||
return SXRET_OK;
|
||||
}
|
||||
static sxi32 MemBackendRelease(SyMemBackend *pBackend) {
|
||||
SyMemBlock *pBlock, *pNext;
|
||||
pBlock = pBackend->pBlocks;
|
||||
for(;;) {
|
||||
if(pBackend->nBlock == 0) {
|
||||
break;
|
||||
}
|
||||
pNext = pBlock->pNext;
|
||||
pBackend->pMethods->xFree(pBlock);
|
||||
pBlock = pNext;
|
||||
pBackend->nBlock--;
|
||||
/* LOOP ONE */
|
||||
if(pBackend->nBlock == 0) {
|
||||
break;
|
||||
}
|
||||
pNext = pBlock->pNext;
|
||||
pBackend->pMethods->xFree(pBlock);
|
||||
pBlock = pNext;
|
||||
pBackend->nBlock--;
|
||||
/* LOOP TWO */
|
||||
if(pBackend->nBlock == 0) {
|
||||
break;
|
||||
}
|
||||
pNext = pBlock->pNext;
|
||||
pBackend->pMethods->xFree(pBlock);
|
||||
pBlock = pNext;
|
||||
pBackend->nBlock--;
|
||||
/* LOOP THREE */
|
||||
if(pBackend->nBlock == 0) {
|
||||
break;
|
||||
}
|
||||
pNext = pBlock->pNext;
|
||||
pBackend->pMethods->xFree(pBlock);
|
||||
pBlock = pNext;
|
||||
pBackend->nBlock--;
|
||||
/* LOOP FOUR */
|
||||
}
|
||||
if(pBackend->pMethods->xRelease) {
|
||||
pBackend->pMethods->xRelease(pBackend->pMethods->pUserData);
|
||||
}
|
||||
pBackend->pMethods = 0;
|
||||
pBackend->pBlocks = 0;
|
||||
#if defined(UNTRUST)
|
||||
pBackend->nMagic = 0x2626;
|
||||
#endif
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyMemBackendRelease(SyMemBackend *pBackend) {
|
||||
sxi32 rc;
|
||||
#if defined(UNTRUST)
|
||||
if(SXMEM_BACKEND_CORRUPT(pBackend)) {
|
||||
return SXERR_INVALID;
|
||||
}
|
||||
#endif
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
rc = MemBackendRelease(&(*pBackend));
|
||||
if(pBackend->pMutexMethods) {
|
||||
SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
SyMutexRelease(pBackend->pMutexMethods, pBackend->pMutex);
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE void *SyMemBackendDup(SyMemBackend *pBackend, const void *pSrc, sxu32 nSize) {
|
||||
void *pNew;
|
||||
#if defined(UNTRUST)
|
||||
if(pSrc == 0 || nSize <= 0) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
pNew = SyMemBackendAlloc(&(*pBackend), nSize);
|
||||
if(pNew) {
|
||||
SyMemcpy(pSrc, pNew, nSize);
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
PH7_PRIVATE char *SyMemBackendStrDup(SyMemBackend *pBackend, const char *zSrc, sxu32 nSize) {
|
||||
char *zDest;
|
||||
zDest = (char *)SyMemBackendAlloc(&(*pBackend), nSize + 1);
|
||||
if(zDest) {
|
||||
Systrcpy(zDest, nSize + 1, zSrc, nSize);
|
||||
}
|
||||
return zDest;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobInitFromBuf(SyBlob *pBlob, void *pBuffer, sxu32 nSize) {
|
||||
#if defined(UNTRUST)
|
||||
if(pBlob == 0 || pBuffer == 0 || nSize < 1) {
|
||||
return SXERR_EMPTY;
|
||||
}
|
||||
#endif
|
||||
pBlob->pBlob = pBuffer;
|
||||
pBlob->mByte = nSize;
|
||||
pBlob->nByte = 0;
|
||||
pBlob->pAllocator = 0;
|
||||
pBlob->nFlags = SXBLOB_LOCKED | SXBLOB_STATIC;
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobInit(SyBlob *pBlob, SyMemBackend *pAllocator) {
|
||||
#if defined(UNTRUST)
|
||||
if(pBlob == 0) {
|
||||
return SXERR_EMPTY;
|
||||
}
|
||||
#endif
|
||||
pBlob->pBlob = 0;
|
||||
pBlob->mByte = pBlob->nByte = 0;
|
||||
pBlob->pAllocator = &(*pAllocator);
|
||||
pBlob->nFlags = 0;
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobReadOnly(SyBlob *pBlob, const void *pData, sxu32 nByte) {
|
||||
#if defined(UNTRUST)
|
||||
if(pBlob == 0) {
|
||||
return SXERR_EMPTY;
|
||||
}
|
||||
#endif
|
||||
pBlob->pBlob = (void *)pData;
|
||||
pBlob->nByte = nByte;
|
||||
pBlob->mByte = 0;
|
||||
pBlob->nFlags |= SXBLOB_RDONLY;
|
||||
return SXRET_OK;
|
||||
}
|
||||
#ifndef SXBLOB_MIN_GROWTH
|
||||
#define SXBLOB_MIN_GROWTH 16
|
||||
#endif
|
||||
static sxi32 BlobPrepareGrow(SyBlob *pBlob, sxu32 *pByte) {
|
||||
sxu32 nByte;
|
||||
void *pNew;
|
||||
nByte = *pByte;
|
||||
if(pBlob->nFlags & (SXBLOB_LOCKED | SXBLOB_STATIC)) {
|
||||
if(SyBlobFreeSpace(pBlob) < nByte) {
|
||||
*pByte = SyBlobFreeSpace(pBlob);
|
||||
if((*pByte) == 0) {
|
||||
return SXERR_SHORT;
|
||||
}
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
if(pBlob->nFlags & SXBLOB_RDONLY) {
|
||||
/* Make a copy of the read-only item */
|
||||
if(pBlob->nByte > 0) {
|
||||
pNew = SyMemBackendDup(pBlob->pAllocator, pBlob->pBlob, pBlob->nByte);
|
||||
if(pNew == 0) {
|
||||
return SXERR_MEM;
|
||||
}
|
||||
pBlob->pBlob = pNew;
|
||||
pBlob->mByte = pBlob->nByte;
|
||||
} else {
|
||||
pBlob->pBlob = 0;
|
||||
pBlob->mByte = 0;
|
||||
}
|
||||
/* Remove the read-only flag */
|
||||
pBlob->nFlags &= ~SXBLOB_RDONLY;
|
||||
}
|
||||
if(SyBlobFreeSpace(pBlob) >= nByte) {
|
||||
return SXRET_OK;
|
||||
}
|
||||
if(pBlob->mByte > 0) {
|
||||
nByte = nByte + pBlob->mByte * 2 + SXBLOB_MIN_GROWTH;
|
||||
} else if(nByte < SXBLOB_MIN_GROWTH) {
|
||||
nByte = SXBLOB_MIN_GROWTH;
|
||||
}
|
||||
pNew = SyMemBackendRealloc(pBlob->pAllocator, pBlob->pBlob, nByte);
|
||||
if(pNew == 0) {
|
||||
return SXERR_MEM;
|
||||
}
|
||||
pBlob->pBlob = pNew;
|
||||
pBlob->mByte = nByte;
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobAppend(SyBlob *pBlob, const void *pData, sxu32 nSize) {
|
||||
sxu8 *zBlob;
|
||||
sxi32 rc;
|
||||
if(nSize < 1) {
|
||||
return SXRET_OK;
|
||||
}
|
||||
rc = BlobPrepareGrow(&(*pBlob), &nSize);
|
||||
if(SXRET_OK != rc) {
|
||||
return rc;
|
||||
}
|
||||
if(pData) {
|
||||
zBlob = (sxu8 *)pBlob->pBlob ;
|
||||
zBlob = &zBlob[pBlob->nByte];
|
||||
pBlob->nByte += nSize;
|
||||
SX_MACRO_FAST_MEMCPY(pData, zBlob, nSize);
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobNullAppend(SyBlob *pBlob) {
|
||||
sxi32 rc;
|
||||
sxu32 n;
|
||||
n = pBlob->nByte;
|
||||
rc = SyBlobAppend(&(*pBlob), (const void *)"\0", sizeof(char));
|
||||
if(rc == SXRET_OK) {
|
||||
pBlob->nByte = n;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobDup(SyBlob *pSrc, SyBlob *pDest) {
|
||||
sxi32 rc = SXRET_OK;
|
||||
#ifdef UNTRUST
|
||||
if(pSrc == 0 || pDest == 0) {
|
||||
return SXERR_EMPTY;
|
||||
}
|
||||
#endif
|
||||
if(pSrc->nByte > 0) {
|
||||
rc = SyBlobAppend(&(*pDest), pSrc->pBlob, pSrc->nByte);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobCmp(SyBlob *pLeft, SyBlob *pRight) {
|
||||
sxi32 rc;
|
||||
#ifdef UNTRUST
|
||||
if(pLeft == 0 || pRight == 0) {
|
||||
return pLeft ? 1 : -1;
|
||||
}
|
||||
#endif
|
||||
if(pLeft->nByte != pRight->nByte) {
|
||||
/* Length differ */
|
||||
return pLeft->nByte - pRight->nByte;
|
||||
}
|
||||
if(pLeft->nByte == 0) {
|
||||
return 0;
|
||||
}
|
||||
/* Perform a standard memcmp() operation */
|
||||
rc = SyMemcmp(pLeft->pBlob, pRight->pBlob, pLeft->nByte);
|
||||
return rc;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobReset(SyBlob *pBlob) {
|
||||
pBlob->nByte = 0;
|
||||
if(pBlob->nFlags & SXBLOB_RDONLY) {
|
||||
pBlob->pBlob = 0;
|
||||
pBlob->mByte = 0;
|
||||
pBlob->nFlags &= ~SXBLOB_RDONLY;
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobRelease(SyBlob *pBlob) {
|
||||
if((pBlob->nFlags & (SXBLOB_STATIC | SXBLOB_RDONLY)) == 0 && pBlob->mByte > 0) {
|
||||
SyMemBackendFree(pBlob->pAllocator, pBlob->pBlob);
|
||||
}
|
||||
pBlob->pBlob = 0;
|
||||
pBlob->nByte = pBlob->mByte = 0;
|
||||
pBlob->nFlags = 0;
|
||||
return SXRET_OK;
|
||||
}
|
||||
PH7_PRIVATE sxi32 SyBlobSearch(const void *pBlob, sxu32 nLen, const void *pPattern, sxu32 pLen, sxu32 *pOfft) {
|
||||
const char *zIn = (const char *)pBlob;
|
||||
const char *zEnd;
|
||||
sxi32 rc;
|
||||
if(pLen > nLen) {
|
||||
return SXERR_NOTFOUND;
|
||||
}
|
||||
zEnd = &zIn[nLen - pLen];
|
||||
for(;;) {
|
||||
if(zIn > zEnd) {
|
||||
break;
|
||||
}
|
||||
SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc);
|
||||
if(rc == 0) {
|
||||
if(pOfft) {
|
||||
*pOfft = (sxu32)(zIn - (const char *)pBlob);
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
zIn++;
|
||||
if(zIn > zEnd) {
|
||||
break;
|
||||
}
|
||||
SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc);
|
||||
if(rc == 0) {
|
||||
if(pOfft) {
|
||||
*pOfft = (sxu32)(zIn - (const char *)pBlob);
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
zIn++;
|
||||
if(zIn > zEnd) {
|
||||
break;
|
||||
}
|
||||
SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc);
|
||||
if(rc == 0) {
|
||||
if(pOfft) {
|
||||
*pOfft = (sxu32)(zIn - (const char *)pBlob);
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
zIn++;
|
||||
if(zIn > zEnd) {
|
||||
break;
|
||||
}
|
||||
SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc);
|
||||
if(rc == 0) {
|
||||
if(pOfft) {
|
||||
*pOfft = (sxu32)(zIn - (const char *)pBlob);
|
||||
}
|
||||
return SXRET_OK;
|
||||
}
|
||||
zIn++;
|
||||
}
|
||||
return SXERR_NOTFOUND;
|
||||
}
|
Reference in New Issue
Block a user