示例#1
0
//--------------------------------------------------------------------------------------------------
le_sem_Ref_t CreateSemaphore
(
    const char* nameStr,
    int         initialCount,
    bool        isTraceable
)
//--------------------------------------------------------------------------------------------------
{
    // Allocate a semaphore object and initialize it.
    Semaphore_t* semaphorePtr = le_mem_ForceAlloc(SemaphorePoolRef);
    semaphorePtr->semaphoreListLink = LE_DLS_LINK_INIT;
    semaphorePtr->waitingList = LE_DLS_LIST_INIT;
    pthread_mutex_init(&semaphorePtr->waitingListMutex, NULL);  // Default attributes = Fast mutex.
    semaphorePtr->isTraceable = isTraceable;
    if (le_utf8_Copy(semaphorePtr->nameStr, nameStr, sizeof(semaphorePtr->nameStr), NULL) == LE_OVERFLOW)
    {
        LE_WARN("Semaphore name '%s' truncated to '%s'.", nameStr, semaphorePtr->nameStr);
    }

    // Initialize the underlying POSIX semaphore shared between thread.
    int result = sem_init(&semaphorePtr->semaphore,0, initialCount);
    if (result != 0)
    {
        LE_FATAL("Failed to set the semaphore . errno = %d (%m).", errno);
    }

    // Add the semaphore to the process's Semaphore List.
    LOCK_SEMAPHORE_LIST();
    le_dls_Queue(&SemaphoreList, &semaphorePtr->semaphoreListLink);
    UNLOCK_SEMAPHORE_LIST();

    return semaphorePtr;
}
示例#2
0
文件: mem.c 项目: tegoo/legato-af
//--------------------------------------------------------------------------------------------------
le_mem_PoolRef_t _le_mem_CreatePool
(
    const char*     componentName,  ///< [IN] Name of the component.
    const char*     name,           ///< [IN] Name of the pool inside the component.
    size_t      objSize ///< [IN] The size of the individual objects to be allocated from this pool
                        /// (in bytes).  E.g., sizeof(MyObject_t).
)
{
    le_mem_PoolRef_t newPool = malloc(sizeof(MemPool_t));

    // Crash if we can't create the memory pool.
    LE_ASSERT(newPool);

    // Initialize the memory pool.
    InitPool(newPool, componentName, name, objSize);

    Lock();

    // Generate an error if there are multiple pools with the same name.
    VerifyUniquenessOfName(newPool);

    // Add the new pool to the list of pools.
    ListOfPoolsChgCnt++;
    le_dls_Queue(&ListOfPools, &(newPool->poolLink));

    Unlock();

    return newPool;
}
示例#3
0
//--------------------------------------------------------------------------------------------------
le_mrc_ScanInformation_Ref_t le_mrc_GetFirstCellularNetworkScan
(
    le_mrc_ScanInformation_ListRef_t  scanInformationListRef ///< [IN] The list of scan information.
)
{
    pa_mrc_ScanInformation_t* nodePtr;
    le_dls_Link_t*          linkPtr;

    le_mrc_ScanInformationList_t* scanInformationListPtr = le_ref_Lookup(ScanInformationListRefMap,
                                                                         scanInformationListRef);

    if (scanInformationListPtr == NULL)
    {
        LE_KILL_CLIENT("Invalid reference (%p) provided!", scanInformationListRef);
        return NULL;
    }

    linkPtr = le_dls_Peek(&(scanInformationListPtr->paScanInformationList));
    if (linkPtr != NULL)
    {
        nodePtr = CONTAINER_OF(linkPtr, pa_mrc_ScanInformation_t, link);
        scanInformationListPtr->currentLink = linkPtr;

        le_mrc_ScanInformationSafeRef_t* newScanInformationPtr = le_mem_ForceAlloc(ScanInformationSafeRefPool);
        newScanInformationPtr->safeRef = le_ref_CreateRef(ScanInformationRefMap,nodePtr);
        newScanInformationPtr->link = LE_DLS_LINK_INIT;
        le_dls_Queue(&(scanInformationListPtr->safeRefScanInformationList),&(newScanInformationPtr->link));

        return (le_mrc_ScanInformation_Ref_t)newScanInformationPtr->safeRef;
    }
    else
    {
        return NULL;
    }
}
示例#4
0
//--------------------------------------------------------------------------------------------------
static void AppendNetworkScanResult
(
    le_mrc_Rat_t   rat,                   /// [IN] Requested simulated RAT result
    le_dls_List_t *scanInformationListPtr ///< [OUT] list of pa_mrc_ScanInformation_t
)
{
    pa_mrc_ScanInformation_t *newScanInformationPtr = NULL;

    char mccStr[LE_MRC_MCC_BYTES];
    char mncStr[LE_MRC_MNC_BYTES];

    newScanInformationPtr = le_mem_ForceAlloc(ScanInformationPool);

    memset(newScanInformationPtr, 0, sizeof(*newScanInformationPtr));
    newScanInformationPtr->link = LE_DLS_LINK_INIT;

    // @TODO Default to SIM MCC/MNC
    strcpy(mccStr, PA_SIMU_SIM_DEFAULT_MCC);
    strcpy(mncStr, PA_SIMU_SIM_DEFAULT_MNC);

    newScanInformationPtr->rat = rat;
    strcpy(newScanInformationPtr->mobileCode.mcc, mccStr);
    strcpy(newScanInformationPtr->mobileCode.mnc, mncStr);
    newScanInformationPtr->isInUse = IsNetworkInUse(rat, mccStr, mncStr);
    newScanInformationPtr->isAvailable = !(newScanInformationPtr->isInUse);
    newScanInformationPtr->isHome = true;
    newScanInformationPtr->isForbidden = false;

    le_dls_Queue(scanInformationListPtr, &(newScanInformationPtr->link));
}
示例#5
0
//--------------------------------------------------------------------------------------------------
void atmachinestring_AddInList
(
    le_dls_List_t *list,          ///< List of atmachinestring_t
    const char   **patternListPtr ///< List of pattern
)
{
    uint32_t i = 0;

    if (!patternListPtr) {
        return;
    }

    while(patternListPtr[i] != NULL) {
        atmachinestring_t* newStringPtr = le_mem_ForceAlloc(AtStringPool);

        LE_FATAL_IF(
            (strlen(patternListPtr[i])>ATSTRING_SIZE),
                    "%s is too long (%zd): Max size %d",
                    patternListPtr[i],strlen(patternListPtr[i]),ATSTRING_SIZE);

        strncpy(newStringPtr->line,patternListPtr[i],ATSTRING_SIZE);
        newStringPtr->line[ATSTRING_SIZE-1]='\0';

        newStringPtr->link = LE_DLS_LINK_INIT;
        le_dls_Queue(list,&(newStringPtr->link));
        i++;
    }
}
示例#6
0
//--------------------------------------------------------------------------------------------------
static le_result_t GetFirmwareItem
(
    json_t *jsonItemPtr,                    ///<[IN] json object containing firmware item.
    Manifest_t *manPtr                      ///<[IN] Object containing manifest header.
)
{
    Item_t* item = le_mem_ForceAlloc(ItemPoolRef);

    item->type = LE_UPDATE_FIRMWARE;

    // Now add item in the linked list
    le_dls_Queue(&(manPtr->itemList), &(item->link));

    memset((item->ActionItem).firmware.version,
           0,
           sizeof((item->ActionItem).firmware.version));

    // Get firmware version. This is optional field
    le_result_t result = GetJsonStrField(jsonItemPtr,
                                         JSON_FIELD_VERSION,
                                         (item->ActionItem).firmware.version,
                                         sizeof((item->ActionItem).firmware.version));

    result = GetJsonSizeField(jsonItemPtr,
                              JSON_FIELD_SIZE,
                              &((item->ActionItem).firmware.size));
    LE_DEBUG("Got firmware item: %p, size: %zd",
              item,
              (item->ActionItem).firmware.size);

    return result;
}
示例#7
0
//--------------------------------------------------------------------------------------------------
le_mcc_CallRef_t le_mcc_Create
(
    const char* phoneNumPtr
        ///< [IN]
        ///< The target number we are going to
        ///< call.
)
{
    if (phoneNumPtr == NULL)
    {
        LE_KILL_CLIENT("phoneNumPtr is NULL !");
        return NULL;
    }

    if(strlen(phoneNumPtr) > (LE_MDMDEFS_PHONE_NUM_MAX_BYTES-1))
    {
        LE_KILL_CLIENT("strlen(phoneNumPtr) > %d", (LE_MDMDEFS_PHONE_NUM_MAX_BYTES-1));
        return NULL;
    }

    // Create the Call object.
    le_mcc_Call_t* mccCallPtr = GetCallObject(phoneNumPtr, -1, false);

    if (mccCallPtr != NULL)
    {
        le_mem_AddRef(mccCallPtr);
        mccCallPtr->refCount++;
    }
    else
    {
        mccCallPtr = CreateCallObject (phoneNumPtr,
                                        -1,
                                        LE_MCC_EVENT_TERMINATED,
                                        LE_MCC_TERM_UNDEFINED,
                                        -1);
    }

    // Manage client session
    SessionRefNode_t* newSessionRefPtr = le_mem_ForceAlloc(SessionRefPool);
    newSessionRefPtr->sessionRef = le_mcc_GetClientSessionRef();
    newSessionRefPtr->link = LE_DLS_LINK_INIT;

    // Add the new sessionRef into the the sessionRef list
    le_dls_Queue(&mccCallPtr->sessionRefList,
                    &(newSessionRefPtr->link));

    if (mccCallPtr==NULL)
    {
        LE_ERROR("mccCallPtr null!!!!");
        return NULL;
    }

    LE_DEBUG("Create Call ref.%p", mccCallPtr->callRef);

    // Return a Safe Reference for this Call object.
    return (mccCallPtr->callRef);
}
示例#8
0
//--------------------------------------------------------------------------------------------------
le_event_FdMonitorRef_t le_event_CreateFdMonitor
(
    const char*     name,       ///< [in] Name of the object (for diagnostics).
    int             fd          ///< [in] File descriptor to be monitored for events.
)
//--------------------------------------------------------------------------------------------------
{
    // Get a pointer to the thread-specific event loop data record.
    event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr();

    // Allocate the object.
    FdMonitor_t* fdMonitorPtr = le_mem_ForceAlloc(FdMonitorPool);

    // Initialize the object.
    fdMonitorPtr->link = LE_DLS_LINK_INIT;
    fdMonitorPtr->fd = fd;
    fdMonitorPtr->threadRecPtr = perThreadRecPtr;
    memset(fdMonitorPtr->handlerArray, 0, sizeof(fdMonitorPtr->handlerArray));

    // To start with, no events are in the set to be monitored.  They will be added as handlers
    // are registered for them. (Although, EPOLLHUP and EPOLLERR will always be monitored
    // regardless of what flags we specify).  We use epoll in "level-triggered mode".
    fdMonitorPtr->epollEvents = 0;

    // Assume that the event should wake up the system; can be changed later.
    fdMonitorPtr->wakeUp = true;

    // Copy the name into it.
    if (le_utf8_Copy(fdMonitorPtr->name, name, sizeof(fdMonitorPtr->name), NULL) == LE_OVERFLOW)
    {
        LE_WARN("FD Monitor object name '%s' truncated to '%s'.", name, fdMonitorPtr->name);
    }

    LOCK

    // Create a safe reference for the object.
    fdMonitorPtr->safeRef = le_ref_CreateRef(FdMonitorRefMap, fdMonitorPtr);

    // Add it to the thread's FD Monitor list.
    le_dls_Queue(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link);

    // Tell epoll(7) to start monitoring this fd.
    struct epoll_event ev;
    ev.events = fdMonitorPtr->epollEvents;
    ev.data.ptr = fdMonitorPtr->safeRef;
    if (epoll_ctl(perThreadRecPtr->epollFd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        LE_FATAL("epoll_ctl(ADD) failed for fd %d. errno = %d (%m)", fd, errno);
    }

    UNLOCK

    return fdMonitorPtr->safeRef;
}
示例#9
0
//--------------------------------------------------------------------------------------------------
void msgService_AddSession
(
    le_msg_ServiceRef_t serviceRef,
    le_msg_SessionRef_t sessionRef
)
//--------------------------------------------------------------------------------------------------
{
    // The Session object holds a reference to the Service object.
    le_mem_AddRef(serviceRef);

    le_dls_Queue(&serviceRef->sessionList, msgSession_GetListLink(sessionRef));
}
示例#10
0
//--------------------------------------------------------------------------------------------------
static void AddToWaitingList
(
    Semaphore_t*        semaphorePtr,
    sem_ThreadRec_t*    perThreadRecPtr
)
//--------------------------------------------------------------------------------------------------
{
    LOCK_WAITING_LIST(semaphorePtr);

    le_dls_Queue(&semaphorePtr->waitingList, &perThreadRecPtr->waitingListLink);

    UNLOCK_WAITING_LIST(semaphorePtr);
}
示例#11
0
//--------------------------------------------------------------------------------------------------
static le_result_t GetAppItem
(
    json_t *jsonItemPtr,                    ///<[IN] json object containing App item.
    Manifest_t *manPtr                      ///<[IN] Object containing manifest header.
)
{
    Item_t* item = le_mem_ForceAlloc(ItemPoolRef);

    item->type = LE_UPDATE_APP;
    // Now add item in the linked list
    le_dls_Queue(&(manPtr->itemList), &(item->link));

    // Get AppName
    if (GetJsonStrField(jsonItemPtr, JSON_FIELD_NAME,
                        (item->ActionItem).app.appName,
                        sizeof((item->ActionItem).app.appName)) != LE_OK)
    {
        return LE_FAULT;
    }

    le_update_Command_t command;
    le_result_t result = GetCommand(jsonItemPtr, &command);

    if (result == LE_OK)
    {
        switch(command)
        {
            case LE_UPDATE_CMD_INSTALL:
                result = GetJsonSizeField(jsonItemPtr,
                                          JSON_FIELD_SIZE,
                                          &(item->ActionItem.app.size));
                break;
            case LE_UPDATE_CMD_REMOVE:
                // Ignore size field and set it to zero.
                (item->ActionItem).app.size = 0;
                break;
        }
        (item->ActionItem).app.command = command;
    }
    LE_DEBUG("Got app item: %p, size: %zd",
              item,
              (item->ActionItem).app.size);
    return result;
}
示例#12
0
文件: mem.c 项目: tegoo/legato-af
//--------------------------------------------------------------------------------------------------
le_mem_PoolRef_t _le_mem_CreateSubPool
(
    le_mem_PoolRef_t    superPool,  ///< [IN] The super-pool.
    const char*     componentName,  ///< [IN] Name of the component.
    const char*     name,           ///< [IN] Name of the pool inside the component.
    size_t              numObjects  ///< [IN] The number of objects to take from the super-pool.
)
{
    LE_ASSERT(superPool != NULL);

    // Make sure the parent pool is not itself a sub-pool.
    LE_ASSERT(superPool->superPoolPtr == NULL);

    // Get a sub-pool from the pool of sub-pools.
    le_mem_PoolRef_t subPool = le_mem_ForceAlloc(SubPoolsPool);

    // Initialize the pool.
    InitPool(subPool, componentName, name, superPool->userDataSize);
    subPool->superPoolPtr = superPool;

    Lock();

    // Log an error if the pool name is not unique.
    VerifyUniquenessOfName(subPool);

    // Add the sub-pool to the list of pools.
    ListOfPoolsChgCnt++;
    le_dls_Queue(&ListOfPools, &(subPool->poolLink));

    Unlock();

    // Expand the pool to its initial size.
    // Note:    This moves blocks from the parent pool to the sub pool, expanding the parent pool,
    //          if necessary.
    le_mem_ExpandPool(subPool, numObjects);

    // Inherit the parent pool's destructor.
    subPool->destructor = superPool->destructor;

    return subPool;
}
示例#13
0
//--------------------------------------------------------------------------------------------------
le_fdMonitor_Ref_t le_fdMonitor_Create
(
    const char*             name,       ///< [in] Name of the object (for diagnostics).
    int                     fd,         ///< [in] File descriptor to be monitored for events.
    le_fdMonitor_HandlerFunc_t handlerFunc, ///< [in] Handler function.
    short                   events      ///< [in] Initial set of events to be monitored.
)
//--------------------------------------------------------------------------------------------------
{
    // Get a pointer to the thread-specific event loop data record.
    event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr();

    // Allocate the object.
    FdMonitor_t* fdMonitorPtr = le_mem_ForceAlloc(FdMonitorPool);

    // Initialize the object.
    fdMonitorPtr->link = LE_DLS_LINK_INIT;
    fdMonitorPtr->fd = fd;
    fdMonitorPtr->epollEvents = PollToEPoll(events) | EPOLLWAKEUP;  // Non-deferrable by default.
    fdMonitorPtr->isAlwaysReady = false;
    fdMonitorPtr->threadRecPtr = perThreadRecPtr;
    fdMonitorPtr->handlerFunc = handlerFunc;
    fdMonitorPtr->contextPtr = NULL;

    // Copy the name into it.
    if (le_utf8_Copy(fdMonitorPtr->name, name, sizeof(fdMonitorPtr->name), NULL) == LE_OVERFLOW)
    {
        LE_WARN("FD Monitor object name '%s' truncated to '%s'.", name, fdMonitorPtr->name);
    }

    LOCK

    // Create a safe reference for the object.
    fdMonitorPtr->safeRef = le_ref_CreateRef(FdMonitorRefMap, fdMonitorPtr);

    // Add it to the thread's FD Monitor list.
    le_dls_Queue(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link);

    // Tell epoll(7) to start monitoring this fd.
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.events = fdMonitorPtr->epollEvents;
    ev.data.ptr = fdMonitorPtr->safeRef;
    if (epoll_ctl(perThreadRecPtr->epollFd, EPOLL_CTL_ADD, fd, &ev) == -1)
    {
        if (errno == EPERM)
        {
            LE_DEBUG("fd %d doesn't support epoll(), assuming always readable and writeable.", fd);
            fdMonitorPtr->isAlwaysReady = true;

            // If either EPOLLIN or EPOLLOUT are enabled, queue up the handler for this now.
            uint32_t epollEvents = fdMonitorPtr->epollEvents & (EPOLLIN | EPOLLOUT);
            if (epollEvents != 0)
            {
                fdMon_Report(fdMonitorPtr->safeRef, epollEvents);
            }
        }
        else
        {
            LE_FATAL("epoll_ctl(ADD) failed for fd %d. errno = %d (%m)", fd, errno);
        }
    }

    UNLOCK

    return fdMonitorPtr->safeRef;
}
示例#14
0
//--------------------------------------------------------------------------------------------------
void le_sig_SetEventHandler
(
    int sigNum,                                 ///< The signal to set the event handler for.  See
                                                ///  parameter documentation in comments above.
    le_sig_EventHandlerFunc_t sigEventHandler   ///< The event handler to call when a signal is
                                                ///  received.
)
{
    // Check parameters.
    if ( (sigNum == SIGKILL) || (sigNum == SIGSTOP) || (sigNum == SIGFPE) || (sigNum == SIGILL) ||
         (sigNum == SIGSEGV) || (sigNum == SIGBUS) || (sigNum == SIGABRT) || (sigNum == SIGIOT) ||
         (sigNum == SIGTRAP) || (sigNum == SIGSYS) )
    {
        LE_FATAL("Signal event handler for %s is not allowed.", strsignal(sigNum));
    }

    // Get the monitor object for this thread.
    MonitorObj_t* monitorObjPtr = pthread_getspecific(SigMonKey);

    if (monitorObjPtr == NULL)
    {
        if (sigEventHandler == NULL)
        {
            // Event handler already does not exist so we don't need to do anything, just return.
            return;
        }
        else
        {
            // Create the monitor object
            monitorObjPtr = le_mem_ForceAlloc(MonitorObjPool);
            monitorObjPtr->handlerObjList = LE_DLS_LIST_INIT;
            monitorObjPtr->fd = -1;
            monitorObjPtr->monitorRef = NULL;

            // Add it to the thread's local data.
            LE_ASSERT(pthread_setspecific(SigMonKey, monitorObjPtr) == 0);
        }
    }

    // See if a handler for this signal already exists.
    HandlerObj_t* handlerObjPtr = FindHandlerObj(sigNum, &(monitorObjPtr->handlerObjList));

    if (handlerObjPtr == NULL)
    {
        if (sigEventHandler == NULL)
        {
            // Event handler already does not exist so we don't need to do anything, just return.
            return;
        }
        else
        {
            // Create the handler object.
            handlerObjPtr = le_mem_ForceAlloc(HandlerObjPool);

            // Set the handler.
            handlerObjPtr->link = LE_DLS_LINK_INIT;
            handlerObjPtr->handler = sigEventHandler;
            handlerObjPtr->sigNum = sigNum;

            // Add the handler object to the list.
            le_dls_Queue(&(monitorObjPtr->handlerObjList), &(handlerObjPtr->link));
        }
    }
    else
    {
        if (sigEventHandler == NULL)
        {
            // Remove the handler object from the list.
            le_dls_Remove(&(monitorObjPtr->handlerObjList), &(handlerObjPtr->link));
        }
        else
        {
            // Just update the handler.
            handlerObjPtr->handler = sigEventHandler;
        }
    }

    // Recreate the signal mask.
    sigset_t sigSet;
    LE_ASSERT(sigemptyset(&sigSet) == 0);

    le_dls_Link_t* handlerLinkPtr = le_dls_Peek(&(monitorObjPtr->handlerObjList));
    while (handlerLinkPtr != NULL)
    {
        HandlerObj_t* handlerObjPtr = CONTAINER_OF(handlerLinkPtr, HandlerObj_t, link);

        LE_ASSERT(sigaddset(&sigSet, handlerObjPtr->sigNum) == 0);

        handlerLinkPtr = le_dls_PeekNext(&(monitorObjPtr->handlerObjList), handlerLinkPtr);
    }

    // Update or create the signal fd.
    monitorObjPtr->fd = signalfd(monitorObjPtr->fd, &sigSet, SFD_NONBLOCK);

    if (monitorObjPtr->fd == -1)
    {
        LE_FATAL("Could not set signal event handler: %m");
    }

    // Create a monitor fd if it doesn't already exist.
    if (monitorObjPtr->monitorRef == NULL)
    {
        // Create the monitor name using SIG_STR + thread name.
        char monitorName[LIMIT_MAX_THREAD_NAME_BYTES + sizeof(SIG_STR)] = SIG_STR;

        LE_ASSERT(le_utf8_Copy(monitorName + sizeof(SIG_STR),
                               le_thread_GetMyName(),
                               LIMIT_MAX_THREAD_NAME_BYTES + sizeof(SIG_STR),
                               NULL) == LE_OK);

        // Create the monitor.
        monitorObjPtr->monitorRef = le_fdMonitor_Create(monitorName,
                                                        monitorObjPtr->fd,
                                                        OurSigHandler,
                                                        POLLIN);
    }
}
示例#15
0
static le_result_t TestDoublyLinkLists(size_t maxListSize)
{
    // Node definition.
    typedef struct
    {
        le_dls_Link_t link;
        uint32_t id;  
    }
    idRecord_t;

    int i;
    le_dls_List_t list0, list1;
    le_dls_Link_t* removedLinksPtr0[REMOVE_SIZE] = {NULL};
    le_dls_Link_t* removedLinksPtr1[REMOVE_SIZE] = {NULL};

    printf("\n");
    printf("*** Unit Test for le_doublyLinkedList module. ***\n");

    //
    // Multiple list creation
    //
    // Initialize the lists
    list0 = LE_DLS_LIST_INIT;
    list1 = LE_DLS_LIST_INIT;
    printf("Two doubly linked lists were successfully created.\n");


    //
    // Attempt to query empty list
    //
    if ( (le_dls_Peek(&list0) != NULL) || (le_dls_PeekTail(&list0) != NULL) ||
         (le_dls_Pop(&list0) != NULL) || (le_dls_PopTail(&list0) != NULL) )
    {
        printf("Query of empty list failed: %d", __LINE__);
        return LE_FAULT;
    }
    printf("Query of empty list correct.\n");


    //
    // Node insertions
    //
    {
        idRecord_t* newNodePtr;
        
        // Insert to the tail
        for (i = 0; i < maxListSize; i++)
        {
            // Create the new node
            newNodePtr = (idRecord_t*)malloc(sizeof(idRecord_t));
            newNodePtr->id = i;
            
            // Initialize the link.
            newNodePtr->link = LE_DLS_LINK_INIT;

            // Insert the new node to the tail.
            le_dls_Queue(&list0, &(newNodePtr->link));
        }
        printf("%zu nodes were added to the tail of list0.\n", maxListSize);
        
        // Insert to the head
        for (i = 0; i < maxListSize; i++)
        {
            // Create the new node
            newNodePtr = (idRecord_t*)malloc(sizeof(idRecord_t));
            newNodePtr->id = i;
            
            // Initialize the link.
            newNodePtr->link = LE_DLS_LINK_INIT;

            // Insert the new node to the tail.
            le_dls_Stack(&list1, &(newNodePtr->link));
        }
        printf("%zu nodes were added to the head of list1.\n", maxListSize);
    }

    //
    // Check that all the nodes have been added properly
    //
    {
        idRecord_t* nodePtr;
        le_dls_Link_t* link0Ptr = le_dls_Peek(&list0);
        le_dls_Link_t* link1Ptr = le_dls_PeekTail(&list1);
        
        if ( (link0Ptr == NULL) || (link1Ptr == NULL) )
        {
            printf("Link error: %d", __LINE__);
            return LE_FAULT;
        }
        
        i = 0;
        do
        {
            // Get the node from list 0
            nodePtr = CONTAINER_OF(link0Ptr, idRecord_t, link);

            // Check the node.
            if ( nodePtr->id != i)
            {
                printf("Link error: %d", __LINE__);
                return LE_FAULT;
            }

            // Get the node from list 1
            nodePtr = CONTAINER_OF(link1Ptr, idRecord_t, link);

            // Check the node.
            if ( nodePtr->id != i)
            {
                printf("Link error: %d", __LINE__);
                return LE_FAULT;
            }

            // Move to the next node.
            link0Ptr = le_dls_PeekNext(&list0, link0Ptr);
            link1Ptr = le_dls_PeekPrev(&list1, link1Ptr);
            i++;

        } while (link0Ptr != NULL);
        
        // Make sure everything is correct.
        if ( (i != maxListSize) || (link1Ptr != NULL) )
        {
            printf("Link error: %d", __LINE__);
            return LE_FAULT;
        }
    }
    
    printf("Checked that all nodes added to the head and tails are all correct.\n");
    

    //
    // Remove random nodes
    //

    //seed the random number generator with the clock
    srand((unsigned int)clock());
    
    {
        // Start at the end of the lists and randomly remove links.
        le_dls_Link_t* linkToRemovePtr;
        le_dls_Link_t* link0Ptr = le_dls_PeekTail(&list0);
        le_dls_Link_t* link1Ptr = le_dls_Peek(&list1);
        
        int r0 = 0;
        int r1 = 0;
        do
        {
            // For list 0
            if ( (rand() < REMOVE_THRESHOLD) && (r0 < REMOVE_SIZE) )
            {
                // Mark this node for removal.
                linkToRemovePtr = link0Ptr;
                
                // Move to the next node.
                link0Ptr = le_dls_PeekPrev(&list0, link0Ptr);
                
                // Remove the node.
                le_dls_Remove(&list0, linkToRemovePtr);
                
                // Store the removed node for later use.
                removedLinksPtr0[r0++] = linkToRemovePtr;
            }
            else
            {
                // Just move one
                link0Ptr = le_dls_PeekPrev(&list0, link0Ptr);
            }
            
            
            // For list 1
            if ( (rand() < REMOVE_THRESHOLD) && (r1 < REMOVE_SIZE) )
            {
                // Mark this node for removal.
                linkToRemovePtr = link1Ptr;
                
                // Move to the next node.
                link1Ptr = le_dls_PeekNext(&list1, link1Ptr);
                
                // Remove the node.
                le_dls_Remove(&list1, linkToRemovePtr);
                
                // Store the removed node for later use.
                removedLinksPtr1[r1++] = linkToRemovePtr;
            }
            else
            {
                // Just move to the next node
                link1Ptr = le_dls_PeekNext(&list1, link1Ptr);
            }
        } while (link0Ptr != NULL);
        
        printf("Randomly removed %d nodes from list0.\n", r0);
        printf("Randomly removed %d nodes from list1.\n", r1);
    }


    //
    // Check that the proper nodes were removed
    //
    {
        int numNodesRemoved = 0;
        
        // For list 0.
        // Check that the nodes in the removed nodes are indeed not in the list.
        for (i = 0; i < REMOVE_SIZE; i++)
        {
            if (removedLinksPtr0[i] == NULL)
            {
                break;
            }
            
            if (le_dls_IsInList(&list0, removedLinksPtr0[i]))
            {
                printf("Node removal incorrect: %d", __LINE__);
                return LE_FAULT;
            }
            
            numNodesRemoved++;
        }
        
        // Compare the list count.
        if ( (numNodesRemoved != maxListSize - le_dls_NumLinks(&list0)) || (le_dls_NumLinks(&list0) == maxListSize) )
        {
            printf("Node removal incorrect: %d", __LINE__);
            return LE_FAULT;
        }
        
        // For list 1.
        // Check that the nodes in the removed nodes are indeed not in the list.
        numNodesRemoved = 0;
        for (i = 0; i < REMOVE_SIZE; i++)
        {
            if (removedLinksPtr1[i] == NULL)
            {
                break;
            }
            
            if (le_dls_IsInList(&list1, removedLinksPtr1[i]))
            {
                printf("Node removal incorrect: %d", __LINE__);
                return LE_FAULT;
            }
            
            numNodesRemoved++;
        }
        
        // Compare the list count.
        if ( (numNodesRemoved != maxListSize - le_dls_NumLinks(&list1)) || (le_dls_NumLinks(&list1) == maxListSize) )
        {
            printf("Node removal incorrect: %d", __LINE__);
            return LE_FAULT;
        }
    }
    
    printf("Checked that nodes were removed correctly.\n");
    
    
    //
    // Add the randomly removed nodes back in.
    //
    {        
        idRecord_t *nodePtr, *removedNodePtr;
        le_dls_Link_t* linkPtr;
     
        // For list 0.
        for (i = 0; i < REMOVE_SIZE; i++)
        {
            if (removedLinksPtr0[i] == NULL)
            {
                break;
            }
            
            removedNodePtr = CONTAINER_OF(removedLinksPtr0[i], idRecord_t, link);
            
            if (removedNodePtr->id == maxListSize-1)
            {
                le_dls_Queue(&list0, removedLinksPtr0[i]);
            }
            else
            {            
                // Search the list for the place to insert this.            
                linkPtr = le_dls_PeekTail(&list0);
                do
                {
                    // Get the node
                    nodePtr = CONTAINER_OF(linkPtr, idRecord_t, link);
                    
                    // Find the id that is just before this one.
                    if (nodePtr->id == removedNodePtr->id + 1)
                    {
                        le_dls_AddBefore(&list0, linkPtr, removedLinksPtr0[i]);
                        break;
                    }
                    
                    linkPtr = le_dls_PeekPrev(&list0, linkPtr);
                    
                } while (linkPtr != NULL);
            }
        }
        
        
        // For list 1.
        for (i = 0; i < REMOVE_SIZE; i++)
        {
            if (removedLinksPtr1[i] == NULL)
            {
                break;
            }
            
            removedNodePtr = CONTAINER_OF(removedLinksPtr1[i], idRecord_t, link);
            
            if (removedNodePtr->id == maxListSize-1)
            {
                le_dls_Stack(&list1, removedLinksPtr1[i]);
            }
            else
            {            
                // Search the list for the place to insert this.            
                linkPtr = le_dls_Peek(&list1);
                do
                {
                    // Get the node
                    nodePtr = CONTAINER_OF(linkPtr, idRecord_t, link);
                    
                    // Find the id that is just before this one.
                    if (nodePtr->id == removedNodePtr->id + 1)
                    {
                        le_dls_AddAfter(&list1, linkPtr, removedLinksPtr1[i]);
                        break;
                    }
                    
                    linkPtr = le_dls_PeekNext(&list1, linkPtr);
                    
                } while (linkPtr != NULL);
            }
        }
    }
    
    printf("Added all randomly removed nodes back in.\n");
    
    //Check that the list is correct.
    {
        idRecord_t* nodePtr;
        le_dls_Link_t* link0Ptr = le_dls_Peek(&list0);
        le_dls_Link_t* link1Ptr = le_dls_PeekTail(&list1);
        
        if ( (link0Ptr == NULL) || (link1Ptr == NULL) )
        {
            printf("Link error: %d", __LINE__);
            return LE_FAULT;
        }
        
        i = 0;
        do
        {
            // Get the node from list 0
            nodePtr = CONTAINER_OF(link0Ptr, idRecord_t, link);

            // Check the node.
            if ( nodePtr->id != i)
            {
                printf("Link error: %d", __LINE__);
                return LE_FAULT;
            }
            
            // Get the node from list 1
            nodePtr = CONTAINER_OF(link1Ptr, idRecord_t, link);

            // Check the node.
            if ( nodePtr->id != i)
            {
                printf("Link error: %d", __LINE__);
                return LE_FAULT;
            }        
            
            // Move to the next node.
            link0Ptr = le_dls_PeekNext(&list0, link0Ptr);
            link1Ptr = le_dls_PeekPrev(&list1, link1Ptr);
            i++;
            
        } while (link0Ptr != NULL);
        
        // Make sure everything is correct.
        if ( (i != maxListSize) || (link1Ptr != NULL) )
        {
            printf("Link error: %d", __LINE__);
            return LE_FAULT;
        }
    }
    
    printf("Checked that all nodes are now added back in in the correct order.\n");
    
    
    //
    // Swap nodes.
    //
    {
        //Swap all the nodes in the list so the list is in reverse order.
        le_dls_Link_t* linkPtr, *tmpLinkPtr;
        le_dls_Link_t* otherlinkPtr;    
        idRecord_t* nodePtr, *otherNodePtr;

        // For list 0.
        linkPtr = le_dls_Peek(&list0);
        otherlinkPtr = le_dls_PeekTail(&list0);    
        for (i = 0; i < (le_dls_NumLinks(&list0) / 2); i++)
        {
            nodePtr = CONTAINER_OF(linkPtr, idRecord_t, link);
            otherNodePtr = CONTAINER_OF(otherlinkPtr, idRecord_t, link);
            
            if (nodePtr->id < otherNodePtr->id) 
            {
                le_dls_Swap(&list0, linkPtr, otherlinkPtr);
            }
            else
            {
                break;
            }
            
            // switch the pointers back but not the links.
            tmpLinkPtr = linkPtr;
            linkPtr = otherlinkPtr;
            otherlinkPtr = tmpLinkPtr;
            
            linkPtr = le_dls_PeekNext(&list0, linkPtr);
            otherlinkPtr = le_dls_PeekPrev(&list0, otherlinkPtr);
        }


        // For list 1.
        linkPtr = le_dls_Peek(&list1);
        otherlinkPtr = le_dls_PeekTail(&list1);    
        for (i = 0; i < (le_dls_NumLinks(&list1) / 2); i++)
        {
            nodePtr = CONTAINER_OF(linkPtr, idRecord_t, link);
            otherNodePtr = CONTAINER_OF(otherlinkPtr, idRecord_t, link);
            
            if (nodePtr->id > otherNodePtr->id) 
            {
                le_dls_Swap(&list1, linkPtr, otherlinkPtr);
            }
            else
            {
                break;
            }
            
            // switch the pointers back but not the links.
            tmpLinkPtr = linkPtr;
            linkPtr = otherlinkPtr;
            otherlinkPtr = tmpLinkPtr;
            
            linkPtr = le_dls_PeekNext(&list1, linkPtr);
            otherlinkPtr = le_dls_PeekPrev(&list1, otherlinkPtr);
        }
    }
    
    printf("Reversed the order of both lists using swap.\n");
    
    //Check that the list is correct.
    {
        idRecord_t* nodePtr;
        le_dls_Link_t* link0Ptr = le_dls_PeekTail(&list0);
        le_dls_Link_t* link1Ptr = le_dls_Peek(&list1);
        
        if ( (link0Ptr == NULL) || (link1Ptr == NULL) )
        {
            printf("Link error: %d", __LINE__);
            return LE_FAULT;
        }
        
        i = 0;
        do
        {
            // Get the node from list 0
            nodePtr = CONTAINER_OF(link0Ptr, idRecord_t, link);

            // Check the node.
            if ( nodePtr->id != i)
            {
                printf("Link error: %d", __LINE__);
                return LE_FAULT;
            }
            
            // Get the node from list 1
            nodePtr = CONTAINER_OF(link1Ptr, idRecord_t, link);

            // Check the node.
            if ( nodePtr->id != i)
            {
                printf("Link error: %d", __LINE__);
                return LE_FAULT;
            }        

            // Move to the next node.
            link0Ptr = le_dls_PeekPrev(&list0, link0Ptr);
            link1Ptr = le_dls_PeekNext(&list1, link1Ptr);
            i++;
            
        } while (link0Ptr != NULL);
        
        // Make sure everything is correct.
        if ( (i != maxListSize) || (link1Ptr != NULL) )
        {
            printf("Link error: %d", __LINE__);
            return LE_FAULT;
        }
    }
    
    printf("Checked that all nodes are now correctly in the reverse order.\n");
    

    //
    // Pop nodes.
    //
    {
        //pop all of list0 except for one node.  Save the first node using swap before the pop.
        for (i = maxListSize; i > 1; i--)
        {
            // get the first two links.
            le_dls_Link_t* linkPtr = le_dls_Peek(&list0);
            le_dls_Link_t* otherlinkPtr = le_dls_PeekNext(&list0, linkPtr);

            // swap the first two links.
            le_dls_Swap(&list0, linkPtr, otherlinkPtr);

            // pop the first link.
            le_dls_Pop(&list0);
        }
        
        
        //pop half the list.
        for (i = 0; i < (maxListSize / 2); i++)
        {
            le_dls_PopTail(&list1);
        }
    }
    
    printf("Popped all the nodes except one from the head of list0.\n");
    printf("Popped half the nodes from the tail of list1.\n");
    
    // Check that the list is still in tact.
    {
        idRecord_t* nodePtr;
        
        // For list 0.
        le_dls_Link_t* linkPtr = le_dls_Peek(&list0); 
        nodePtr = CONTAINER_OF(linkPtr, idRecord_t, link);

        if (nodePtr->id != maxListSize-1)
        {
            printf("Link error: %d", __LINE__);
        }

        // Check that the number of links left is correct.
        if (le_dls_NumLinks(&list0) != 1)
        {
            printf("Wrong number of links: %d", __LINE__);
            return LE_FAULT;
        }
        
        // For list1.
        linkPtr = le_dls_Peek(&list1); 
        i = 0;
        do
        {
            nodePtr = CONTAINER_OF(linkPtr, idRecord_t, link);
            
            if (nodePtr->id != i++)
            {
                printf("Link error: %d", __LINE__);
                return LE_FAULT;
            }
            
            linkPtr = le_dls_PeekNext(&list1, linkPtr);
        } while(linkPtr != NULL);
        
        // Check that the number of links left is correct.
        if (i != maxListSize - (maxListSize / 2))
        {
            printf("Wrong number of links: %d", __LINE__);
            return LE_FAULT;
        }
    }
    
    printf("Checked that all nodes were properly popped from the lists.\n");


    //
    // Check for list corruption.
    //
    {
        le_dls_Link_t* linkPtr;
        
        if (le_dls_IsListCorrupted(&list1))
        {
            printf("List1 is corrupt but shouldn't be: %d", __LINE__);
            return LE_FAULT;
        }

        // Access one of the links directly.  This should corrupt the list.
        linkPtr = le_dls_PeekTail(&list1);
        linkPtr = le_dls_PeekPrev(&list1, linkPtr);
        linkPtr->prevPtr = linkPtr;

        if (!le_dls_IsListCorrupted(&list1))
        {
            printf("List1 is not corrupted but should be: %d", __LINE__);
            return LE_FAULT;
        }
    }

    printf("Checked lists for corruption.\n");

    
    printf("*** Unit Test for le_doublyLinkedList module passed. ***\n");
    printf("\n");
    return LE_OK;
}