📄 rvmemory.c
字号:
}
#if (RV_MEMORY_DEBUGINFO == 1)
if(result == RV_OK) {
/* If we sucessfully destructed, destroy the allocated block list and its lock. */
RvLockGet(®ion->listlock);
RvObjListDestruct(®ion->alloclist);
RvLockDestruct(®ion->listlock);
}
#endif
return result;
}
#if (RV_MEMORY_DEBUGINFO != 1)
RVCOREAPI RvStatus RVCALLCONV RvMemoryAlloc(RvMemory *reqregion, void **resultptr, RvSize_t size)
#else
/* Special Alloc for debugging */
RVCOREAPI RvStatus RVCALLCONV RvMemoryAllocDbg(RvMemory *reqregion, void **resultptr, RvSize_t size, RvInt line, RvChar *filename)
#endif
{
RvStatus result;
RvMemory *region;
RvSize_t realsize;
RvMemoryAllocHead *allochead;
#if (RV_MEMORY_DEBUGCHECK == 1)
RvUint8 *allocend;
#endif
/* To save time we don't lock region and assume the driver will */
/* do any needed locking. This does imply that RvMemoryDestruct */
/* can not be called until it is known that no other calls will */
/* be made on that region. */
/* If requested region is NULL, use the default region */
region = reqregion;
if(region == NULL)
region = &RvDefaultRegion;
#if defined(RV_NULLCHECK)
if(resultptr == NULL)
return RvMemoryErrorCode(RV_ERROR_NULLPTR);
#endif
#if defined(RV_OTHERCHECK)
if(region->drivernum < 0)
return RvMemoryErrorCode(RV_ERROR_DESTRUCTED);
if(RvDriverStatus[region->drivernum] != RV_OK)
return RvMemoryErrorCode(RV_MEMORY_ERROR_DRIVERFAILED);
#endif
/* Add overhead to needed size */
realsize = size + RV_MEMORY_ALLOC_OVERHEAD;
#if defined(RV_RANGECHECK)
if(realsize < size) /* overhead caused us to wrap */
return RvMemoryErrorCode(RV_ERROR_OUTOFRANGE);
#endif
/* Call driver to allocate space and deal with out-of-memory callback */
for(;;) {
result = region->drivercalls->alloc(region->driverRegion, resultptr, realsize);
/* Don't retry if we didn't run out of memory or the user callback doesn't return RV_OK */
if((RvErrorGetCode(result) != RV_ERROR_OUTOFRESOURCES) || (region->nomem == NULL) || (region->nomem(realsize) != RV_OK))
break;
}
if(result == RV_OK) {
/* Store pointer back to region along with any other info */
/* and bump resultptr to proper position. */
allochead = (RvMemoryAllocHead *)*resultptr;
*resultptr = (void *)((RvInt8 *)*resultptr + RV_MEMORY_ALLOC_HEAD_OVERHEAD);
allochead->region = region;
#if (RV_MEMORY_DEBUGINFO == 1)
/* Include additional debugging information */
allochead->line = line;
allochead->filename = filename;
allochead->thread = RvThreadCurrent();
allochead->id = RvThreadCurrentId();
/* Add block to end of allocated blocks list. */
if(RvLockGet(®ion->listlock) == RV_OK) {
RvObjListInsertBefore(®ion->alloclist, NULL, allochead);
RvLockRelease(®ion->listlock);
}
#endif
#if (RV_MEMORY_DEBUGCHECK == 1)
allochead->freed = RV_FALSE; /* Used to check for memory freed multiple times */
/* Set boundry at head and at the end. The one at the head */
/* be bigger than the request size because it goes to the */
/* pointer to be returned, which is aligned. */
allochead->reqsize = size;
memset(&allochead->boundry[0], RV_MEMORY_HEAD_FILL, (RvSize_t)((RvUint8 *)*resultptr - (RvUint8 *)&allochead->boundry[0]));
allocend = (RvUint8 *)*resultptr + size;
memset(allocend, RV_MEMORY_TAIL_FILL, RV_MEMORY_BOUNDRY_SIZE);
/* Set memory to make sure 0 isn't assumed. */
memset(*resultptr, RV_MEMORY_ALLOC_FILL, size);
#endif
}
return result;
}
RVCOREAPI RvStatus RVCALLCONV RvMemoryFree(void *ptr)
{
RvStatus result;
RvMemoryAllocHead *allochead;
#if (RV_MEMORY_DEBUGCHECK == 1)
RvUint8 *tmpptr;
size_t i;
#endif
/* To save time we don't lock region (see note in RvMemoryAlloc) */
#if defined(RV_NULLCHECK)
if(ptr == NULL)
return RvMemoryErrorCode(RV_ERROR_NULLPTR);
#endif
/* Region pointer should be stored right before ptr */
allochead = (RvMemoryAllocHead *)((RvInt8 *)ptr - RV_MEMORY_ALLOC_HEAD_OVERHEAD);
/* Do boundry and sanity checking. */
#if (RV_MEMORY_DEBUGCHECK == 1)
/* Check to make sure block hasn't already been freed. */
if(allochead->freed != RV_FALSE)
return RvMemoryErrorCode(RV_ERROR_UNKNOWN);
allochead->freed = RV_TRUE; /* Mark as freed */
/* Check header boundry (variable size). */
tmpptr = (RvUint8 *)&allochead->boundry[0];
while(tmpptr != (RvUint8 *)ptr) {
if(*tmpptr != RV_MEMORY_HEAD_FILL)
return RvMemoryErrorCode(RV_MEMORY_ERROR_OVERRUN);
tmpptr += 1;
}
/* Check boundry at end (always requested size). */
tmpptr = (RvUint8 *)ptr + allochead->reqsize;
for(i = 0; i < RV_MEMORY_BOUNDRY_SIZE; i++) {
if(*tmpptr != RV_MEMORY_TAIL_FILL)
return RvMemoryErrorCode(RV_MEMORY_ERROR_OVERRUN);
tmpptr += 1;
}
/* Overwrite free memory to insure its not still being used. */
memset(ptr, RV_MEMORY_FREE_FILL, allochead->reqsize);
#endif
#if defined(RV_OTHERCHECK)
if(allochead->region->drivernum < 0)
return RvMemoryErrorCode(RV_ERROR_DESTRUCTED);
if(RvDriverStatus[allochead->region->drivernum] != RV_OK)
return RvMemoryErrorCode(RV_MEMORY_ERROR_DRIVERFAILED);
#endif
#if (RV_MEMORY_DEBUGINFO == 1)
/* Remove block from allocated block list */
if(RvLockGet(&allochead->region->listlock) == RV_OK) {
RvObjListRemoveItem(&allochead->region->alloclist, allochead);
RvLockRelease(&allochead->region->listlock);
}
#endif
result = allochead->region->drivercalls->free(allochead->region->driverRegion, allochead);
return result;
}
RVCOREAPI RvStatus RVCALLCONV RvMemoryGetInfo(RvMemory *reqregion, RvMemoryInfo *meminfo)
{
RvMemory *region;
/* If requested region is NULL, use the default region */
region = reqregion;
if(region == NULL)
region = &RvDefaultRegion;
#if defined(RV_NULLCHECK)
if(meminfo == NULL)
return RvMemoryErrorCode(RV_ERROR_NULLPTR);
#endif
#if defined(RV_OTHERCHECK)
if(region->drivernum < 0)
return RvMemoryErrorCode(RV_ERROR_DESTRUCTED);
if(RvDriverStatus[region->drivernum] != RV_OK)
return RvMemoryErrorCode(RV_MEMORY_ERROR_DRIVERFAILED);
#endif
/* We fill in the first 2 fields and pass the rest into the driver */
strcpy(meminfo->name, region->name);
meminfo->drivernum = region->drivernum;
return region->drivercalls->info(region->driverRegion, meminfo);
}
RvStatus RvMemorySetDefaultMemCB(RvMemoryFunc func)
{
RvStatus result;
result = RvLockGet(&RvUserDefaultLock);
if(result == RV_OK) {
RvUserDefaultCB = func;
RvLockRelease(&RvUserDefaultLock);
}
return result;
}
RvStatus RvMemoryGetDefaultMemCB(RvMemoryFunc *func)
{
RvStatus result;
result = RvLockGet(&RvUserDefaultLock);
if(result == RV_OK) {
*func = RvUserDefaultCB;
RvLockRelease(&RvUserDefaultLock);
}
return result;
}
/* Out-of-memory callback for default memory region. Returns */
/* RV_OK if memory allocation should be tried again. It calls */
/* the function set by the user. */
static RvStatus RvMemoryDefaultMemCB(RvSize_t size)
{
RvStatus result;
result = RvLockGet(&RvUserDefaultLock);
if(result == RV_OK) {
if(RvUserDefaultCB != NULL) {
result = RvUserDefaultCB(size);
} else result = RvMemoryErrorCode(RV_ERROR_OUTOFRESOURCES);
RvLockRelease(&RvUserDefaultLock);
}
return result;
}
#if defined(RV_TEST_CODE)
#include "rvstdio.h"
#include "rvsemaphore.h"
/* Define quick macro to make error output more readable */
#define RvMemoryPrintError(_r) RvPrintf("Error %d/%d/%d\n", RvErrorGetLib((_r)), RvErrorGetModule((_r)), RvErrorGetCode((_r)))
/* Just test init/end and default region here. Let individual driver */
/* test deal with tests for those drivers. */
void RvMemoryTest(void)
{
RvStatus result;
void *memptr;
/* Initialize other needed modules */
RvSemaphoreInit();
RvLockInit();
RvPrintf("RvMemoryInit: ");
result = RvMemoryInit();
if(result != RV_OK) {
RvMemoryPrintError(result);
} else RvPrintf("OK\n");
/* Allocate and free from default region */
RvPrintf("RvMemoryAlloc (NULL): ");
result = RvMemoryAlloc(NULL, &memptr, 1000);
if(result != RV_OK) {
RvMemoryPrintError(result);
} else RvPrintf("OK (%p)\n", memptr);
RvPrintf("RvMemoryFree: ");
result = RvMemoryFree(memptr);
if(result != RV_OK) {
RvMemoryPrintError(result);
} else RvPrintf("OK\n");
/* Clean up */
RvPrintf("RvMemoryEnd: ");
result = RvMemoryEnd();
if(result != RV_OK) {
RvMemoryPrintError(result);
} else RvPrintf("OK\n");
/* Shut down other needed modules */
RvLockEnd();
RvSemaphoreEnd();
}
#endif /* RV_TEST_CODE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -