📄 ema.c
字号:
************************************************************************/
EMAElement emaAdd(IN HEMA emaH, IN void* appHandle)
{
emaObject* ema = (emaObject *)emaH;
emaElem* elem;
char* ptr;
int location;
/* Use RA for our purposes */
RvLockGet(&ema->lock);
location = raAdd(ema->ra, (RAElement*)&elem);
RvLockRelease(&ema->lock);
/* Make sure it was allocated */
if (location < 0)
{
RvLogError(&ema->log,
(&ema->log, "emaAdd (%s): Out of resources", raGetName(ema->ra)));
return NULL;
}
/* Set the element's OO information */
elem->ema = ema;
elem->flags = 0;
elem->appHandle = appHandle;
#ifdef RV_EMA_DEBUG
elem->debug1 = EMA_DEBUG_BYTES;
elem->debug2 = EMA_DEBUG_BYTES;
#endif
RvLogDebug(&ema->log,
(&ema->log, "emaAdd (%s): Got 0x%p (location=%d)", raGetName(ema->ra), elem, location));
ptr = (char*)elem + sizeof(emaElem);
/* Allocate a mutex if necessary */
switch (ema->lockType)
{
case emaLinkedLocks: memset(ptr + ema->elemSize, 0, sizeof(EMAElement*)); break;
default: break;
}
/* Calculate and return the position of the true element */
return (EMAElement*)ptr;
}
/************************************************************************
* emaDelete
* purpose: Delete an element from EMA
* input : elem - Element to delete
* return : Negative value on failure
************************************************************************/
#ifdef RV_EMA_DEBUG
int emaDeleteDebug(IN EMAElement elem, IN const char* filename, IN int lineno)
#else
int emaDelete(IN EMAElement elem)
#endif
{
emaObject* ema;
emaElem* rElem;
int location;
if (elem == NULL) return RV_ERROR_UNKNOWN;
/* Find out our element information */
rElem = (emaElem *)((char*)elem - sizeof(emaElem));
ema = rElem->ema;
/* Find the location */
location = raGetByPtr(ema->ra, rElem);
#ifdef RV_EMA_DEBUG
RvLogDebug(&ema->log,
(&ema->log, "emaDelete (%s): Deleting %d,0x%p,refCount=%d (%s:%d)",
raGetName(ema->ra), location, rElem,
EMA_GET_REFERENCE(rElem), filename, lineno));
#else
RvLogDebug(&ema->log,
(&ema->log, "emaDelete (%s): Deleting %d,0x%p (refCount=%d)",
raGetName(ema->ra), location, rElem,
EMA_GET_REFERENCE(rElem)));
#endif
#ifdef RV_EMA_DEBUG
if ((rElem->debug1 != EMA_DEBUG_BYTES) || (rElem->debug2 != EMA_DEBUG_BYTES))
{
RvLogExcep(&ema->log,
(&ema->log, "emaDelete (%s): Someone is messing with memory 0x%p", raGetName(ema->ra), rElem));
}
#endif
/* Check the reference count */
if (rElem->flags == 0)
{
/* No one is looking for this guy - we can delete it */
emaDeleteElement(ema, rElem, location, RV_FALSE, "emaDelete");
}
else
{
RvLockGet(&ema->lock);
#ifdef RV_EMA_DEBUG
if ((rElem->flags & EMA_ALREADY_DELETED) != 0)
{
RvLogExcep(&ema->log,
(&ema->log, "emaDelete (%s): Deleting an element 0x%p for the second time",
raGetName(ema->ra), rElem));
}
#endif
ema->markCount++;
rElem->flags |= EMA_ALREADY_DELETED;
RvLockRelease(&ema->lock);
}
return 0;
}
/************************************************************************
* emaLinkToElement
* purpose: Link an EMA element to another element, from a different
* EMA construct. This function should be used when the EMA we're
* dealing with was created with emaLinkedLocks. This function
* allows the element to use a different element's lock.
* This function will only work if the element has no reference
* count at present.
* input : elem - Element to link
* otherElem - Element we're linking to. Should be constructed
* with emaNormalLocks or linked to such element.
* output : none
* return : Non-negative value on success
* Negative value on failure
************************************************************************/
int emaLinkToElement(IN EMAElement elem, IN EMAElement otherElem)
{
emaObject* ema;
emaElem* rElem;
EMAElement* parent;
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 the element */
if (ema == NULL) return RV_ERROR_UNKNOWN;
RvLogDebug(&ema->log,
(&ema->log, "emaLinkToElement (%s): Linking 0x%p to 0x%p", raGetName(ema->ra), rElem, otherElem));
#ifdef RV_EMA_DEBUG
if (ema->lockType != emaLinkedLocks)
{
RvLogExcep(&ema->log,
(&ema->log, "emaLinkToElement (%s): This EMA cannot be linked", raGetName(ema->ra)));
return RV_ERROR_UNKNOWN;
}
#endif
/* Find place of parent */
parent = (EMAElement*)((char*)elem + ema->elemSize);
if (EMA_GET_REFERENCE(rElem) > 0)
{
RvLogError(&ema->log,
(&ema->log, "emaLinkToElement (%s): Cannot link 0x%p - has a positive reference count",
raGetName(ema->ra), rElem));
return RV_ERROR_UNKNOWN;
}
*parent = otherElem;
return 0;
}
/************************************************************************
* emaLock
* purpose: Lock an element in EMA for use from the executing thread only
* This function will succeed only if the element exists
* input : elem - Element to lock
* output : none
* return : RV_TRUE - When the element exists and was locked
* RV_FALSE - When the element doesn't exist (NULL are was deleted)
* In this case, there's no need to call emaUnlock().
************************************************************************/
#ifdef RV_EMA_DEBUG
RvBool emaLockDebug(IN EMAElement elem, IN const char* filename, IN int lineno)
#else
RvBool emaLock(IN EMAElement elem)
#endif
{
emaObject* ema;
emaElem* rElem;
RvBool status = RV_TRUE;
EMAElement parent = NULL;
#ifdef RV_EMA_DEBUG_DEADLOCKS
RvThreadId curThreadId = RvThreadCurrentId();
#endif
if (elem == NULL) return RV_FALSE;
/* Find out our element information */
rElem = (emaElem *)((char*)elem - sizeof(emaElem));
ema = rElem->ema;
/* Make sure we've got the element */
if (ema == NULL) return RV_FALSE;
#ifdef RV_EMA_DEBUG
RvLogDebug(&ema->log,
(&ema->log, "emaLock (%s): Locking 0x%p (%s:%d)", raGetName(ema->ra), rElem, filename, lineno));
#endif
switch (ema->lockType)
{
#ifdef RV_EMA_DEBUG
case emaNoLocks:
RvLogExcep(&ema->log,
(&ema->log, "emaLock (%s): This EMA cannot be locked", raGetName(ema->ra)));
break;
#endif
case emaNormalLocks:
/* We lock it */
RvMutexLock((RvMutex *)((char*)elem + ema->elemSize));
/* Now that it's locked, see if the element still exists */
if (rElem->ema == NULL)
{
/* Seems like someone has deleted this element when we were trying to lock it */
#ifdef RV_EMA_DEBUG
RvLogDebug(&ema->log,
(&ema->log, "emaLock (%s): Unlocking deleted element 0x%p", raGetName(ema->ra), rElem));
#endif
status = RV_FALSE;
/* Release the lock - we shouldn't go on with it */
RvMutexUnlock((RvMutex *)((char*)elem + ema->elemSize));
}
break;
case emaLinkedLocks:
{
/* We lock the parent */
parent = *((EMAElement*)((char*)elem + ema->elemSize));
if (parent != NULL)
status = emaLock(parent);
else
status = RV_FALSE;
if (status == RV_FALSE)
{
RvLogWarning(&ema->log,
(&ema->log, "emaLock (%s): Couldn't lock parent=0x%p of 0x%p for some reason",
raGetName(ema->ra), parent, elem));
}
break;
}
default:
break;
}
/* Make sure we increment the reference count on this one */
if (status == RV_TRUE)
{
#ifdef RV_EMA_DEBUG_DEADLOCKS
rElem->lockedThread = curThreadId;
#ifdef RV_EMA_DEBUG
rElem->filename = filename;
rElem->lineno = lineno;
#endif
#endif
EMA_INC_REFERENCE(rElem,1);
EMA_INC_LOCKS(rElem,1);
}
return status;
}
/************************************************************************
* emaUnlock
* purpose: Unlock an element in EMA that were previously locked by
* emaLock() from the same thread
* input : elem - Element to unlock
* 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 emaUnlockDebug(IN EMAElement elem, IN const char* filename, IN int lineno)
#else
int emaUnlock(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,
"emaUnlock (%s): Unlocking 0x%p (%s:%d)", raGetName(ema->ra), rElem, filename, lineno));
if (EMA_GET_LOCKS(rElem) == 0)
{
RvLogExcep(&ema->log, (&ema->log,
"emaUnlock (%s): Element 0x%p (%s:%d) is not locked!", raGetName(ema->ra), rElem, filename, lineno));
return RV_OK;
}
#endif
EMA_DEC_REFERENCE(rElem,1);
EMA_DEC_LOCKS(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, "emaUnlock");
}
switch (ema->lockType)
{
#ifdef RV_EMA_DEBUG
case emaNoLocks:
RvLogExcep(&ema->log,
(&ema->log, "emaUnlock (%s): This EMA cannot be unlocked", raGetName(ema->ra)));
break;
#endif
case emaNormalLocks:
/* We lock it */
RvMutexUnlock((RvMutex *)((char*)elem + ema->elemSize));
break;
case emaLinkedLocks:
{
/* We lock the parent */
int result = RV_ERROR_UNKNOWN;
EMAElement parent = *((EMAElement*)((char*)elem + ema->elemSize));
if (parent != NULL)
result = emaUnlock(parent);
if (result < 0)
{
RvLogWarning(&ema->log,
(&ema->log, "emaUnlock (%s): Couldn't unlock parent=0x%p of 0x%p for some reason",
raGetName(ema->ra), parent, elem));
elemExists = result;
}
break;
}
default:
break;
}
return elemExists;
}
/************************************************************************
* emaMark
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -