void * fonction_thread () { cpt=100; while (cpt--) { le_sem_Wait(GSemPtr); fprintf(stdout, "\n%d : thread '%s' has %s %d\n", cpt,le_thread_GetMyName(),SEM_NAME_1,le_sem_GetValue(GSemPtr)); CU_PASS("thread GSemPtr get"); le_sem_Wait(GSem2Ptr); fprintf(stdout, "\n%d : thread '%s' has %s %d\n", cpt,le_thread_GetMyName(),SEM_NAME_2,le_sem_GetValue(GSem2Ptr)); CU_PASS("thread GSem2Ptr get"); usleep(10000); le_sem_Post(GSem2Ptr); fprintf(stdout, "\n%d : thread '%s' release %s %d\n", cpt,le_thread_GetMyName(),SEM_NAME_2,le_sem_GetValue(GSem2Ptr)); CU_PASS("thread GSemPtr2 UnLocked"); le_sem_Post(GSemPtr); fprintf(stdout, "\n%d : thread '%s' release %s %d\n", cpt,le_thread_GetMyName(),SEM_NAME_1,le_sem_GetValue(GSemPtr)); CU_PASS("thread GSemPtr UnLocked"); } return NULL; }
// A thread "main" function which creates a series of sems. static void* ThreadCreateSem ( void* context ) { char semNameBuffer[LIMIT_MAX_SEMAPHORE_NAME_BYTES] = {0}; LE_INFO("Thread [%s] has started. Waiting on a semaphore.", le_thread_GetMyName()); le_mutex_Lock(SemIndexMutexRef); snprintf(semNameBuffer, LIMIT_MAX_SEMAPHORE_NAME_BYTES, "[%s]Sem%ld", le_thread_GetMyName(), SemCreateIdx); le_sem_Ref_t sem = le_sem_Create(semNameBuffer, 0); SemRefArray[SemCreateIdx] = (SemRef_t){le_thread_GetCurrent(), sem}; SemCreateIdx++; le_mutex_Unlock(SemIndexMutexRef); LE_INFO("In thread [%s], about to wait sem", le_thread_GetMyName()); // notify the calling thread that this thread is about to wait on its sema. le_sem_Post(SemaRef); le_sem_Wait(sem); LE_INFO("In thread [%s], sema is posted", le_thread_GetMyName()); le_event_RunLoop(); return NULL; }
//-------------------------------------------------------------------------------------------------- le_result_t le_sem_TryWait ( le_sem_Ref_t semaphorePtr ///< [IN] Pointer to the semaphore ) { // TODO: Implement this. // if (semaphorePtr->isTraceable) // { // } // else { int result; result = sem_trywait(&semaphorePtr->semaphore); if (result != 0) { if ( errno == EAGAIN ) { return LE_WOULD_BLOCK; } else { LE_FATAL("Thread '%s' failed to trywait on semaphore '%s'. Error code %d (%m).", le_thread_GetMyName(), semaphorePtr->nameStr, result); } } } return LE_OK; }
//-------------------------------------------------------------------------------------------------- void le_sem_Wait ( le_sem_Ref_t semaphorePtr ///< [IN] Pointer to the semaphore ) { // TODO: Implement this: // if (semaphorePtr->isTraceable) // { // } // else { int result; sem_ThreadRec_t* perThreadRecPtr = thread_GetSemaphoreRecPtr(); ListOfSemaphoresChgCnt++; perThreadRecPtr->waitingOnSemaphore = semaphorePtr; AddToWaitingList(semaphorePtr, perThreadRecPtr); result = sem_wait(&semaphorePtr->semaphore); RemoveFromWaitingList(semaphorePtr, perThreadRecPtr); ListOfSemaphoresChgCnt++; perThreadRecPtr->waitingOnSemaphore = NULL; LE_FATAL_IF( (result!=0), "Thread '%s' failed to wait on semaphore '%s'. Error code %d (%m).", le_thread_GetMyName(), semaphorePtr->nameStr, result); } }
// Delete from 1 to n-1 for all threads static void DelMutex1toNMinus1PerThread ( void* param1, void* param2 ) { LE_INFO("DelMutex1toNMinus1PerThread in thread [%s]", le_thread_GetMyName()); DelMutexes(0, 1); }
// ------------------------------------------------------------------------------------------------- static void IncrementCounter(void) // ------------------------------------------------------------------------------------------------- { Lock(); Counter++; LE_INFO("Thread '%s' incremented counter to %zu.", le_thread_GetMyName(), Counter); Unlock(); }
// ------------------------------------------------------------------------------------------------- static void ThreadDestructor ( void* destructorContext ) // ------------------------------------------------------------------------------------------------- { Context_t* contextPtr = destructorContext; LE_TEST_INFO("Thread '%s' destructor running.", le_thread_GetMyName()); le_mem_Release(contextPtr); }
//-------------------------------------------------------------------------------------------------- le_result_t le_sem_WaitWithTimeOut ( le_sem_Ref_t semaphorePtr, ///< [IN] Pointer to the semaphore. le_clk_Time_t timeToWait ///< [IN] Time to wait ) { // TODO: Implement this. // if (semaphorePtr->isTraceable) // { // } // else { struct timespec timeOut; int result; // Prepare the timer le_clk_Time_t currentUtcTime = le_clk_GetAbsoluteTime(); le_clk_Time_t wakeUpTime = le_clk_Add(currentUtcTime,timeToWait); timeOut.tv_sec = wakeUpTime.sec; timeOut.tv_nsec = wakeUpTime.usec; // Retrieve reference thread sem_ThreadRec_t* perThreadRecPtr = thread_GetSemaphoreRecPtr(); // Save into waiting list ListOfSemaphoresChgCnt++; perThreadRecPtr->waitingOnSemaphore = semaphorePtr; AddToWaitingList(semaphorePtr, perThreadRecPtr); result = sem_timedwait(&semaphorePtr->semaphore,&timeOut); // Remove from waiting list RemoveFromWaitingList(semaphorePtr, perThreadRecPtr); ListOfSemaphoresChgCnt++; perThreadRecPtr->waitingOnSemaphore = NULL; if (result != 0) { if ( errno == ETIMEDOUT ) { return LE_TIMEOUT; } else { LE_FATAL("Thread '%s' failed to wait on semaphore '%s'. Error code %d (%m).", le_thread_GetMyName(), semaphorePtr->nameStr, result); } } } return LE_OK; }
// ------------------------------------------------------------------------------------------------- static void* ThreadMainFunction ( void* objPtr ) // ------------------------------------------------------------------------------------------------- { Context_t* contextPtr = objPtr; LE_INFO("Thread '%s' started.", le_thread_GetMyName()); IncrementCounter(); if (contextPtr->depth < DEPTH) { LE_INFO("Thread '%s' spawning children.", le_thread_GetMyName()); SpawnChildren(contextPtr->depth + 1, contextPtr->completionObjPtr); } LE_INFO("Thread '%s' terminating.", le_thread_GetMyName()); return contextPtr->completionObjPtr; }
// A thread "main" function which creates a series of mutexes. static void* ThreadCreateMutex ( void* context ) { long mutexCount = (long)context; char mutexNameBuffer[MAX_NAME_BYTES] = {0}; MutexRefArray_t mra; mra.size = mutexCount; mra.mutexRefArray = malloc(mutexCount * sizeof(le_mutex_Ref_t)); LE_INFO("Thread [%s] has started. Creating %ld mutexes.", le_thread_GetMyName(), mutexCount); le_mutex_Lock(MutexIndexMutexRef); long cnt = 0; while (cnt < mutexCount) { snprintf(mutexNameBuffer, MAX_NAME_BYTES, "[%s]Mutex%ld", le_thread_GetMyName(), MutexCreateIdx); mra.mutexRefArray[cnt] = le_mutex_CreateNonRecursive(mutexNameBuffer); le_mutex_Lock(mra.mutexRefArray[cnt]); MutexCreateIdx++; cnt++; } le_mutex_Unlock(MutexIndexMutexRef); // Save the list of mutex refs in the thread's local storage. (void) pthread_setspecific(TsdMutexRefKey, &mra); le_sem_Post(SemaRef); le_event_RunLoop(); return NULL; }
// Delete all mutexes for the first thread. static void DelAllMutexesFor1stThread ( void* param1, void* param2 ) { LE_INFO("DelAllMutexesFor1stThread in thread [%s]", le_thread_GetMyName()); // Determine if this is the "1st" thread on the thread list. If so, delete all mutexes. if (le_thread_GetCurrent() == ThreadRefArray[0]) { LE_INFO("This thread is the 1st thread in the thread list - deleting all mutexes."); DelMutexes(0, 0); } }
// ------------------------------------------------------------------------------------------------- static void IncrementCounter(void) // ------------------------------------------------------------------------------------------------- { Lock(); Counter++; LE_TEST_INFO("Thread '%s' incremented counter to %u.", le_thread_GetMyName(), Counter); if (Counter == ExpectedCounterValue) { le_sem_Post(CounterSemRef); } Unlock(); }
// Delete all mutexes for a thread in the middle. static void DelAllMutexesForMidThread ( void* param1, void* param2 ) { LE_INFO("DelAllMutexesForMidThread in thread [%s]", le_thread_GetMyName()); long midIdx = ThreadNum / 2; // Determine if this is the "mid" thread on the thread list. If so, delete all mutexes. if (le_thread_GetCurrent() == ThreadRefArray[midIdx]) { LE_INFO("This thread is the mid thread in the thread list - deleting all mutexes."); DelMutexes(0, 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); } }
// ------------------------------------------------------------------------------------------------- static void SpawnChildren ( size_t depth, // Indicates what nesting level the thread is at. // 1 = children of the process main thread. void* completionObjPtr // Ptr to the object whose ref count is used to terminate the test. ) // ------------------------------------------------------------------------------------------------- { int i; char childName[32]; le_thread_Ref_t children[FAN_OUT]; // Create and start all the children. for (i = 0; i < FAN_OUT; i++) { le_thread_Ref_t threadRef; Context_t* contextPtr = le_mem_ForceAlloc(ContextPoolRef); contextPtr->depth = depth; contextPtr->completionObjPtr = completionObjPtr; le_mem_AddRef(completionObjPtr); snprintf(childName, sizeof(childName), "%s-%d", le_thread_GetMyName(), i + 1); LE_INFO("Spawning thread '%s'.", childName); threadRef = le_thread_Create(childName, ThreadMainFunction, contextPtr); LE_INFO("Thread '%s' created.", childName); // Create a thread destructor that will release the Context object and the // Test Completion Object that we are going to pass to the child. le_thread_AddChildDestructor(threadRef, ThreadDestructor, contextPtr); LE_INFO("Thread '%s' destructor added.", childName); // Make every third child thread non-joinable and the rest joinable. if (((i + 1) % 3) != 0) { le_thread_SetJoinable(threadRef); } LE_INFO("Thread '%s' joinability set.", childName); // Start the child thread. le_thread_Start(threadRef); LE_INFO("Thread '%s' started.", childName); // Remember the child's thread reference for later join attempt. children[i] = threadRef; } // Join with all the children. for (i = 0; i < FAN_OUT; i++) { void* threadReturnValue; snprintf(childName, sizeof(childName), "%s-%d", le_thread_GetMyName(), i + 1); LE_INFO("Joining with thread '%s'.", childName); le_result_t result = le_thread_Join(children[i], &threadReturnValue); if (result != LE_OK) { LE_INFO("Failed to join with thread '%s'.", childName); LE_FATAL_IF(((i + 1) % 3) != 0, "Failed to join with joinable thread '%s'!", childName); } else { LE_INFO("Successfully joined with thread '%s', which returned %p.", childName, threadReturnValue); LE_FATAL_IF(((i + 1) % 3) == 0, "Joined with non-joinable thread '%s'!", childName); LE_FATAL_IF(threadReturnValue != completionObjPtr, "Thread returned strange value %p. Expected %p.", threadReturnValue, completionObjPtr); } } }
// ------------------------------------------------------------------------------------------------- static void SpawnChildren ( size_t depth // Indicates what nesting level the thread is at. // 1 = children of the process main thread. ) // ------------------------------------------------------------------------------------------------- { int i, j, k; char childName[32]; le_thread_Ref_t children[FAN_OUT]; const char* threadName = le_thread_GetMyName(); if (depth == 2) { LE_ASSERT(sscanf(threadName, "%*[^-]-%d", &j) == 1); // switch to zero-based j--; LE_TEST_INFO("depth 2: j=%d", j); } else if (depth == 3) { LE_ASSERT(sscanf(threadName, "%*[^-]-%d-%d", &k, &j) == 2); // switch to zero based k--; j--; LE_TEST_INFO("depth 3: j=%d,k=%d", j, k); } // Create and start all the children. for (i = 0; i < FAN_OUT; i++) { le_thread_Ref_t threadRef; Context_t* contextPtr = le_mem_ForceAlloc(ContextPoolRef); contextPtr->depth = depth; int item = 0; if (depth == 1) { item = i*(FAN_OUT+1)*(FAN_OUT+1); } if (depth == 2) { item = (j*(FAN_OUT+1)+(i+1))*(FAN_OUT+1); } else if (depth == 3) { item = (k*(FAN_OUT+1) + (j+1))*(FAN_OUT+1) + (i+1); } if (item >= FAN_OUT*(FAN_OUT+1)*(FAN_OUT+1)) { LE_TEST_FATAL("Result index %d outside test result array size %d!", item, FAN_OUT*(FAN_OUT+1)*(FAN_OUT+1)); } snprintf(childName, sizeof(childName), "%s-%d", threadName, i + 1); LE_TEST_INFO("Spawning thread '%s' (item %d).", childName, item); threadRef = le_thread_Create(childName, ThreadMainFunction, contextPtr); TestResults[item].createOk = !!threadRef; // Create a thread destructor that will release the Context object and the // Test Completion Object that we are going to pass to the child. le_thread_AddChildDestructor(threadRef, ThreadDestructor, contextPtr); LE_TEST_INFO("Thread '%s' destructor added.", childName); // Make every third leaf thread non-joinable and the rest joinable. // Non-leaves must be joinable to ensure join if (IsThreadJoinable(depth, i)) { le_thread_SetJoinable(threadRef); LE_TEST_INFO("Thread '%s' joinability set.", childName); } // Start the child thread. le_thread_Start(threadRef); LE_TEST_INFO("Thread '%s' started.", childName); // Remember the child's thread reference for later join attempt. children[i] = threadRef; } // Join with all the children. for (i = 0; i < FAN_OUT; i++) { void* threadReturnValue; int item = 0; if (depth == 1) { item = i*(FAN_OUT+1)*(FAN_OUT+1); } if (depth == 2) { item = (j*(FAN_OUT+1)+(i+1))*(FAN_OUT+1); } else if (depth == 3) { item = (k*(FAN_OUT+1)+(j+1))*(FAN_OUT+1) + (i+1); } if (item >= FAN_OUT*(FAN_OUT+1)*(FAN_OUT+1)) { LE_TEST_FATAL("Result index %d outside test result array size %d!", item, FAN_OUT*(FAN_OUT+1)*(FAN_OUT+1)); } snprintf(childName, sizeof(childName), "%s-%d", le_thread_GetMyName(), i + 1); if (IsThreadJoinable(depth, i)) { le_result_t result = le_thread_Join(children[i], &threadReturnValue); TestResults[item].joinOk = (result == LE_OK); if (result != LE_OK) { LE_TEST_INFO("Failed to join with thread '%s'.", childName); } else { LE_TEST_INFO("Successfully joined with thread '%s', which returned %p.", childName, threadReturnValue); TestResults[item].expectedJoin = (void*)depth; TestResults[item].actualJoin = threadReturnValue; } } else { // Do not try to join non-joinable threads. Result is undefined as thread // could have exited in the meantime and been recycled. TestResults[item].joinOk = false; } } }