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