📄 ema.c
字号:
/*
***********************************************************************************
NOTICE:
This document contains information that is proprietary to RADVISION LTD..
No part of this publication may be reproduced in any form whatsoever without
written prior approval by RADVISION LTD..
RADVISION LTD. reserves the right to revise this publication and make changes
without obligation to notify any person of such revisions or changes.
***********************************************************************************
*/
#include "rvstdio.h"
#include "rvmutex.h"
#include "rvlock.h"
#include "rvmemory.h"
#include "rvlog.h"
#include "ra.h"
#include "ema.h"
#ifdef RV_EMA_DEBUG_DEADLOCKS
#include "rvthread.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/************************************************************************
* emaObject struct
* Holds the information of an emaObject
************************************************************************/
typedef struct
{
HRA ra; /* Handle to RA we're using */
RvLogSource log; /* Log to use for messages */
RvLock lock; /* Lock we're using */
emaLockType lockType; /* Type of locking mechanism to use */
RvUint32 elemSize; /* Size of each element inside EMA */
RvUint32 type; /* Integer representing the type of objects stored in EMA */
void* userData; /* User related information associated with this EMA object */
void const* instance; /* Instance associated with this EMA object */
RvUint32 markCount; /* Number of items currently deleted and marked */
RvWatchdog* watchdog; /* Watchdog used (if not NULL) */
RvUint32 watchdogResource; /* Resource index value in the watchdog */
} emaObject;
/************************************************************************
* emaElem struct
* Holds the information of an ema element
*
* Note: The mutex for the element is held in the end of the allocation
* if using emaNormalLocks. If emaLinkedLocks is used, then in the
* end of the allocation we'll have to pointer to the linked element
* in another EMA construct.
************************************************************************/
typedef struct
{
emaObject* ema; /* Pointer to the EMA object.
When this pointer is NULL, it indicates that the element
was deleted. We use this for emaLock().
THIS MUST BE THE FIRST FIELD IN THIS STRUCT! */
#ifdef RV_EMA_DEBUG
RvUint32 debug1; /* Debugging bytes == EMA_DEBUG_BYTES */
#endif
RvUint32 flags; /* Reference count and locks count.
It also holds a bit indicating if element was deleted */
void* appHandle; /* Application's handle of the EMA object */
#ifdef RV_EMA_DEBUG_DEADLOCKS
RvThreadId lockedThread; /* Indication who's the thread that locked this object */
#ifdef RV_EMA_DEBUG
char* filename; /* Filename that locked this object */
int lineno; /* Line number that locked this object */
#endif
#endif
#ifdef RV_EMA_DEBUG
RvUint32 debug2; /* Debugging bytes == EMA_DEBUG_BYTES */
#endif
} emaElem;
/* Bytes used when debuging memory allocations */
#define EMA_DEBUG_BYTES (0xdeadbeef)
/* Indication in the reference count that this element was deleted */
#define EMA_ALREADY_DELETED 0x80000000
/* Indication of the reference count's actual value */
#define EMA_GET_REFERENCE(elem) ((elem)->flags & 0x0000ffff)
#define EMA_INC_REFERENCE(elem,count) ((elem)->flags += (RvUint16)(count))
#define EMA_DEC_REFERENCE(elem,count) ((elem)->flags -= (RvUint16)(count))
/* Indication of the locks count's actual value */
#define EMA_GET_LOCKS(elem) (((elem)->flags & 0x7fff0000) >> 16)
#define EMA_INC_LOCKS(elem,count) ((elem)->flags += (((RvUint32)(count)) << 16))
#define EMA_DEC_LOCKS(elem,count) ((elem)->flags -= (((RvUint32)(count)) << 16))
/************************************************************************
*
* Private functions
*
************************************************************************/
/************************************************************************
* emaDeleteElement
* purpose: Delete an element used by ema.
* input : ema - EMA object used
* rElem - Element to delete
* location - Location of element deleted
* decCount - RV_TRUE if we need to decrease count of marked/deleted elements
* functionName- Name of function that called this one - used for log
* output : none
* return : none
************************************************************************/
static void emaDeleteElement(
IN emaObject* ema,
IN emaElem* rElem,
IN int location,
IN RvBool decCount,
IN const char* functionName)
{
RvBool locked = RV_TRUE;
EMAElement parent = NULL;
if (functionName);
/* First of all, let's lock the element and remove the reference to ema on it.
Doing this, allows us to stay blocked on an emaLock() call while trying to
delete the element */
switch (ema->lockType)
{
case emaNoLocks: break;
case emaNormalLocks: RvMutexLock((RvMutex *)((char*)rElem + sizeof(emaElem) + ema->elemSize)); break;
case emaLinkedLocks:
{
parent = *((EMAElement*)((char*)rElem + sizeof(emaElem) + ema->elemSize));
if (parent != NULL)
locked = emaLock(parent);
else
locked = RV_FALSE;
break;
}
}
rElem->ema = NULL;
if (locked)
{
switch (ema->lockType)
{
case emaNoLocks: break;
case emaNormalLocks: RvMutexUnlock((RvMutex *)((char*)rElem + sizeof(emaElem) + ema->elemSize)); break;
case emaLinkedLocks: emaUnlock(parent); break;
}
}
/* Do all the rest here */
RvLockGet(&ema->lock);
if (decCount)
ema->markCount--;
raDeleteLocation(ema->ra, location);
RvLockRelease(&ema->lock);
RvLogDebug(&ema->log,
(&ema->log, "%s (%s): 0x%p deleted (location=%d)", functionName, raGetName(ema->ra), rElem, location));
}
/******************************************************************************
* emaWatchdogResourceCallback
* ----------------------------------------------------------------------------
* General: Watchdog callback for accessing an EMA instance.
* This function is an accessory function to make the handling of
* EMA resources easier for the watchdog.
*
* Return Value: RV_OK - if successful.
* Other on failure
* ----------------------------------------------------------------------------
* Arguments:
* Input: context - EMA instance handle.
* resource - The requested resource's enumeration.
* type - The type of information requested.
* Output: value - The actual resource value.
*****************************************************************************/
static int RVCALLCONV EmaWatchdogResourceCallback(
IN void* context,
IN RvUint32 resource,
IN RvWatchdogResourceType type,
OUT RvUint32* value)
{
emaObject* ema = (emaObject *)context;
RV_UNUSED_ARG(resource);
switch (type)
{
case RvWatchdogMaxVal:
*value = raMaxSize(ema->ra);
break;
case RvWatchdogMaxUsage:
*value = raMaxUsage(ema->ra);
break;
case RvWatchdogCurrent:
*value = raCurSize(ema->ra);
break;
default:
return RV_ERROR_UNKNOWN;
}
return RV_OK;
}
/************************************************************************
*
* Public functions
*
************************************************************************/
/************************************************************************
* emaConstruct
* purpose: Create an EMA object
* input : elemSize - Size of elements in the EMA in bytes
* maxNumOfElements - Number of elements in EMA
* lockType - Type of locking mechanism to use
* name - Name of EMA (used in log messages)
* type - Integer representing the type of objects
* stored in this EMA.
* userData - User related information associated with
* this EMA object.
* instance - Instance associated with this EMA object.
* output : none
* return : Handle to RA constructed on success
* NULL on failure
************************************************************************/
HEMA emaConstruct(
IN int elemSize,
IN int maxNumOfElements,
IN emaLockType lockType,
IN const char* name,
IN RvUint32 type,
IN void* userData,
IN void const* instance)
{
emaObject* ema;
int allocSize = 0;
/* Allocate the object */
if(RvMemoryAlloc(NULL, (void**)&ema, sizeof(emaObject)) != RV_OK)
return NULL;
/* Remember the type of elements stored */
ema->type = type;
ema->userData = userData;
ema->instance = instance;
/* Create a log handle for our use */
RvLogSourceConstruct(RvLogGet(), &ema->log, RV_LOG_LIBCODE_ASN1, "EMA", "Enhanced Memory Allocator");
/* Calculate the size of each element (platform-aligned) */
ema->elemSize = RvRoundToSize(elemSize, RV_ALIGN_SIZE);
/* See if we need a lock for each element */
switch (lockType)
{
case emaNoLocks: allocSize = (int)(ema->elemSize + sizeof(emaElem)); break;
case emaNormalLocks: allocSize = (int)(ema->elemSize + sizeof(emaElem) + sizeof(RvMutex)); break;
case emaLinkedLocks: allocSize = (int)(ema->elemSize + sizeof(emaElem) + sizeof(EMAElement*)); break;
}
/* Create the RA */
ema->ra = raConstruct(allocSize, maxNumOfElements, RV_FALSE, name);
/* Create the mutex */
RvLockConstruct(&ema->lock);
ema->lockType = lockType;
#ifndef NOTHREADS
if (lockType == emaNormalLocks)
{
int i;
/* Initialize all the mutexes we need */
for (i = 0; i < maxNumOfElements; i++)
{
RvMutexConstruct((RvMutex *) (RV_RA_ELEM_DATA(ema->ra, i) + sizeof(emaElem) + ema->elemSize));
}
}
#endif
ema->markCount = 0;
ema->watchdog = NULL;
return (HEMA)ema;
}
/************************************************************************
* emaDestruct
* purpose: Free an EMA object, deallocating all of its used memory
* input : emaH - Handle of the EMA object
* output : none
* return : none
************************************************************************/
void emaDestruct(IN HEMA emaH)
{
emaObject* ema = (emaObject *)emaH;
int numElems;
if (ema == NULL) return;
numElems = raCurSize(ema->ra);
if (numElems > 0)
{
RvLogWarning(&ema->log,
(&ema->log, "emaDestruct (%s): %d elements not deleted", raGetName(ema->ra), numElems));
}
/* Remove lock */
RvLockDestruct(&ema->lock);
#ifndef NOTHREADS
if (ema->lockType == emaNormalLocks)
{
int i;
/* End all the mutexes we initialized */
for (i = 0; i < raMaxSize(ema->ra); i++)
{
RvMutexDestruct((RvMutex *) (RV_RA_ELEM_DATA(ema->ra, i) + sizeof(emaElem) + ema->elemSize));
}
}
#endif
/* Remove watchdog resource if we have to */
if (ema->watchdog != NULL)
RvWatchdogDeleteResource(ema->watchdog, ema->watchdogResource);
/* Free any used memory and RA */
raDestruct(ema->ra);
RvLogSourceDestruct(RvLogGet(), &ema->log);
RvMemoryFree(ema);
}
/************************************************************************
* emaAdd
* purpose: Allocate an element in EMA for use, without initializing its
* value.
* This automatically locks the EMA object.
* input : emaH - Handle of the EMA object
* appHandle - Application's handle for the EMA object
* output : none
* return : Pointer to element added on success
* NULL on failure
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -