📄 ema.c
字号:
* purpose: Mark an element in EMA for use, not letting anyone delete
* this element until it is release.
* This automatically locks the EMA object.
* input : elem - Element to mark
* output : none
* return : Negative value on failure
************************************************************************/
#ifdef RV_EMA_DEBUG
int emaMarkDebug(IN EMAElement elem, IN const char* filename, IN int lineno)
#else
int emaMark(IN EMAElement elem)
#endif
{
emaObject* ema;
emaElem* rElem;
if (elem == NULL) return RV_ERROR_UNKNOWN;
/* Find out our element information */
rElem = (emaElem *)((char*)elem - sizeof(emaElem));
ema = rElem->ema;
#ifdef RV_EMA_DEBUG
RvLogDebug(&ema->log,
(&ema->log, "emaMark (%s): Marking 0x%p, refCount=%d (%s:%d)",
raGetName(ema->ra), rElem, EMA_GET_REFERENCE(rElem), filename, lineno));
if ((rElem->debug1 != EMA_DEBUG_BYTES) || (rElem->debug2 != EMA_DEBUG_BYTES))
{
RvLogExcep(&ema->log,
(&ema->log, "emaMark (%s): Someone is messing with memory 0x%p", raGetName(ema->ra), rElem));
}
#endif
/* Increase the reference count */
switch (ema->lockType)
{
case emaNoLocks: break;
case emaNormalLocks: RvMutexLock((RvMutex *)((char*)elem + ema->elemSize)); break;
case emaLinkedLocks:
emaLock(*((EMAElement*)((char*)elem + ema->elemSize)));
emaMark(*((EMAElement*)((char*)elem + ema->elemSize)));
break;
}
EMA_INC_REFERENCE(rElem,1);
switch (ema->lockType)
{
case emaNoLocks: break;
case emaNormalLocks: RvMutexUnlock((RvMutex *)((char*)elem + ema->elemSize)); break;
case emaLinkedLocks: emaUnlock(*((EMAElement*)((char*)elem + ema->elemSize))); break;
}
return 0;
}
/************************************************************************
* emaRelease
* purpose: Release an element in EMA after it was marked using
* emaMark(), returning an indication if this element
* still exists.
* This automatically locks the EMA object.
* input : elem - Element to mark
* output : none
* return : RV_TRUE if element still exists
* RV_FALSE if element was deleted and is not valid anymore
* Negative value on failure
************************************************************************/
#ifdef RV_EMA_DEBUG
int emaReleaseDebug(IN EMAElement elem, IN const char* filename, IN int lineno)
#else
int emaRelease(IN EMAElement elem)
#endif
{
emaObject* ema;
emaElem* rElem;
int elemExists;
if (elem == NULL) return RV_ERROR_UNKNOWN;
/* Find out our element information */
rElem = (emaElem *)((char*)elem - sizeof(emaElem));
ema = rElem->ema;
#ifdef RV_EMA_DEBUG
RvLogDebug(&ema->log, (&ema->log,
"emaRelease (%s): Releasing 0x%p, refCount=%d (%s:%d)",
raGetName(ema->ra), rElem, EMA_GET_REFERENCE(rElem), filename, lineno));
if (EMA_GET_REFERENCE(rElem) == 0)
{
RvLogExcep(&ema->log, (&ema->log,
"emaRelease (%s): Releasing 0x%p (%s:%d) when it's not marked!",
raGetName(ema->ra), rElem, filename, lineno));
}
if ((rElem->debug1 != EMA_DEBUG_BYTES) || (rElem->debug2 != EMA_DEBUG_BYTES))
{
RvLogExcep(&ema->log, (&ema->log,
"emaRelease (%s): Someone is messing with memory 0x%p", raGetName(ema->ra), rElem));
}
#else
RvLogDebug(&ema->log,
(&ema->log, "emaRelease (%s): Releasing 0x%p, refCount=%d", raGetName(ema->ra), rElem, EMA_GET_REFERENCE(rElem)));
#endif
/* Decrease the reference count */
switch (ema->lockType)
{
case emaNoLocks: break;
case emaNormalLocks: RvMutexLock((RvMutex *)((char*)elem + ema->elemSize)); break;
case emaLinkedLocks:
emaLock(*((EMAElement*)((char*)elem + ema->elemSize)));
emaRelease(*((EMAElement*)((char*)elem + ema->elemSize)));
break;
}
EMA_DEC_REFERENCE(rElem,1);
elemExists = ((rElem->flags & EMA_ALREADY_DELETED) == 0);
/* Delete element if we're done with it */
if (rElem->flags == EMA_ALREADY_DELETED)
{
int location = raGetByPtr(ema->ra, rElem);
emaDeleteElement(ema, rElem, location, RV_TRUE, "emaRelease");
}
switch (ema->lockType)
{
case emaNoLocks: break;
case emaNormalLocks: RvMutexUnlock((RvMutex *)((char*)elem + ema->elemSize)); break;
case emaLinkedLocks:
emaUnlock(*((EMAElement*)((char*)elem + ema->elemSize)));
break;
}
return elemExists;
}
/************************************************************************
* emaWasDeleted
* purpose: Check if an element in EMA was deleted after a call to
* emaMark().
* input : elem - Element to mark
* output : none
* return : RV_TRUE if element was deleted
* RV_FALSE if element still exists
************************************************************************/
RvBool emaWasDeleted(IN EMAElement elem)
{
emaObject* ema;
emaElem* rElem;
/* Find out our element information */
rElem = (emaElem *)((char*)elem - sizeof(emaElem));
ema = rElem->ema;
RvLogDebug(&ema->log,
(&ema->log, "emaWasDeleted (%s): Checking 0x%p (refCount=%d)",
raGetName(ema->ra), rElem, EMA_GET_REFERENCE(rElem)));
#ifdef RV_EMA_DEBUG
if ((rElem->debug1 != EMA_DEBUG_BYTES) || (rElem->debug2 != EMA_DEBUG_BYTES))
{
RvLogExcep(&ema->log,
(&ema->log, "emaWasDeleted (%s): Someone is messing with memory 0x%p", raGetName(ema->ra), rElem));
}
#endif
/* Check if element was deleted */
return ((rElem->flags & EMA_ALREADY_DELETED) != 0);
}
/************************************************************************
* emaPrepareForCallback
* purpose: Prepare an element in EMA for use in a callback to the app.
* This function will make sure the element is unlocked the necessary
* number of times, and then marked once (so the app won't delete
* this element).
* emaReturnFromCallback() should be called after the callback,
* with the return value of this function.
* input : elem - Element to prepare
* output : none
* return : Number of times the element was locked on success
* Negative value on failure
************************************************************************/
#ifdef RV_EMA_DEBUG
int emaPrepareForCallbackDebug(IN EMAElement elem, IN const char* filename, IN int lineno)
#else
int emaPrepareForCallback(IN EMAElement elem)
#endif
{
emaObject* ema;
emaElem* rElem;
int numLocks;
if (elem == NULL) return RV_ERROR_UNKNOWN;
/* Find out our element information */
rElem = (emaElem *)((char*)elem - sizeof(emaElem));
ema = rElem->ema;
/* Make sure we've got an element */
if (ema == NULL) return RV_ERROR_UNKNOWN;
#ifdef RV_EMA_DEBUG
if (EMA_GET_LOCKS(rElem) == 0)
{
RvLogInfo(&ema->log, (&ema->log,
"emaPrepareForCallback (%s): on 0x%p (%s:%d) when not locked!",
raGetName(ema->ra), rElem, filename, lineno));
}
#endif
/* Increase the reference count */
EMA_INC_REFERENCE(rElem,1);
/* See where the do we have to unlock */
switch (ema->lockType)
{
case emaNormalLocks:
{
/* We unlock the element */
int i;
numLocks = EMA_GET_LOCKS(rElem);
/* First we decrease the number of locks, and then we actually exit them... */
EMA_DEC_LOCKS(rElem,numLocks);
for (i = 0; i < numLocks; i++)
{
RvMutexUnlock((RvMutex *)((char*)elem + ema->elemSize));
}
break;
}
case emaLinkedLocks:
{
/* We must prepare the parent */
EMAElement parent = *((EMAElement*)((char*)elem + ema->elemSize));
if (parent != NULL)
numLocks = emaPrepareForCallback(parent);
else
numLocks = RV_ERROR_UNKNOWN;
if (numLocks < 0)
{
RvLogWarning(&ema->log,
(&ema->log, "emaPrepareForCallback (%s): Couldn't prepare parent=0x%p of 0x%p for some reason",
raGetName(ema->ra), parent, elem));
}
break;
}
default:
numLocks = 0;
break;
}
#ifdef RV_EMA_DEBUG
RvLogDebug(&ema->log,
(&ema->log, "emaPrepareForCallback (%s): on 0x%p - locked %d times (%s:%d)",
raGetName(ema->ra), rElem, numLocks, filename, lineno));
#endif
return numLocks;
}
/************************************************************************
* emaReturnFromCallback
* purpose: Make sure the EMA element knows it has returned from a
* callback. This function will ensure that the element is
* locked again with the specified number of times. It will also
* release the element, and if timersLocked==0, and the element
* was deleted by the app in the callback, the element will also
* be permanently deleted.
* input : elem - Element to prepare
* output : none
* return : RV_TRUE if element still exists
* RV_FALSE if element was deleted and is not valid anymore
* Negative value on failure
************************************************************************/
#ifdef RV_EMA_DEBUG
int emaReturnFromCallbackDebug(IN EMAElement elem, IN int timesLocked, IN const char* filename, IN int lineno)
#else
int emaReturnFromCallback(IN EMAElement elem, IN int timesLocked)
#endif
{
emaObject* ema;
emaElem* rElem;
int status = RV_ERROR_UNKNOWN;
if (elem == NULL) return RV_ERROR_UNKNOWN;
/* Find out our element information */
rElem = (emaElem *)((char*)elem - sizeof(emaElem));
ema = rElem->ema;
/* Make sure we've got an element */
if (ema == NULL) return RV_ERROR_UNKNOWN;
#ifdef RV_EMA_DEBUG
RvLogDebug(&ema->log,
(&ema->log, "emaReturnFromCallback (%s): on 0x%p, %d times (%s:%d)",
raGetName(ema->ra), rElem, timesLocked, filename, lineno));
#endif
/* See where the do we have to unlock */
switch (ema->lockType)
{
case emaNormalLocks:
{
/* We unlock the element */
int i;
/* First we should lock, and only then: increase the number of locks */
for (i = 0; i < timesLocked; i++)
{
RvMutexLock((RvMutex *)((char*)elem + ema->elemSize));
}
EMA_INC_LOCKS(rElem,timesLocked);
status = 0;
break;
}
case emaLinkedLocks:
{
/* We must prepare the parent */
EMAElement parent = *((EMAElement*)((char*)elem + ema->elemSize));
if (parent != NULL)
status = emaReturnFromCallback(parent, timesLocked);
else
status = RV_ERROR_UNKNOWN;
if (status < 0)
{
RvLogWarning(&ema->log,
(&ema->log, "emaReturnFromCallback (%s): Couldn't return parent=0x%p of 0x%p for some reason",
raGetName(ema->ra), parent, elem));
}
break;
}
default:
break;
}
/* Decrease the reference count */
EMA_DEC_REFERENCE(rElem,1);
/* Delete element if we're done with it */
if (rElem->flags == EMA_ALREADY_DELETED)
{
int location = raGetByPtr(ema->ra, rElem);
emaDeleteElement(ema, rElem, location, RV_TRUE, "emaReturnFromCallback");
}
else
{
/* We didn't delete this element... */
status = RV_TRUE;
}
return status;
}
/************************************************************************
* emaSetApplicationHandle
* purpose: Set the application handle of an element in EMA
* input : elem - Element in EMA
* appHandle - Application's handle for the element
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -