⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rvmemory.c

📁 基于h323协议的软phone
💻 C
📖 第 1 页 / 共 2 页
字号:
/***********************************************************************
Filename   : rvmemory.c
Description: memory management functions
************************************************************************
        Copyright (c) 2001 RADVISION Inc. and RADVISION Ltd.
************************************************************************
NOTICE:
This document contains information that is confidential and proprietary
to RADVISION Inc. and RADVISION Ltd.. No part of this document may be
reproduced in any form whatsoever without written prior approval by
RADVISION Inc. or RADVISION Ltd..

RADVISION Inc. and RADVISION Ltd. reserve the right to revise this
publication and make changes without obligation to notify any person of
such revisions or changes.
***********************************************************************/
#include "rvmemory.h"
#include "rvlock.h"
#include <string.h>

#if (RV_MEMORY_DEBUGINFO == 1)
#include "rvthread.h"
#endif

/* This module does not need to be ported to different operating systems. */
/* Some of memory drivers do need to be ported. It is part of the ccore */
/* layer because the memory drivers are dependent upon its existance and */
/* so are some other modules at this layer. */

/* Structure containing definitions for driver calls. Each driver must provide all of these functions. */
/* The RvMemoryDriverFuncs typedef is in rvmemory.h because a forward declaration is needed. */
struct RvMemoryDriverFuncs_s {
    RvStatus (*init)(void);                                              /* Called once at startup. */
    RvStatus (*end)(void);                                               /* Called once at shutdown */
    RvStatus (*construct)(void *driverRegion, void *start, RvSize_t size, RvSize_t overhead, RvMemory *moremem, void *attr); /* Construct a memory region. */
    RvStatus (*destruct)(void *driverRegion);                            /* Destruct a memory region */
    RvStatus (*alloc)(void *driverRegion, void **result, RvSize_t size); /* Allocate from a memory region. */
    RvStatus (*free)(void *driverRegion, void *ptr);                     /* Deallocate from a memory region. */
    RvStatus (*info)(void *driverRegion, RvMemoryInfo *meminfo);         /* Get statistics about a memory region */
};

/* Array of available memory drivers. MUST match RV_MEMORY_NUMDRIVERS */
/* and RV_MEMORY_DRIVER_XXX list in the rvmemory.h file. NOTE that the */
/* first driver is used as the default and thus the Init calls MUST NOT */
/* depend on any other memory drivers being available. */
static RvMemoryDriverFuncs RvMemoryDrivers[] = {
    { RvOsMemInit, RvOsMemEnd, RvOsMemConstruct, RvOsMemDestruct, RvOsMemAlloc, RvOsMemFree, RvOsMemGetInfo },
    { RvPoolMemInit, RvPoolMemEnd, RvPoolMemConstruct, RvPoolMemDestruct, RvPoolMemAlloc, RvPoolMemFree, RvPoolMemGetInfo }
};

/* Lets make error codes a little easier to type */
#define RvMemoryErrorCode(_e) RvErrorCode(RV_ERROR_LIBCODE_CCORE, RV_CCORE_MODULE_MEMORY, (_e))

#if (RV_MEMORY_DEBUGCHECK == 1)
#define RV_MEMORY_BOUNDRY_SIZE 16 /* minumum size */
#define RV_MEMORY_HEAD_FILL 0x5A  /* head boundry marker */
#define RV_MEMORY_TAIL_FILL 0xA5  /* tail boundry marker */
#define RV_MEMORY_ALLOC_FILL 0xAA /* alloced memory filler */
#define RV_MEMORY_FREE_FILL 0xDD  /* freed memory filler */
#else
#define RV_MEMORY_BOUNDRY_SIZE 0
#endif

/* Define additional data to be stored at the beginning of each allocation. */
/* The OVERHEAD size must account for the alignment of the ptr that */
/* will be returned to the user. */
typedef struct {
    RvMemory *region; /* always needed */
#if (RV_MEMORY_DEBUGINFO == 1)
    RvObjListElement alloclistelem;
    RvInt line;
    RvChar *filename;
    RvThread *thread;
    RvThreadId id;
#endif
#if (RV_MEMORY_DEBUGCHECK == 1)
    RvBool freed;
    size_t reqsize;
    RvUint8 boundry[RV_MEMORY_BOUNDRY_SIZE]; /* Must be last item in structure */
#endif
} RvMemoryAllocHead;
#define RV_MEMORY_ALLOC_HEAD_OVERHEAD RvRoundToSize(sizeof(RvMemoryAllocHead), RV_ALIGN_SIZE)

