static ClRcT clAmsListHeadDelete(ClAmsListHeadT *pList)
{
    while(!CL_LIST_HEAD_EMPTY(&pList->list))
    {
        ClListHeadT *pFirst = pList->list.pNext;
        ClAmsEntityTriggerT *pEntityTrigger = CL_LIST_ENTRY(pFirst, ClAmsEntityTriggerT, list);
        clListDel(pFirst);
        clHeapFree(pEntityTrigger);
    }
    pList->numElements = 0;
    return CL_OK;
}
static ClAmsTestEntitiesMarkerT *clAmsTestEntityFindMarker(const ClCharT *pName)
{
    register ClListHeadT *pTemp;
    ClListHeadT *pHead = &gClAmsTestEntitiesMarkerList;
    CL_LIST_FOR_EACH(pTemp,pHead)
    {
        ClAmsTestEntitiesMarkerT *pMarker = CL_LIST_ENTRY(pTemp,ClAmsTestEntitiesMarkerT,list);
        if(!strcmp(pMarker->pName,pName))
        {
            return pMarker;
        }
    }
static ClRcT transportNotifyRegistrants(ClIocPhysicalAddressT *compAddr, ClUint32T status)
{
    ClListHeadT *iter, *next = NULL;
    for(iter = gClXportNotifyRegistrants.pNext; iter != &gClXportNotifyRegistrants;
        iter = next)
    {
        ClTransportNotifyRegistrantT *registrant;
        next = iter->pNext;
        registrant = CL_LIST_ENTRY(iter, ClTransportNotifyRegistrantT, list);
        registrant->callback(compAddr, status, registrant->arg);
    }
    return CL_OK;
}
/*
 * To be called during a reset or a free of the loads.
 */
void clAmsTestEntityUnmark(void)
{
    ClListHeadT *pHead = &gClAmsTestEntitiesMarkerList;
    if(gClAmsTestEntitiesMarker == CL_FALSE)
        return;
    gClAmsTestEntitiesMarker = CL_FALSE;
    while(!CL_LIST_HEAD_EMPTY(pHead))
    {
        ClListHeadT *pTemp = pHead->pNext;
        ClAmsTestEntitiesMarkerT *pMarker = CL_LIST_ENTRY(pTemp,ClAmsTestEntitiesMarkerT,list);
        clAmsTestEntityDeleteMarker(pMarker);
        clListDel(pTemp);
        free(pMarker);
    }
}
ClRcT clAmsEntityTriggerLoadAll(ClMetricT *pMetric)
{
    ClAmsEntityTriggerT *pEntityTrigger = NULL;
    ClListHeadT *pHead = &gClAmsEntityTriggerList.list.list;
    register ClListHeadT *pTemp ;

#ifdef VXWORKS_BUILD
    return CL_AMS_RC(CL_ERR_NOT_SUPPORTED);
#endif

    clOsalMutexLock(&gClAmsEntityTriggerList.list.mutex);
    CL_LIST_FOR_EACH(pTemp, pHead)
    {
        pEntityTrigger = CL_LIST_ENTRY(pTemp, ClAmsEntityTriggerT, list);
        clAmsEntityTriggerUpdate(pEntityTrigger, pMetric);
        clAmsEntityTriggerCheck(pEntityTrigger, pMetric);
    }
ClRcT clTransportNotifyDeregister(ClTransportNotifyCallbackT callback)
{
    ClListHeadT *iter, *next = NULL;
    ClTransportNotifyRegistrantT *registrant;

    for(iter = gClXportNotifyRegistrants.pNext; iter != &gClXportNotifyRegistrants;
        iter = next)
    {
        next = iter->pNext;
        registrant = CL_LIST_ENTRY(iter, ClTransportNotifyRegistrantT, list);
        if(registrant->callback == callback)
        {
            clListDel(&registrant->list);
            clHeapFree(registrant);
            return CL_OK;
        }
    }

    return CL_ERR_NOT_EXIST;
}
/*
 * The recovery thread for entity threshold.
 */
static ClPtrT clAmsEntityTriggerRecoveryThread(ClPtrT pArg)
{
#define MAX_RECOVERY_MASK (0x3)

    static ClInt32T numRecovery = 0;
    ClTimerTimeOutT timeout = { 0,  0 };
    ClTimerTimeOutT delay =   { 0,  500 };

    static ClAmsListHeadT recoveryList = { 0, CL_LIST_HEAD_INITIALIZER(recoveryList.list) };
    clOsalMutexLock(&gClAmsEntityTriggerRecoveryCtrl.list.mutex);
    while(gClAmsEntityTriggerRecoveryCtrl.running == CL_TRUE)
    {
        ClListHeadT *pNext = NULL;

        while(!gClAmsEntityTriggerRecoveryCtrl.list.numElements)
        {
            numRecovery = 0;
            clOsalCondWait(&gClAmsEntityTriggerRecoveryCtrl.list.cond,
                           &gClAmsEntityTriggerRecoveryCtrl.list.mutex,
                           timeout);
            if(gClAmsEntityTriggerRecoveryCtrl.running == CL_FALSE)
                goto out_drain;
        }
        /*
         * We are here when the recovery list isn't empty.
         * We shove the existing recovery batch into the temp list 
         * and reset the main list to release the lock and go lockless.
         */
        recoveryList.numElements = gClAmsEntityTriggerRecoveryCtrl.list.numElements;
        gClAmsEntityTriggerRecoveryCtrl.list.numElements = 0;
        pNext = gClAmsEntityTriggerRecoveryCtrl.list.list.pNext;
        clListDelInit(&gClAmsEntityTriggerRecoveryCtrl.list.list);
        clListAddTail(pNext, &recoveryList.list);
        clOsalMutexUnlock(&gClAmsEntityTriggerRecoveryCtrl.list.mutex);
        
        while(gClAmsEntityTriggerRecoveryCtrl.running == CL_TRUE
              &&
              recoveryList.numElements > 0
              &&
              !CL_LIST_HEAD_EMPTY(&recoveryList.list))
        {
            ClListHeadT *pFirst = recoveryList.list.pNext;
            ClAmsEntityTriggerT *pEntityTrigger = CL_LIST_ENTRY(pFirst, ClAmsEntityTriggerT, list);
            
            /*
             * Take a break incase you have done some recoveries
             */
            if(numRecovery && !(numRecovery & MAX_RECOVERY_MASK))
            {
                clOsalTaskDelay(delay);
            }
            ++numRecovery;
            numRecovery &= 0xffff;
            /*
             * Unlink the entry from the recovery list.
             */
            clListDel(pFirst);
            clAmsEntityTriggerRecovery(pEntityTrigger);
            clHeapFree(pEntityTrigger);
            --recoveryList.numElements;
        }

        clOsalMutexLock(&gClAmsEntityTriggerRecoveryCtrl.list.mutex);

        if(gClAmsEntityTriggerRecoveryCtrl.running == CL_FALSE)
        {
            goto out_drain;
        }

    }

    /*
     * Drain the entries holding the lock.
     */
    out_drain:
    clAmsListHeadDelete(&recoveryList);
    clAmsListHeadDelete(&gClAmsEntityTriggerRecoveryCtrl.list);
    clOsalMutexUnlock(&gClAmsEntityTriggerRecoveryCtrl.list.mutex);
    
    return NULL;
}