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;
}
/*
 * 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);
    }
}
/*
 * 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;
}