示例#1
0
//--------------------------------------------------------------------------------------------------
static void Testle_temp_ThresholdEvent
(
)
{
    //  le_temp_ThresholdEventHandlerRef_t ref;
    struct timespec ts;
    le_temp_ThresholdEventHandlerRef_t ref;

    TimeCounter = 0;
    PoolTemp = 1;
    LE_INFO("Set PoolTemp %d", PoolTemp);

    ref = le_temp_AddThresholdEventHandler(ThresholdEventHandlerFunc, NULL);
    LE_ASSERT(ref != NULL);
    LE_INFO("ref  0x%p", ref);
    le_temp_RemoveThresholdEventHandler(ref);

    le_thread_Ref_t thread = le_thread_Create("tempTest",DisplayTempThread,NULL);
    le_thread_Start(thread);

    le_thread_Ref_t thread2 = le_thread_Create("EventThread",EventThread,NULL);
    le_thread_Start(thread2);

    sem_init(&SemaphoreCriticalEvent,0,0);

    PoolTemp = 2;
    LE_INFO("Set PoolTemp %d", PoolTemp);

    if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
    {
        LE_ERROR("Cannot get current time");
        return;
    }

    LE_INFO("!!!!!!! YOU MUST WARM UP OR COLD DOWN THE"
        " MODULE in %d second !!!!!!!", WAIT_TIME_EVENT);

    ts.tv_sec += WAIT_TIME_EVENT; // Wait for 480 seconds.
    ts.tv_nsec += 0;

    if ( sem_timedwait(&SemaphoreCriticalEvent,&ts) == -1 )
    {
        LE_WARN("errno %d", errno);
        if ( errno == ETIMEDOUT)
        {
            LE_WARN("Timeout for Warnig Event");
            return;
        }
    }

    PoolTemp = 0;
    LE_INFO("Set PoolTemp %d", PoolTemp);
    sleep(2);
}
示例#2
0
//--------------------------------------------------------------------------------------------------
static void TestLeGnssPositionHandler
(
    void
)
{
    le_thread_Ref_t positionThreadRef;

    LE_INFO("Start Test Testle_gnss_PositionHandlerTest");

    LE_INFO("Start GNSS");
    LE_ASSERT((le_gnss_Start()) == LE_OK);
    LE_INFO("Wait 5 seconds");
    sleep(5);

    // Add Position Handler Test
    positionThreadRef = le_thread_Create("PositionThread",PositionThread,NULL);
    le_thread_Start(positionThreadRef);

    LE_INFO("Wait for a 3D fix");
    sleep(60);

    le_gnss_RemovePositionHandler(PositionHandlerRef);

    LE_INFO("Wait 5 seconds");
    sleep(5);

    // stop thread
    le_thread_Cancel(positionThreadRef);

    LE_INFO("Stop GNSS");
    LE_ASSERT((le_gnss_Stop()) == LE_OK);
}
示例#3
0
//--------------------------------------------------------------------------------------------------
static void StartStressECall
(
    void
)
{
    LE_INFO("Start StartStressECall");

    LastECallState = LE_ECALL_STATE_DISCONNECTED;
    TestCount = 0;

    ThreadSemaphore = le_sem_Create("ThreadSem",0);

    LE_ASSERT(le_ecall_AddStateChangeHandler(MyECallEventHandler, NULL) != NULL);

    LE_ASSERT(le_ecall_SetPsapNumber(PsapNumber) == LE_OK);

    LE_ASSERT(le_ecall_SetMsdTxMode(LE_ECALL_TX_MODE_PUSH) == LE_OK);

    LE_ASSERT((MytECallRef=le_ecall_Create()) != NULL);

    LE_ASSERT(le_ecall_SetMsdPosition(MytECallRef, true, +48898064, +2218092, 0) == LE_OK);

    LE_ASSERT(le_ecall_SetMsdPassengersCount(MytECallRef, 3) == LE_OK);

    le_thread_Start(le_thread_Create("ECallLoopThread", ECallLoopThread, NULL));
    // Start Test
    le_sem_Post(ThreadSemaphore);
}
示例#4
0
//--------------------------------------------------------------------------------------------------
static void TestMdc_StartStopAsync
(
    void
)
{
    le_clk_Time_t   timeToWait;
    timeToWait.sec = 0;
    timeToWait.usec = 1000000;

    const StartStopAsyncFunc_t testFunc[] = { le_mdc_StartSessionAsync,
                                              le_mdc_StopSessionAsync,
                                              NULL
                                            };
    int i=0;

    while (testFunc[i])
    {
        le_thread_Ref_t testThread = le_thread_Create("AsyncStartStopSessionThread",
                                                      AsyncStartStopSessionThread,
                                                      testFunc[i]);

        // Start the thread
        le_thread_Start(testThread);

        LE_ASSERT(le_sem_WaitWithTimeOut(ThreadSemaphore, timeToWait) != LE_TIMEOUT);

        le_thread_Cancel(testThread);

        i++;
    }
}
示例#5
0
// Create all semaphores for the specified number of threads. Since there's no semaphore list,
// one semaphore is created per thread.
void createAllSemaphores
(
    void
)
{
    char threadNameBuffer[MAX_THREAD_NAME_SIZE] = {0};

    long threadCnt = 0;
    while (threadCnt < ThreadNum)
    {
        snprintf(threadNameBuffer, MAX_THREAD_NAME_SIZE, "Thread%ld", threadCnt);

        // Store the thread references in an array
        ThreadRefArray[threadCnt] = le_thread_Create(threadNameBuffer, ThreadCreateSem, NULL);

        le_thread_Start(ThreadRefArray[threadCnt]);

        threadCnt++;
    }

    LE_INFO("========== Created all threads ===========");

    // waiting for all threads to start waiting on their sema.
    long cnt = 0;
    while (cnt < ThreadNum)
    {
        le_sem_Wait(SemaRef);
        cnt++;
    }

    LE_INFO("========== All threads have started waiting on their semaphores ===========");
}
示例#6
0
//--------------------------------------------------------------------------------------------------
static void TestMdc_Handler ( void )
{
    le_result_t res;

    /* Create the thread to subcribe and call the handlers */
    ThreadSemaphore = le_sem_Create("HandlerSem",0);
    le_thread_Ref_t thread = le_thread_Create("Threadhandler", ThreadTestHandler, NULL);
    le_thread_Start(thread);
    int i;
    le_clk_Time_t   timeToWait;
    timeToWait.sec = 0;
    timeToWait.usec = 1000000;

    /* Wait the thread to be ready */
    le_sem_Wait(ThreadSemaphore);

    for (i = 0; i < NB_PROFILE; i++)
    {
        /* Start a session for the current profile: the handler should be called */
        res = le_mdc_StartSession(ProfileRef[i]);
        LE_ASSERT(res == LE_OK);
        /* Wait for the call of the handler (error if timeout) */
        LE_ASSERT(le_sem_WaitWithTimeOut(ThreadSemaphore, timeToWait) == LE_OK);
        /* Check the the handler parameters */
        LE_ASSERT(ProfileRefReceivedByHandler == ProfileRef[i]);
        LE_ASSERT(ConnectionStateReceivedByHandler == true);
        ConnectionStateReceivedByHandler = false;
    }

    for (i = 0; i < NB_PROFILE; i++)
    {
        /* Stop a session for the current profile: the handler should be called */
        res = le_mdc_StopSession(ProfileRef[i]);
        LE_ASSERT(res == LE_OK);
        /* Wait for the call of the handler (error if timeout) */
        LE_ASSERT(le_sem_WaitWithTimeOut(ThreadSemaphore, timeToWait) == LE_OK);
        /* Check the the handler parameters */
        LE_ASSERT(ProfileRefReceivedByHandler == ProfileRef[i]);
        LE_ASSERT(ConnectionStateReceivedByHandler == false);
        ConnectionStateReceivedByHandler = true;
    }

    /* Remove the handler of the profile 1: ther handler can be removed only by the thread which
     * subscribed to the handler, so put the RemoveHandler() function in queue of this thread */
    le_event_QueueFunctionToThread(         thread,
                                            RemoveHandler,
                                            SessionStateHandler[1],
                                            NULL);
    le_sem_Wait(ThreadSemaphore);
    /* Start a session for the current profile: no handler should be called */
    res = le_mdc_StartSession(ProfileRef[1]);
    /* No semaphore post is waiting, we are expecting a timeout */
    LE_ASSERT(le_sem_WaitWithTimeOut(ThreadSemaphore, timeToWait) == LE_TIMEOUT);
    res = le_mdc_StopSession(ProfileRef[1]);
    /* No semaphore post is waiting, we are expecting a timeout */
    LE_ASSERT(le_sem_WaitWithTimeOut(ThreadSemaphore, timeToWait) == LE_TIMEOUT);

}
示例#7
0
void testTraceable
(
    void
)
{
    le_sem_Ref_t sema1Ref = le_sem_CreateTraceable("TracSema1", 0);
    le_thread_Ref_t thread1Ref = le_thread_Create("Thread1", WaitOnSem, (void*)sema1Ref);
    le_thread_Start(thread1Ref);
}
示例#8
0
//--------------------------------------------------------------------------------------------------
le_result_t le_media_PlayDtmf
(
    le_audio_Stream_t*   streamPtr, ///< [IN] Stream object
    const char*          dtmfPtr,   ///< [IN] The DTMFs to play.
    uint32_t             duration,  ///< [IN] The DTMF duration in milliseconds.
    uint32_t             pause      ///< [IN] The pause duration between tones in milliseconds.
)
{
    le_result_t       res;
    DtmfThreadCtx_t*  threadCtxPtr = le_mem_ForceAlloc(DtmfThreadContextPool);

    memset(threadCtxPtr, 0, sizeof(DtmfThreadCtx_t));

    streamPtr->samplePcmConfig.sampleRate = 16000;
    streamPtr->samplePcmConfig.bitsPerSample = 16;
    streamPtr->samplePcmConfig.channelsCount = 1;
    streamPtr->samplePcmConfig.fileSize = -1;
    streamPtr->samplePcmConfig.pcmFormat = PCM_RAW;

    threadCtxPtr->duration = duration;
    threadCtxPtr->pause = pause;
    threadCtxPtr->sampleRate = 16000;
    threadCtxPtr->dtmfPtr = dtmfPtr;
    if (pipe(threadCtxPtr->pipefd) == -1)
    {
        LE_ERROR("Failed to create the pipe");
        le_mem_Release(threadCtxPtr);
        return LE_FAULT;
    }

    streamPtr->fd = threadCtxPtr->pipefd[0];

    if ((res=pa_audio_PlaySamples(streamPtr->audioInterface,
                                  streamPtr->fd,
                                  &streamPtr->samplePcmConfig)) == LE_OK)
    {
        LE_INFO("Spawn DTMF thread");
        if (DtmfTreadRef == NULL)
        {
            DtmfTreadRef = le_thread_Create("PlayDtmfs", PlayDtmfThread, threadCtxPtr);

            le_thread_AddChildDestructor(DtmfTreadRef,
                                        DestroyPlayDtmfThread,
                                        threadCtxPtr);

            le_thread_Start(DtmfTreadRef);
        }
    }
    else
    {
        le_mem_Release(threadCtxPtr);
        LE_ERROR("Cannot spawn DTMF thread!");
    }

    return res;
}
示例#9
0
文件: main.c 项目: H-H-bin/legato-af
//--------------------------------------------------------------------------------------------------
void Testle_ecall_AddHandlers
(
    void
)
{
    int i;

    // Create a semaphore to coordinate the test
    ThreadSemaphore = le_sem_Create("HandlerSem",0);

    // int app context
    memset(AppCtx, 0, NB_CLIENT*sizeof(AppContext_t));

    // Start tasks: simulate multi-user of le_ecall
    // each thread subcribes to state handler using le_ecall_AddStateChangeHandler
    for (i=0; i < NB_CLIENT; i++)
    {
        char string[20]={0};
        snprintf(string,20,"app%dhandler", i);
        AppCtx[i].appId = i;
        AppCtx[i].appThreadRef = le_thread_Create(string, AppHandler, &AppCtx[i]);
        le_thread_Start(AppCtx[i].appThreadRef);
    }

    // Wait that the tasks have started before continuing the test
    SynchTest();

    LE_ASSERT((CurrentEcallRef=le_ecall_Create()) != NULL);

    SimulateAndCheckState(LE_ECALL_STATE_STARTED);
    SimulateAndCheckState(LE_ECALL_STATE_CONNECTED);
    SimulateAndCheckState(LE_ECALL_STATE_WAITING_PSAP_START_IND);
    SimulateAndCheckState(LE_ECALL_STATE_PSAP_START_IND_RECEIVED);
    SimulateAndCheckState(LE_ECALL_STATE_MSD_TX_STARTED);
    SimulateAndCheckState(LE_ECALL_STATE_LLNACK_RECEIVED);
    SimulateAndCheckState(LE_ECALL_STATE_LLACK_RECEIVED);
    SimulateAndCheckState(LE_ECALL_STATE_MSD_TX_COMPLETED);
    SimulateAndCheckState(LE_ECALL_STATE_ALACK_RECEIVED_POSITIVE);
    SimulateAndCheckState(LE_ECALL_STATE_COMPLETED);
    SimulateAndCheckState(LE_ECALL_STATE_RESET);
    SimulateAndCheckState(LE_ECALL_STATE_TIMEOUT_T2);
    SimulateAndCheckState(LE_ECALL_STATE_TIMEOUT_T3);
    SimulateAndCheckState(LE_ECALL_STATE_TIMEOUT_T5);
    SimulateAndCheckState(LE_ECALL_STATE_TIMEOUT_T6);
    SimulateAndCheckState(LE_ECALL_STATE_TIMEOUT_T7);
    SimulateAndCheckState(LE_ECALL_STATE_TIMEOUT_T9);
    SimulateAndCheckState(LE_ECALL_STATE_TIMEOUT_T10);
// TODO: will be completed once pa_mcc_simu will be ready
// SimulateAndCheckState(LE_ECALL_STATE_DISCONNECTED);

    // Check that no more call of the semaphore
    LE_ASSERT(le_sem_GetValue(ThreadSemaphore) == 0);
    le_ecall_Delete(CurrentEcallRef);
}
示例#10
0
// This is testing if Mutex_t.waitingList is displayed correctly.
// Thread1 successfully locks mutexes 1, 2, and 3, and then Thread 2 and 3 tries to lock mutex 1, and 
// Thread 4 and 5 tries to lock mutex 3.
// Therefore the expected result is that Mutex1's waiting list has Thread2 and 3, Mutex2's waiting 
// list is empty, and Mutex3's waiting list has Thread4 and 5.
void testWaitingList
(
    void
)
{
    le_mutex_Ref_t mutex1Ref = le_mutex_CreateNonRecursive("Mutex1");
    le_mutex_Ref_t mutex2Ref = le_mutex_CreateNonRecursive("Mutex2");
    le_mutex_Ref_t mutex3Ref = le_mutex_CreateNonRecursive("Mutex3");

    // create mutex arrays to be passed to each thread.
    le_mutex_Ref_t mutexRefArray1[3] = {mutex1Ref, mutex2Ref, mutex3Ref};
    le_mutex_Ref_t mutexRefArray2[1] = {mutex1Ref};
    le_mutex_Ref_t mutexRefArray3[1] = {mutex3Ref};

    // put the arrays in a data struct containing size
    MutexRefArray_t mra1 = {NUM_ARRAY_MEMBERS(mutexRefArray1), mutexRefArray1};
    MutexRefArray_t mra2 = {NUM_ARRAY_MEMBERS(mutexRefArray2), mutexRefArray2};
    MutexRefArray_t mra3 = {NUM_ARRAY_MEMBERS(mutexRefArray3), mutexRefArray3};

    // create thread refs
    le_thread_Ref_t thread1Ref = le_thread_Create("Thread1", LockMutex, (void*)&mra1);
    le_thread_Ref_t thread2Ref = le_thread_Create("Thread2", LockMutex, (void*)&mra2);
    le_thread_Ref_t thread3Ref = le_thread_Create("Thread3", LockMutex, (void*)&mra2);
    le_thread_Ref_t thread4Ref = le_thread_Create("Thread4", LockMutex, (void*)&mra3);
    le_thread_Ref_t thread5Ref = le_thread_Create("Thread5", LockMutex, (void*)&mra3);

    // start the threads
    le_thread_Start(thread1Ref);
    // Do not proceed untiil Thread1 has gotten all the mutex locks
    le_sem_Wait(SemaRef);
    le_thread_Start(thread2Ref);
    le_thread_Start(thread3Ref);
    le_thread_Start(thread4Ref);
    le_thread_Start(thread5Ref);

    // Threads 2, 3, 4, and 5 are mutex-locked and therefore can't get to Post. The function needs 
    // to hang around for a bit for the mutex refs to be available for the threads.
    le_sem_Wait(SemaRef);

    LE_INFO("++++++++++++++++++  END OF testWaitingList (shouldn't get here) +++++++++++++++++++++");
}
示例#11
0
//--------------------------------------------------------------------------------------------------
static void Testle_temp_PlatformThresholdEventSetting
(
)
{
    int32_t warningTemperature = 0;
    int32_t criticalTemperature = 0;
    int32_t lowarningTemperature = 0;
    int32_t locriticalTemperature = 0;

    int32_t temperature = 0;
    le_result_t res = LE_FAULT;

    TimeCounter = 0;
    PoolTemp = 1;
    LE_INFO("Set PoolTemp %d", PoolTemp);

    le_thread_Ref_t thread = le_thread_Create("tempTest",DisplayTempThread,NULL);
    le_thread_Start(thread);

    LE_INFO("!!!!!!! YOU HAVE %d SECOND TO SET THE MODULE AT"
        " THE TEMP REFERENCE !!!!!!!", WAIT_TIME);
    TimeCounter = 0;

    PoolTemp = 2;
    LE_INFO("Set PoolTemp %d", PoolTemp);

    sleep(WAIT_TIME);

    // Get current Platform Tempeartaure
    res = le_temp_GetPlatformTemperature(&temperature);
    LE_ASSERT(res == LE_OK);
    LE_INFO("le_temp_GetPlatformTemperature return %d degree Celcus", temperature);

    res = le_temp_GetPlatformThresholds(&locriticalTemperature, &lowarningTemperature,
                    &warningTemperature, &criticalTemperature);
    LE_ASSERT(res == LE_OK);

    // Set Warning Platform threshold Tempeartaure
    criticalTemperature = temperature + 20;
    warningTemperature = temperature + 10;
    lowarningTemperature = temperature - 10;
    locriticalTemperature = temperature - 20;

    //criticalTemperature = DEFAULT_PLATFORM_HICRITICAL_THRESHOLD; //temperature + 20;
    res = le_temp_SetPlatformThresholds(locriticalTemperature, lowarningTemperature,
                    warningTemperature, criticalTemperature);
    LE_ASSERT(res == LE_OK);

    PoolTemp = 0;
    LE_INFO("Set PoolTemp %d", PoolTemp);
    LE_INFO("!!!!!!! YOU MUST REBOOT THE MODULE !!!!!!!");
    sleep(2);
}
示例#12
0
文件: main.c 项目: H-H-bin/legato-af
//--------------------------------------------------------------------------------------------------
void Testle_Temp_Init
(
    void
)
{
    // Create a semaphore to coordinate the test
    ThreadSemaphore = le_sem_Create("HandlerSem",0);

    le_thread_Start(le_thread_Create("PaTempThread", TempThread, NULL));

    le_sem_Wait(ThreadSemaphore);
}
示例#13
0
// -------------------------------------------------------------------------------------------------
void prio_Start
(
    void
)
// -------------------------------------------------------------------------------------------------
{
    // Note, we actually don't need to increment and decrement the memory block reference count
    // because we don't return until the test is complete.

#if LE_CONFIG_LINUX
    le_thread_Ref_t idleThread = le_thread_Create("idle", ThreadMainFunction, (void*)SCHED_IDLE);
#endif
#if LE_CONFIG_THREAD_REALTIME_ONLY
    const ssize_t expectedSched = SCHED_RR;
#else
    const ssize_t expectedSched = SCHED_OTHER;
#endif
    le_thread_Ref_t normalThread = le_thread_Create("norm", ThreadMainFunction, (void*)expectedSched);

#if LE_CONFIG_LINUX
    le_thread_SetJoinable(idleThread);
#endif
    le_thread_SetJoinable(normalThread);

#if LE_CONFIG_LINUX
    LE_ASSERT(LE_OK == le_thread_SetPriority(idleThread, LE_THREAD_PRIORITY_IDLE));
#endif
    LE_ASSERT(LE_OK == le_thread_SetPriority(normalThread, LE_THREAD_PRIORITY_NORMAL));

#if LE_CONFIG_LINUX
    le_thread_Start(idleThread);
#endif
    le_thread_Start(normalThread);

    void* unused;
    LE_ASSERT(LE_OK == le_thread_Join(normalThread, &unused));
#if LE_CONFIG_LINUX
    LE_ASSERT(LE_OK == le_thread_Join(idleThread, &unused));
#endif
}
示例#14
0
// This is testing if Semaphore_t.waitingList is displayed correctly.
// Thread 1, 2, and 3 are all waiting on Sem1. Thread4 is waiting on Sem2. Thread5 is waiting on Sem3.
// Therefore the expected result is that Sem1's waiting list has Thread 1, 2, and 3.
// Sem2's waiting list has Thread4.  Sem3's waiting list has Thread5.
void testWaitingList
(
    void
)
{
    le_sem_Ref_t sema1Ref = le_sem_Create("Semaphore1", 0);
    le_sem_Ref_t sema2Ref = le_sem_Create("Semaphore2", 0);
    le_sem_Ref_t sema3Ref = le_sem_Create("Semaphore3", 0);

    // create thread refs
    le_thread_Ref_t thread1Ref = le_thread_Create("Thread1", WaitOnSem, (void*)sema1Ref);
    le_thread_Ref_t thread2Ref = le_thread_Create("Thread2", WaitOnSem, (void*)sema1Ref);
    le_thread_Ref_t thread3Ref = le_thread_Create("Thread3", WaitOnSem, (void*)sema1Ref);
    le_thread_Ref_t thread4Ref = le_thread_Create("Thread4", WaitOnSem, (void*)sema2Ref);
    le_thread_Ref_t thread5Ref = le_thread_Create("Thread5", WaitOnSem, (void*)sema3Ref);

    // start the threads
    le_thread_Start(thread1Ref);
    le_thread_Start(thread2Ref);
    le_thread_Start(thread3Ref);
    le_thread_Start(thread4Ref);
    le_thread_Start(thread5Ref);
}
示例#15
0
//--------------------------------------------------------------------------------------------------
void simTest_SimPowerUpDown
(
    void
)
{
    le_sim_States_t  state;
    le_sim_Id_t simId;
    le_result_t res;
    le_clk_Time_t timeOut;

    //set timeout seconds for waiting for asynchronous power down event.
    timeOut.sec = 5;
    timeOut.usec = 0;

    SimPowerCycleSemaphore = le_sem_Create("HandlerSimPowerCycle", 0);

    SimPowerCycleThreadRef= le_thread_Create("ThreadSimPowerCycle", SimPowerCycleIndThread, NULL);

    le_thread_Start(SimPowerCycleThreadRef);

    // get blocked here until our event handler is registered and powerCycle thread is running
    res = le_sem_WaitWithTimeOut(SimPowerCycleSemaphore, timeOut);
    LE_ASSERT_OK(res);

    // Power down cases
    simId = le_sim_GetSelectedCard();
    state = le_sim_GetState(simId);
    LE_INFO("test: SIM state %d", state);
    LE_ASSERT(LE_SIM_READY == state);
    LE_ASSERT_OK(le_sim_SetPower(simId, LE_OFF));

    // Wait for complete asynchronous event of powered down (LE_SIM_POWER_DOWN)
    res = le_sem_WaitWithTimeOut(SimPowerCycleSemaphore, timeOut);
    LE_ASSERT_OK(res);
    LE_INFO("Powers Down current SIM: success");

    // Power up cases
    LE_ASSERT_OK(le_sim_SetPower(simId, LE_ON));
    // Wait for complete asynchronous event of powered up  (LE_SIM_READY)
    res = le_sem_WaitWithTimeOut(SimPowerCycleSemaphore, timeOut);
    LE_ASSERT_OK(res);
    LE_INFO("Powers On current SIM: success");

    // Remove the handler
    le_sim_RemoveNewStateHandler(SimPowerCycleHdlrRef);

    // cancel the power cycle test thread
    le_thread_Cancel(SimPowerCycleThreadRef);
}
示例#16
0
文件: main.c 项目: tegoo/legato-af
//--------------------------------------------------------------------------------------------------
void TestSim_AddHandlers
(
    void
)
{
    int i;

    // Create a semaphore to coordinate the test
    ThreadSemaphore = le_sem_Create("HandlerSem",0);

    // int app context
    memset(AppCtx, 0, NB_CLIENT*sizeof(AppContext_t));

    // Start tasks: simulate multi-user of le_sim
    // each thread subcribes to state handler using le_sim_AddNewStateHandler
    for (i=0; i < NB_CLIENT; i++)
    {
        char string[20]={0};
        snprintf(string,20,"app%dhandler", i);
        AppCtx[i].appId = i;
        AppCtx[i].appThreadRef = le_thread_Create(string, AppHandler, &AppCtx[i]);
        le_thread_Start(AppCtx[i].appThreadRef);
    }

    // Wait that the tasks have started before continuing the test
    SynchTest();

    // Sim is absent in this test
    CurrentSimState = LE_SIM_ABSENT;

    pa_simSimu_SetSelectCard(CurrentSimId);
    le_sim_SelectCard(CurrentSimId);
    pa_simSimu_ReportSimState(CurrentSimState);

    // The tasks have subscribe to state event handler:
    // wait the handlers' calls
    SynchTest();

    // Check state handler result
    CheckStateHandlerResult();

    // Check that we are in the expected states (sim absent)
    CheckSimStates();

    // Check that no more call of the semaphore
    LE_ASSERT(le_sem_GetValue(ThreadSemaphore) == 0);
}
示例#17
0
//--------------------------------------------------------------------------------------------------
static void Testle_temp_RadioThresholdEventSetting
(
)
{
    int32_t warningTemperature = 0;
    int32_t criticalTemperature = 0;
    int32_t temperature = 0;

    le_result_t res = LE_FAULT;

    TimeCounter = 0;
    PoolTemp = 1;
    LE_INFO("Set PoolTemp %d", PoolTemp);

    le_thread_Ref_t thread = le_thread_Create("tempTest",DisplayTempThread,NULL);
    le_thread_Start(thread);

    LE_INFO("!!!!!!! YOU HAVE %d SECOND TO SET THE MODULE AT"
           " THE TEMP REFERENCE !!!!!!!", WAIT_TIME);
    TimeCounter = 0;

    PoolTemp = 2;
    LE_INFO("Set PoolTemp %d", PoolTemp);

    sleep(WAIT_TIME);

    // Get current PA Tempeartaure
    res = le_temp_GetRadioTemperature(&temperature);
    LE_ASSERT(res == LE_OK);
    LE_INFO("le_temp_GetRadioTemperature return %d degree Celcus", temperature);

    // Set Warning threshold Tempeartaure
    warningTemperature = temperature + 10;
    criticalTemperature = temperature + 20;

    LE_INFO("temperature threshold are set tole_temp_SetThreshold(%d, %d) in degree Celcus",
        warningTemperature, criticalTemperature);
    res = le_temp_SetRadioThresholds(warningTemperature, criticalTemperature);
    LE_ASSERT(res == LE_OK);

    PoolTemp = 0;
    LE_INFO("Set PoolTemp %d", PoolTemp);
    LE_INFO("!!!!!!! YOU MUST REBOOT THE MODULE !!!!!!!");
    sleep(2);
}
示例#18
0
//--------------------------------------------------------------------------------------------------
static void TestLeGnssTtffMeasurement
(
    void
)
{
    uint32_t ttff = 0;
    uint32_t ttffSave = 0;
    le_thread_Ref_t positionThreadRef;

    LE_INFO("Start Test Testle_gnss_ttffTest");

    LE_INFO("Start GNSS");
    LE_ASSERT((le_gnss_Start()) == LE_OK);

    // Add Position Handler Test
    positionThreadRef = le_thread_Create("PositionThread",PositionThread,NULL);
    le_thread_Start(positionThreadRef);

    LE_INFO("loop to Wait for a 3D fix");
    LoopToGet3Dfix(&ttff);
    ttffSave = ttff;

    /* HOT Restart */
    LE_INFO("Ask for a Hot restart in 3 seconds...");
    sleep(3);
    LE_ASSERT(le_gnss_ForceHotRestart() == LE_OK);

    LE_INFO("loop to Wait for a 3D fix");
    LoopToGet3Dfix(&ttff);

    le_gnss_RemovePositionHandler(PositionHandlerRef);
    LE_INFO("Wait 5 seconds");
    sleep(5);

    // stop thread
    le_thread_Cancel(positionThreadRef);

    LE_INFO("Stop GNSS");
    LE_ASSERT((le_gnss_Stop()) == LE_OK);

    LE_INFO("TTFF start = %d msec", ttffSave);
    LE_INFO("TTFF Hot restart = %d msec", ttff);
}
示例#19
0
//--------------------------------------------------------------------------------------------------
static le_result_t Testle_sms_AsyncSendPdu
(
    void
)
{
    le_result_t res;
    bool pdu_type = true;

    NbSmsTx = NB_SMS_ASYNC_TO_SEND;

    // Init the semaphore for asynchronous callback
    sem_init(&SmsTxSynchronization,0,0);

    TxCallBack = le_thread_Create("Tx CallBack", MyTxThread, &pdu_type);
    le_thread_Start(TxCallBack);

    res = WaitFunction(&SmsTxSynchronization, 10000);
    le_thread_Cancel(TxCallBack);

    return res;
}
示例#20
0
// Create all mutexes spreaded evenly across the specified number of threads.
void createAllMutexes
(
    void
)
{
    char threadNameBuffer[MAX_THREAD_NAME_SIZE] = {0}; 

    long quotient = MutexNum / ThreadNum;
    long remainder = MutexNum % ThreadNum;
    long mutexPerThread;

    long threadCnt = 0;
    while (threadCnt < ThreadNum)
    {
        snprintf(threadNameBuffer, MAX_THREAD_NAME_SIZE, "Thread%ld", threadCnt);

        // Spread mutexes evenly among the threads, and put the remaining mutexes in the last thread.
        mutexPerThread = (threadCnt == (ThreadNum - 1)) ? (quotient + remainder) : quotient;

        // Store the thread references in an array
        ThreadRefArray[threadCnt] = le_thread_Create(threadNameBuffer, ThreadCreateMutex, (void*)mutexPerThread);

        le_thread_Start(ThreadRefArray[threadCnt]);

        threadCnt++;
    }

    LE_INFO("========== Created all threads ===========");

    // waiting for all threads to finish creating their mutexes.
    long cnt = 0;
    while (cnt < ThreadNum)
    {
        le_sem_Wait(SemaRef);
        cnt++;
    }

    LE_INFO("========== All threads have created their mutexes ===========");
}
示例#21
0
// This is testing Traceable Recursive Mutex.
// The expected result is the same as "testRecursive", except "traceable" should also be true (1).
void testTraceableRecursive
(
    void
)
{
    le_mutex_Ref_t mutex1Ref = le_mutex_CreateTraceableRecursive("TracRecurMutex1");

    le_mutex_Ref_t mutexRefArray1[3] = {mutex1Ref, mutex1Ref, mutex1Ref};

    MutexRefArray_t mra1 = {NUM_ARRAY_MEMBERS(mutexRefArray1), mutexRefArray1};

    le_thread_Ref_t thread1Ref = le_thread_Create("Thread1", LockMutex, (void*)&mra1);

    le_thread_Start(thread1Ref);

    le_sem_Wait(SemaRef);

    // Keep the function around so that mutex refs are available.
    le_sem_Wait(SemaRef);

    LE_INFO("++++++++++++++++++  END OF testTraceableRecursive (shouldn't get here) +++++++++++++++++++++");
}
示例#22
0
//--------------------------------------------------------------------------------------------------
static le_result_t Testle_sms_AsyncSendText
(
    void
)
{
    le_result_t res;
    bool pdu_type = false;

    NbSmsTx = NB_SMS_ASYNC_TO_SEND * 2 ;

    // Init the semaphore for asynchronous callback
    sem_init(&SmsTxSynchronization,0,0);

    TxCallBack = le_thread_Create("Tx CallBack", MyTxThread, &pdu_type);
    le_thread_Start(TxCallBack);

    res = WaitFunction(&SmsTxSynchronization, 120000);
    LE_ERROR_IF(res != LE_OK, "SYNC FAILED");

    le_thread_Cancel(TxCallBack);

    return res;
}
示例#23
0
//--------------------------------------------------------------------------------------------------
static void TryConnect
(
    ConnectServiceFunc_t connectFuncPtr,    ///< Function to call to connect to service
    char* serviceNamePtr                    ///< String containing name of the service
)
{
    // Print out message before trying to connect to service to give user some kind of feedback
    printf("Connecting to service ...\n");
    fflush(stdout);

    // Use a separate thread for recovery.  It will be stopped once connected to the service.
    // Make the thread joinable, so we can be sure the thread is stopped before continuing.
    le_thread_Ref_t threadRef = le_thread_Create("timout thread", TimeoutThread, serviceNamePtr);
    le_thread_SetJoinable(threadRef);
    le_thread_Start(threadRef);

    // Try connecting to the service
    connectFuncPtr();

    // Connected to the service, so stop the timeout thread
    le_thread_Cancel(threadRef);
    le_thread_Join(threadRef, NULL);
}
示例#24
0
文件: main.c 项目: H-H-bin/legato-af
//--------------------------------------------------------------------------------------------------
static void Testle_Temp_AddHandlers
(
    void
)
{
    int i;

    // int app context
    memset(AppCtx, 0, NB_CLIENT*sizeof(AppContext_t));

    // Start tasks: simulate multi-user of le_sim
    // each thread subcribes to state handler using le_sim_AddNewStateHandler
    for (i=0; i < NB_CLIENT; i++)
    {
        char string[20]={0};
        snprintf(string,20,"app%dhandler", i);
        AppCtx[i].appId = i;
        AppCtx[i].appThreadRef = le_thread_Create(string, AppHandler, &AppCtx[i]);
        le_thread_Start(AppCtx[i].appThreadRef);
    }

    // Wait that the tasks have started before continuing the test
    SynchTest();

    ExpectedStatus = 0;

    for (; ExpectedStatus <= LE_TEMP_PLATFORM_LOW_CRITICAL; ExpectedStatus++)
    {
        pa_tempSimu_TriggerEventReport(ExpectedStatus);

        // wait the handlers' calls
        SynchTest();
    }

    // Check that no more call of the semaphore
    LE_ASSERT(le_sem_GetValue(ThreadSemaphore) == 0);
}
示例#25
0
void launch_thread()
{
        int i;
        le_thread_Ref_t thread[NB_THREADS];

        GSemPtr  = le_sem_Create( SEM_NAME_1, 5);
        GSem2Ptr = le_sem_Create( SEM_NAME_2, 2);

        CU_ASSERT_PTR_NOT_EQUAL(GSemPtr, NULL);
        for (i = 0; i < NB_THREADS; i ++) {
            char threadName[20];
            snprintf(threadName,20,"Thread_%d",i);
            thread[i] = le_thread_Create(threadName, fonction_thread, NULL);
            le_thread_SetJoinable(thread[i]);
            le_thread_Start(thread[i]);
            usleep(10000);
        }
        for (i = 0; i < NB_THREADS; i ++) {
            le_thread_Join(thread[i], NULL);
        }
        le_sem_Delete(GSem2Ptr);
        le_sem_Delete(GSemPtr);
        CU_PASS("GlobalSemaphore destroy");
}
示例#26
0
//--------------------------------------------------------------------------------------------------
static le_result_t Testle_sms_Send_UCS2
(
    void
)
{
    le_result_t           res = LE_FAULT;
    le_sms_MsgRef_t       myMsg;

    NbSmsRx = 1;

    // Init the semaphore for synchronous API (hangup, answer)
    sem_init(&SmsRxSynchronization,0,0);

    RxThread = le_thread_Create("Rx SMS reception", MyRxThread, NULL);
    le_thread_Start(RxThread);

    // Wait for thread starting.
    sleep(2);

    // Check if Thread SMS RX handler has been started
    if (!RxHdlrRef)
    {
        LE_ERROR("Handler not ready !!");
        return LE_FAULT;
    }

    myMsg = le_sms_Create();
    if (myMsg)
    {

        LE_DEBUG("-TEST- Create Msg %p", myMsg);

        res = le_sms_SetDestination(myMsg, DEST_TEST_PATTERN);
        if (res != LE_OK)
        {
            le_sms_Delete(myMsg);
            return LE_FAULT;
        }

        res = le_sms_SetUCS2(myMsg, UCS2_TEST_PATTERN, sizeof(UCS2_TEST_PATTERN) / 2);
        if (res != LE_OK)
        {
            le_sms_Delete(myMsg);
            return LE_FAULT;
        }

        res = le_sms_Send(myMsg);
        if ((res == LE_FAULT) || (res == LE_FORMAT_ERROR))
        {
            le_sms_Delete(myMsg);
            return LE_FAULT;
        }

        res = WaitFunction(&SmsRxSynchronization, 120000);
        LE_ERROR_IF(res != LE_OK, "SYNC FAILED");

        le_sms_Delete(myMsg);
    }

    le_sms_RemoveRxMessageHandler(RxHdlrRef);
    le_thread_Cancel(RxThread);

    return res;
}
示例#27
0
//--------------------------------------------------------------------------------------------------
static le_result_t RecordAmrFile
(
    le_audio_Stream_t*         streamPtr,
    pa_audio_SamplePcmConfig_t* samplePcmConfigPtr
)
{
    int pipefd[2];
    int32_t wroteLen = 0;

    le_media_Format_t format = GetFormat(streamPtr->sampleAmrConfig.amrMode);

    if ((format != LE_MEDIA_AMR_NB) && (format != LE_MEDIA_AMR_WB))
    {
        LE_ERROR("Bad AMR mode");
        return LE_FAULT;
    }

    MediaAmrContext_t *amrCtxtPtr = le_mem_ForceAlloc(AudioAmrContextPool);

    if (amrCtxtPtr == NULL)
    {
        LE_ERROR("Failed to allocate memeory");
        return LE_FAULT;
    }

    memset(amrCtxtPtr, 0, sizeof(MediaAmrContext_t));

    if ( pa_media_InitAmrEncoder(   &streamPtr->sampleAmrConfig,
                                    &amrCtxtPtr->paAmrEncoderCtxPtr
                                ) != LE_OK )
    {
        LE_ERROR("Failed to init AMR Decoder");
        le_mem_Release(amrCtxtPtr);
        return LE_FAULT;
    }



    if (pipe(pipefd) == -1)
    {
        LE_ERROR("Failed to create the pipe");
        le_mem_Release(amrCtxtPtr);
        return LE_FAULT;
    }

    amrCtxtPtr->fd_in = streamPtr->fd;
    amrCtxtPtr->fd_pipe_input = pipefd[1];
    streamPtr->fd = pipefd[1];
    amrCtxtPtr->fd_pipe_output = pipefd[0];
    amrCtxtPtr->streamPtr = streamPtr;

    samplePcmConfigPtr->channelsCount = 1;
    samplePcmConfigPtr->bitsPerSample = 16;
    samplePcmConfigPtr->fileSize = (-1);

    if (format == LE_MEDIA_AMR_WB)
    {
        samplePcmConfigPtr->sampleRate = 16000;

        wroteLen = write(amrCtxtPtr->fd_in, "#!AMR-WB\n", 9);
    }
    else
    {
        samplePcmConfigPtr->sampleRate = 8000;

        wroteLen = write(amrCtxtPtr->fd_in, "#!AMR\n", 6);
    }

    if (wroteLen <= 0)
    {
        LE_ERROR("Failed to write in given fd");
        le_mem_Release(amrCtxtPtr);
        close(pipefd[0]);
        close(pipefd[1]);
        return LE_FAULT;
    }

    amrCtxtPtr->mediaHandler = le_audio_AddMediaHandler(streamPtr->streamRef,
                                       MyMediaAmrHandler, amrCtxtPtr);


    le_thread_Start(le_thread_Create("PlaySamples", RecordAmrThread, amrCtxtPtr));

    return LE_OK;
}
示例#28
0
//--------------------------------------------------------------------------------------------------
static le_result_t PlayAmrFile
(
    le_audio_Stream_t*         streamPtr,
    pa_audio_SamplePcmConfig_t* samplePcmConfigPtr
)
{
    char header[10] = {0};

    // Try to detect the 5th first characters
    if ( read(streamPtr->fd, header, 9) != 9 )
    {
        LE_WARN("AMR detection: cannot read header");
        return LE_FAULT;
    }

    if ( strncmp(header, "#!AMR", 5) == 0 )
    {
        MediaAmrContext_t * amrCtxtPtr = le_mem_ForceAlloc(AudioAmrContextPool);
        le_media_Format_t format = LE_MEDIA_FORMAT_MAX;
        int pipefd[2];

        if (amrCtxtPtr == NULL)
        {
            LE_ERROR("Failed to allocate memeory");
            return LE_FAULT;
        }

        memset(amrCtxtPtr, 0, sizeof(MediaAmrContext_t));

        if ( strncmp(header+5, "-WB\n", 4) == 0 )
        {
            LE_DEBUG("AMR-WB found");
            format = LE_MEDIA_AMR_WB;
        }
        else if ( strncmp(header+5, "-NB\n", 4) == 0 )
        {
            LE_DEBUG("AMR-NB found");
            format = LE_MEDIA_AMR_NB;
        }
        else if ( strncmp(header+5, "\n", 1) == 0 )
        {
            LE_DEBUG("AMR-NB found");
            format = LE_MEDIA_AMR_NB;
            lseek(streamPtr->fd, -3, SEEK_CUR);
        }
        else
        {
            LE_ERROR("Not an AMR file");
            le_mem_Release(amrCtxtPtr);
            return LE_FAULT;
        }

        if ( pa_media_InitAmrDecoder(format, &amrCtxtPtr->paAmrDecoderCtxPtr) != LE_OK )
        {
            LE_ERROR("Failed to init AMR Decoder");
            le_mem_Release(amrCtxtPtr);
            return LE_FAULT;
        }

        if (format == LE_MEDIA_AMR_WB)
        {
            samplePcmConfigPtr->sampleRate = 16000;
        }
        else
        {
            samplePcmConfigPtr->sampleRate = 8000;
        }

        samplePcmConfigPtr->channelsCount = 1;
        samplePcmConfigPtr->bitsPerSample = 16;
        samplePcmConfigPtr->fileSize = (-1);

        if (pipe(pipefd) == -1)
        {
            LE_ERROR("Failed to create the pipe");
            le_mem_Release(amrCtxtPtr);
            return LE_FAULT;
        }

        amrCtxtPtr->fd_in = streamPtr->fd;
        amrCtxtPtr->fd_pipe_input = pipefd[1];
        streamPtr->fd = pipefd[0];
        amrCtxtPtr->fd_pipe_output = pipefd[0];
        amrCtxtPtr->streamPtr = streamPtr;

        amrCtxtPtr->mediaHandler = le_audio_AddMediaHandler(streamPtr->streamRef,
                                       MyMediaAmrHandler, amrCtxtPtr);


        le_thread_Start(le_thread_Create("PlaySamples", PlayAmrThread, amrCtxtPtr));
    }

    return LE_OK;
}
示例#29
0
// -------------------------------------------------------------------------------------------------
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;
        }
    }
}
示例#30
0
// -------------------------------------------------------------------------------------------------
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);
        }
    }
}