/* Total overhead used by rvmemory for each allocation (including end */
/* boundry which is always the requested size. */
#define RV_MEMORY_ALLOC_OVERHEAD (RV_MEMORY_ALLOC_HEAD_OVERHEAD + RV_MEMORY_BOUNDRY_SIZE)

static RvStatus RvMemoryDefaultMemCB(RvSize_t size);

static RvMemory RvDefaultRegion;     /* Default memory region: OsMem driver, also handle out-of-memory callback */
static RvMemoryFunc RvUserDefaultCB; /* User changable out-of-memory callback for default region */
static RvObjList RvRegionList;       /* List of currently constructed regions */
static RvLock RvUserDefaultLock;     /* Use for locking RvUserDefaultCB */
static RvLock RvMemoryLock;          /* Use for locking during construct/destruct */
static RvStatus RvDriverStatus[RV_MEMORY_NUMDRIVERS]; /* Holds status of individual drivers */

/* Must be called only once and before any other calls to rvmemory. */
RvStatus RvMemoryInit(void)
{
    RvStatus result;
    RvInt i;

    /* Mark default driver so in case we fail we'll abort RvMemoryEnd */
    RvDriverStatus[0] = RvMemoryErrorCode(RV_ERROR_UNKNOWN);

    /* Set up basics */
    RvUserDefaultCB = NULL;
    result = RvLockConstruct(&RvUserDefaultLock);
    if(result != RV_OK)
        return result;
    result = RvLockConstruct(&RvMemoryLock);
    if(result != RV_OK) {
        RvLockDestruct(&RvUserDefaultLock);
        return result;
    }

    /* Set up region list */
    RvObjListConstruct(&RvRegionList, &RvDefaultRegion, &RvDefaultRegion.listElem);

    /* We need to set up the default region first, then initialize everything else */
    RvDriverStatus[0] = RvMemoryDrivers[0].init();
    if(RvDriverStatus[0] == RV_OK)
        RvDriverStatus[0] = RvMemoryConstruct(&RvDefaultRegion, RV_MEMORY_DRIVER_OSMEM, "Default", NULL, 0, NULL, RvMemoryDefaultMemCB, NULL);
    if(RvDriverStatus[0] != RV_OK) {
        RvLockDestruct(&RvUserDefaultLock);
        RvLockDestruct(&RvMemoryLock);
        return RvDriverStatus[0];
    }

    /* Initialize the rest of the drivers and save the results */
    for(i = 1; i < RV_MEMORY_NUMDRIVERS; i++)
        RvDriverStatus[i] = RvMemoryDrivers[i].init();

    return RV_OK;
}

/* Must be called only once and after all regions (except the default */
/* and any created by other memory drivers) have been destructed */
RvStatus RvMemoryEnd(void)
{
    RvStatus result;
    RvInt i;

    if(RvDriverStatus[0] != RV_OK)
        return RvDriverStatus[0];   /* No default driver, init must have failed badly */

    /* Call end functions in reverse order and only if init was successfull */
    for(i = (RV_MEMORY_NUMDRIVERS - 1); i > 0; i--) {
        if(RvDriverStatus[i] == RV_OK)
            RvDriverStatus[i] = RvMemoryDrivers[i].end();
    }

    /* Destroy default region */
    result = RvMemoryDestruct(&RvDefaultRegion);

    /* Call end for default driver */
    RvDriverStatus[0] = RvMemoryDrivers[0].end();
    if(result == RV_OK)
        result = RvDriverStatus[0];

    /* No regions should be left */
    if((result == RV_OK) && (RvObjListSize(&RvRegionList) != 0))
       result = RvMemoryErrorCode(RV_ERROR_UNKNOWN);

    RvObjListDestruct(&RvRegionList);
    RvLockDestruct(&RvMemoryLock);
    RvLockDestruct(&RvUserDefaultLock);
    return result;
}

