//-------------------------------------------------------------------------------------------------- void le_mem_DeleteSubPool ( le_mem_PoolRef_t subPool ///< [IN] The sub-pool to be deleted. ) { LE_ASSERT(subPool != NULL); Lock(); // Make sure all sub-pool objects are free. le_mem_PoolRef_t superPool = subPool->superPoolPtr; LE_FATAL_IF(subPool->numBlocksInUse != 0, "Subpool '%s' deleted while %zu blocks remain allocated.", subPool->name, subPool->numBlocksInUse); size_t numBlocks = subPool->totalBlocks; // Move the blocks from the subPool back to the superpool. MoveBlocks(superPool, subPool, numBlocks); // Update the superPool's block use count. superPool->numBlocksInUse -= numBlocks; // Remove the sub-pool from the list of sub-pools. ListOfPoolsChgCnt++; le_dls_Remove(&ListOfPools, &(subPool->poolLink)); Unlock(); // Release the sub-pool. le_mem_Release(subPool); }
//-------------------------------------------------------------------------------------------------- static void DeleteFdMonitor ( FdMonitor_t* fdMonitorPtr ///< [in] Pointer to the FD Monitor to be deleted. ) //-------------------------------------------------------------------------------------------------- { event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr(); LE_ASSERT(perThreadRecPtr == fdMonitorPtr->threadRecPtr); // Remove the FD Monitor from the thread's FD Monitor List. le_dls_Remove(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link); LOCK // Delete the Safe References used for the FD Monitor and any of its Handler objects. le_ref_DeleteRef(FdMonitorRefMap, fdMonitorPtr->safeRef); UNLOCK // Tell epoll(7) to stop monitoring this fd. StopMonitoringFd(fdMonitorPtr); // Release the object back to it's pool. le_mem_Release(fdMonitorPtr); }
//-------------------------------------------------------------------------------------------------- void le_msg_RemoveServiceHandler ( le_msg_SessionEventHandlerRef_t handlerRef ///< [in] Reference to a previously call of /// le_msg_AddServiceCloseHandler() ) //-------------------------------------------------------------------------------------------------- { le_dls_Link_t* linkPtr = le_ref_Lookup(HandlersRefMap, handlerRef); if ( linkPtr == NULL ) { LE_ERROR("Invalid data request reference"); } else { SessionEventHandler_t* eventPtr = CONTAINER_OF(linkPtr, SessionEventHandler_t, link); /* Remove the link from the close handlers dls */ le_dls_Remove(eventPtr->listPtr, linkPtr); /* Release memory */ le_mem_Release(eventPtr); /* Delete the reference */ le_ref_DeleteRef(HandlersRefMap, handlerRef); } }
//-------------------------------------------------------------------------------------------------- static void DeleteFdMonitor ( FdMonitor_t* fdMonitorPtr ///< [in] Pointer to the FD Monitor to be deleted. ) //-------------------------------------------------------------------------------------------------- { int i; event_PerThreadRec_t* perThreadRecPtr = thread_GetEventRecPtr(); LE_ASSERT(perThreadRecPtr == fdMonitorPtr->threadRecPtr); // Remove the FD Monitor from the thread's FD Monitor List. le_dls_Remove(&perThreadRecPtr->fdMonitorList, &fdMonitorPtr->link); LOCK // Delete the Safe References used for the FD Monitor and any of its Handler objects. le_ref_DeleteRef(FdMonitorRefMap, fdMonitorPtr->safeRef); for (i = 0; i < LE_EVENT_NUM_FD_EVENT_TYPES; i++) { void* safeRef = fdMonitorPtr->handlerArray[i].safeRef; if (safeRef != NULL) { le_ref_DeleteRef(HandlerRefMap, safeRef); } } UNLOCK // Tell epoll(7) to stop monitoring this fd. StopMonitoringFd(fdMonitorPtr); // Release the object back to it's pool. le_mem_Release(fdMonitorPtr); }
//-------------------------------------------------------------------------------------------------- void msgService_RemoveSession ( le_msg_ServiceRef_t serviceRef, le_msg_SessionRef_t sessionRef ) //-------------------------------------------------------------------------------------------------- { le_dls_Remove(&serviceRef->sessionList, msgSession_GetListLink(sessionRef)); // The Session object no longer holds a reference to the Service object. msgService_Release(serviceRef); }
//-------------------------------------------------------------------------------------------------- static void RemoveFromWaitingList ( Semaphore_t* semaphorePtr, sem_ThreadRec_t* perThreadRecPtr ) //-------------------------------------------------------------------------------------------------- { LOCK_WAITING_LIST(semaphorePtr); le_dls_Remove(&semaphorePtr->waitingList, &perThreadRecPtr->waitingListLink); UNLOCK_WAITING_LIST(semaphorePtr); }
//------------------------------------------------------------------------------------------------------------ le_dls_Link_t* le_dls_PopTail ( le_dls_List_t* listPtr ///< [IN] The list to remove from. ) { if (listPtr->headLinkPtr == NULL) { // List is empty. return NULL; } le_dls_Link_t* linkToPopPtr = listPtr->headLinkPtr->prevPtr; le_dls_Remove(listPtr, linkToPopPtr); return linkToPopPtr; }
//-------------------------------------------------------------------------------------------------- le_result_t le_mcc_Delete ( le_mcc_CallRef_t callRef ///< [IN] The call object to free. ) { le_mcc_Call_t* callPtr = le_ref_Lookup(MccCallRefMap, callRef); if (callPtr == NULL) { LE_ERROR("Invalid reference (%p) provided!", callRef); return LE_NOT_FOUND; } if (callPtr->inProgress) { return LE_FAULT; } else { SessionRefNode_t* sessionRefNodePtr; le_dls_Link_t* linkPtr; callPtr->refCount--; LE_DEBUG("refcount %d", callPtr->refCount); // Remove corresponding node from the sessionRefList linkPtr = le_dls_Peek(&(callPtr->sessionRefList)); while (linkPtr != NULL) { sessionRefNodePtr = CONTAINER_OF(linkPtr, SessionRefNode_t, link); linkPtr = le_dls_PeekNext(&(callPtr->sessionRefList), linkPtr); if ( sessionRefNodePtr->sessionRef == le_mcc_GetClientSessionRef() ) { le_dls_Remove( &(callPtr->sessionRefList), &(sessionRefNodePtr->link)); le_mem_Release(sessionRefNodePtr); } } le_mem_Release(callPtr); return LE_OK; } }
//------------------------------------------------------------------------------------------------------------ le_dls_Link_t* le_dls_Pop ( le_dls_List_t* listPtr ///< [IN] The list to remove from. ) { // Check parameters. if (listPtr->headLinkPtr == NULL) { // List is empty. return NULL; } le_dls_Link_t* linkToPopPtr = listPtr->headLinkPtr; le_dls_Remove(listPtr, linkToPopPtr); return linkToPopPtr; }
//-------------------------------------------------------------------------------------------------- static void CloseSessionEventHandler ( le_msg_SessionRef_t sessionRef, void* contextPtr ) { le_mcc_Call_t* callPtr = NULL; SessionRefNode_t* sessionRefNodePtr; le_dls_Link_t* linkPtr; le_ref_IterRef_t iterRef = le_ref_GetIterator(MccCallRefMap); while (le_ref_NextNode(iterRef) == LE_OK) { callPtr = (le_mcc_Call_t*) le_ref_GetValue(iterRef); // Remove corresponding node from the sessionRefList linkPtr = le_dls_Peek(&(callPtr->sessionRefList)); while (linkPtr != NULL) { sessionRefNodePtr = CONTAINER_OF(linkPtr, SessionRefNode_t, link); linkPtr = le_dls_PeekNext(&(callPtr->sessionRefList), linkPtr); // Remove corresponding node from the sessionRefList if ( sessionRefNodePtr->sessionRef == sessionRef ) { le_dls_Remove(&(callPtr->sessionRefList), &(sessionRefNodePtr->link)); le_mem_Release(sessionRefNodePtr); callPtr->refCount--; le_mem_Release(callPtr); } } } }
//-------------------------------------------------------------------------------------------------- void le_sem_Delete ( le_sem_Ref_t semaphorePtr ///< [IN] Pointer to the semaphore ) { // TODO: Implement traceable semaphore deletion. // Remove the Semaphore object from the Semaphore List. LOCK_SEMAPHORE_LIST(); le_dls_Remove(&SemaphoreList, &semaphorePtr->semaphoreListLink); UNLOCK_SEMAPHORE_LIST(); LOCK_WAITING_LIST(semaphorePtr); if ( le_dls_Peek(&semaphorePtr->waitingList)==NULL ) { UNLOCK_WAITING_LIST(semaphorePtr); if (pthread_mutex_destroy(&semaphorePtr->waitingListMutex) != 0) { LE_FATAL( "Semaphore '%s' could not destroy internal mutex!", semaphorePtr->nameStr); } // Destroy the semaphore. if (sem_destroy(&semaphorePtr->semaphore) != 0) { LE_FATAL( "Semaphore '%s' is not a valid semaphore!", semaphorePtr->nameStr); } } else { UNLOCK_WAITING_LIST(semaphorePtr); // TODO print more information LE_FATAL("Semaphore '%s' deleted while threads are still waiting for it!", semaphorePtr->nameStr); } // Release the semaphore object back to the Semaphore Pool. le_mem_Release(semaphorePtr); }
//-------------------------------------------------------------------------------------------------- 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); } }
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; }