/* Note that individual drivers may interpret parameters in a manner specific to that driver */
RvStatus RvMemoryConstruct(RvMemory *region, RvInt drivernum, RvChar *name, void *start, RvSize_t size, RvMemory *moremem, RvMemoryFunc nomem, void *attr)
{
    RvStatus result;
#if (RV_MEMORY_DEBUGINFO == 1)
    RvMemoryAllocHead tmpheader;
#endif

#if defined(RV_NULLCHECK)
    if(region == NULL)
        return RvMemoryErrorCode(RV_ERROR_NULLPTR);
#endif
#if defined(RV_RANGECHECK)
    if((drivernum < 0) || (drivernum >= RV_MEMORY_NUMDRIVERS))
        return RvMemoryErrorCode(RV_ERROR_OUTOFRANGE);
#endif
#if defined(RV_OTHERCHECK)
    if(RvDriverStatus[drivernum] != RV_OK)
        return RvMemoryErrorCode(RV_MEMORY_ERROR_DRIVERFAILED);
#endif

    /* Create a list of allocated blocks for debugging and a lock for it. */
#if (RV_MEMORY_DEBUGINFO == 1)
    result = RvLockConstruct(&region->listlock);
    if(result != RV_OK)
        return result;
    if(RvObjListConstruct(&region->alloclist, &tmpheader, &tmpheader.alloclistelem) == NULL) {
        RvLockDestruct(&region->listlock);
        return RvMemoryErrorCode(RV_ERROR_UNKNOWN);
    }
#endif

    /* Fill in region information with passed in info */
    region->drivernum = drivernum;
    region->drivercalls = &RvMemoryDrivers[drivernum];
    region->start = start;
    region->size = size;
    region->moremem = moremem;
    region->nomem = nomem;
    region->driverRegion = NULL; /* just in case */
    if(name != NULL) {
        strncpy(region->name, name, RV_MEMORY_MAX_NAMESIZE);
        region->name[RV_MEMORY_MAX_NAMESIZE - 1] = '\0';
    } else region->name[0] = '\0';

    /* Each driver needs to set the pointers for driverData in this switch statement. */
    /* We can't assume each union item aligns to the same start point. */
    switch(drivernum) {
        case RV_MEMORY_DRIVER_OSMEM: region->driverRegion = (void *)&region->driverData.osMemData;
                                     break;
        case RV_MEMORY_DRIVER_POOLMEM: region->driverRegion = (void *)&region->driverData.poolMemData;
                                       break;
    }

    /* Call specific driver construct */
    result = region->drivercalls->construct(region->driverRegion, region->start, region->size, RV_MEMORY_ALLOC_OVERHEAD, region->moremem, attr);

    if(result == RV_OK) {
        /* Do any operations that require the construct/destruct lock inside this block */
        RvLockGet(&RvMemoryLock);

        /* Add to end region list */
        RvObjListInsertBefore(&RvRegionList, NULL, region);

        RvLockRelease(&RvMemoryLock);
    }

#if (RV_MEMORY_DEBUGINFO == 1)
    /* Undo debugging stuff if construction failed. */
    if(result != RV_OK) {
        RvObjListDestruct(&region->alloclist);
        RvLockDestruct(&region->listlock);
    }
#endif

    return result;
}

RvStatus RvMemoryDestruct(RvMemory *region)
{
    RvStatus result;
    RvInt origdriver;

#if defined(RV_NULLCHECK)
    if(region == 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

    /* Do any operations that require the construct/destruct lock inside this block */
    RvLockGet(&RvMemoryLock);

    /* Check to see if the region already destructed. Since we don't need locking for */
    /* anything else in the structure, we assume drivernum is monotonic so we don't */
    /* have to lock anything when we check during alloc and free. Since we already */
    /* need to use the global lock we'll use it for modifying drivernum. */
    if(region->drivernum < 0) {
        RvLockRelease(&RvMemoryLock);
        return RV_OK;
    }

    /* Remove region from list */
    RvObjListRemoveItem(&RvRegionList, region);

    origdriver = region->drivernum; /* save it for undo */
    region->drivernum = -1; /* indicate destruction */

    RvLockRelease(&RvMemoryLock);

    result = region->drivercalls->destruct(region->driverRegion);

    if(result != RV_OK) {
        /* We couldn't destroy it so undo things. This leaves an unlocked */
        /* gap when the region looks destructed, then reappears, but since */
        /* the region shouldn't be in use while calling destruct and its a */
        /* failure mode, we don't worry about it. */
        RvLockGet(&RvMemoryLock);
        region->drivernum = origdriver;
        RvObjListInsertBefore(&RvRegionList, NULL, region);
        RvLockRelease(&RvMemoryLock);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -