Unit Test Strategy

interesting indeed. Everything looks sound so far, ie there doesn’t appear to be memory corruption anywhere.

Now since we don’t get to see your code (in particular how you create the mutex and whether you only use the mutex wrappers to access the mutex or also use “manual” claim and release outside of the abstractions), the only thing I can suggest is that you count the times you construct and destruct your mutex wrappers and see if there are mismatches.

I trust you not to do anything fishy in your code such as making copies of your mutex wrappers (copy constructor invocation fallacy) and/or passing these copies on to other tasks…

The mutex wrapper isn’t secret at all :slight_smile: I use this wrapper almost without exceptions. The only exceptions are like in a timer callback, where I don’t want to stall the timer task waiting for a mutex. Then I return immediately if the mutex could not be taken.


/**
 * Class for locking and unlocking mutex. Simply add an instance of CicMutex
 * in a function to lock a semaphore, and it will be automatically unlocked by
 * CicMutex's destructor.
 */

class CicMutex
{
    public:
        /**
         * Constructor which locks a mutex.
         *
         * @param[in]   mutex   Mutex to lock and unlock
         */
        explicit CicMutex(SemaphoreHandle_t mutex) : m_mutex(mutex)
        {
            CIC_ASSERT(mutex != nullptr);
            xSemaphoreTake(mutex, portMAX_DELAY);
        }
        /**
         * Destructor, which unlocks the semaphore given in the constructor.
         */
        ~CicMutex()
        {
            xSemaphoreGive(m_mutex);
        }
    private:
        /**
         * Mutex to be unlocked by destructor.
         */
        SemaphoreHandle_t m_mutex;
};

The mutex is created in CicSettings::init() and this is how it is used:



void CicSettings::config()
{
    CicMutex settings_list_mutex = CicMutex(m_os.settings_list_mutex);
    bool is_image_ok = read_settings_image();
    if (is_image_ok)
    {
        read_settings();
    }
    else
    {
        PRINT_ERROR("[%s:%d] CIC Settings image invalid\r\n", __file__, __LINE__);
    }
}

So what does CicSettings::init() resolve to? Platform specific mutex implementations? Implying that you may have differently working muteces on native FreeRTOS and Posix Linux? If so, is it safe to assume that the two implementations do have matching semantics (I’m not familiar with Posix muteces)?

The CicSettings is mocked so it only creates the mutex using FreeRTOS API. I’m not an expert on FreeRTOS, but I can’t see anything in the Linux port which is for mutexes or semaphore.


void CicSettingsMock::init()
{
    m_os.settings_list_mutex = xSemaphoreCreateMutex();
}

I added a printout from prvResumeThread() from [port.c], and it can resume the new task in between. Should that be possible?


[os/FreeRTOS/tasks.c:4173] 7F5DE4019B70    <---- pxTCB
[os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:504] 7F5DDC003B98
[os/FreeRTOS/tasks.c:4174] 7F5DDC003BD0   <---- pxCurrentTCB

I suspect my problem is that the Linux port vPortSystemTickHandler() does not prevent task switch in a critical section. It doesn’t check uxCriticalNesting which perhaps it should. Will test something tomorrow.

Unlikey. What normally happens when crit sections aren’t working properly is that lists get corrupted, ending in faults, access violations or similar.

Yet I wouldn’t mind if that was the solution… :wink: please keep us informed.

Thanks!

Are you creating threads manually with pthread_create to simulate interrupts ?
if so you will need to mask them from receiving signals.

check the “Common Problems and Solutions” → Creating threads at the end.

No, the test case only creates one FreeRTOS task.
From main() I create a pthread which first creates the task which runs the gtest and then starts the FreeRTOS scheduler. The gtest task runs a few test cases with no tasks and then runs the test case where a task is created and deleted.
I should simplify this test case to just creating a task and do some simple operations.

My bad, I said a thread to simulate interrupts, which is the normal use case, but in fact any thread that is not created by FreeRTOS needs its signals masked.
The reason is that the Posix port uses signals to orchestrate the threads which enables it to act as a single processor system.
A stray thread would receive signals and added to the mix of FreeRTOS controlled threads… and bad things almost always happen.

I can’t see any other thread created by accident or by purpose. Just before the crash there are two quick task switches. This is due to that freq_mgr_task() calls vTaskDelay() immediatly in waiting for a notification from the system control to go from config state to operating state (basically no units are allowed to call each other until operating state).

Actually, one thing that comes to mind is that the function create_nvm_file() calls fwrite(). My CicNvm is ported to read and write to Linux file system, so I save NVM area files before CicSettings is started (which reads settings from CicNvm) Wonder if that is causing problems…

I’ve created a log where I print task names so it is easy to match to gdb LWP’s.


Starting program: /home/corebon/work/cic/exe/CIC_GTEST.exe 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff78d8700 (LWP 5584)]
[os/FreeRTOS/tasks.c:xTaskCreate] gtest_task
[New Thread 0x7ffff0019640 (LWP 5585)]
[os/FreeRTOS/tasks.c:xTaskCreate] IDLE
[New Thread 0x7ffff70d7700 (LWP 5586)]
[os/FreeRTOS/tasks.c:xTaskCreate] Tmr Svc
[New Thread 0x7ffff68d6700 (LWP 5587)]
[os/FreeRTOS/tasks.c:vTaskSwitchContext:3018] Tmr Svc
[os/FreeRTOS/tasks.c:vTaskSwitchContext:3094] pxCurrentTCB = gtest_task
[==========] Running 38 tests from 4 test suites.
[----------] Global test environment set-up.
[----------] 32 tests from CicCommon
[ RUN      ] CicCommon.FileMacro
[       OK ] CicCommon.FileMacro (0 ms)
[ RUN      ] CicCommon.SEC_TO_MS
[       OK ] CicCommon.SEC_TO_MS (0 ms)
[ RUN      ] CicCommon.SEC_TO_US
[       OK ] CicCommon.SEC_TO_US (0 ms)
[ RUN      ] CicCommon.MIN_TO_SEC
[       OK ] CicCommon.MIN_TO_SEC (0 ms)
[ RUN      ] CicCommon.MIN_TO_MS
[       OK ] CicCommon.MIN_TO_MS (0 ms)
[ RUN      ] CicCommon.MS_TO_SEC
[       OK ] CicCommon.MS_TO_SEC (0 ms)
[ RUN      ] CicCommon.NS_TO_MS
[       OK ] CicCommon.NS_TO_MS (0 ms)
[ RUN      ] CicCommon.NS_TO_US
[       OK ] CicCommon.NS_TO_US (0 ms)
[ RUN      ] CicCommon.SIZE_OF_ARRAY
[       OK ] CicCommon.SIZE_OF_ARRAY (0 ms)
[ RUN      ] CicCommon.MIN
[       OK ] CicCommon.MIN (0 ms)
[ RUN      ] CicCommon.MAX
[       OK ] CicCommon.MAX (0 ms)
[ RUN      ] CicCommon.DIFF
[       OK ] CicCommon.DIFF (0 ms)
[ RUN      ] CicCommon.ABS
[       OK ] CicCommon.ABS (0 ms)
[ RUN      ] CicCommon.CONSTRAIN
[       OK ] CicCommon.CONSTRAIN (0 ms)
[ RUN      ] CicCommon.CONSTRAIN_U_TO_INT32
[       OK ] CicCommon.CONSTRAIN_U_TO_INT32 (0 ms)
[ RUN      ] CicCommon.ALIGN_UP
[       OK ] CicCommon.ALIGN_UP (0 ms)
[ RUN      ] CicCommon.ALIGN_DOWN
[       OK ] CicCommon.ALIGN_DOWN (0 ms)
[ RUN      ] CicCommon.PERCENT_OF
[       OK ] CicCommon.PERCENT_OF (0 ms)
[ RUN      ] CicCommon.SIGN
[       OK ] CicCommon.SIGN (0 ms)
[ RUN      ] CicCommon.INT_ROUND
[       OK ] CicCommon.INT_ROUND (0 ms)
[ RUN      ] CicCommon.DBL_ROUND
[       OK ] CicCommon.DBL_ROUND (0 ms)
[ RUN      ] CicCommon.byteswap16
[       OK ] CicCommon.byteswap16 (0 ms)
[ RUN      ] CicCommon.byteswap32
[       OK ] CicCommon.byteswap32 (0 ms)
[ RUN      ] CicCommon.CIC_IS_BIT_SET
[       OK ] CicCommon.CIC_IS_BIT_SET (0 ms)
[ RUN      ] CicCommon.CIC_SET_BIT
[       OK ] CicCommon.CIC_SET_BIT (0 ms)
[ RUN      ] CicCommon.CIC_COND_SET_BIT
[       OK ] CicCommon.CIC_COND_SET_BIT (0 ms)
[ RUN      ] CicCommon.cic_strtod
[       OK ] CicCommon.cic_strtod (0 ms)
[ RUN      ] CicCommon.cic_strtoul_dec
[       OK ] CicCommon.cic_strtoul_dec (0 ms)
[ RUN      ] CicCommon.cic_strtoull_dec
[       OK ] CicCommon.cic_strtoull_dec (0 ms)
[ RUN      ] CicCommon.cic_strtoul_hex
[       OK ] CicCommon.cic_strtoul_hex (0 ms)
[ RUN      ] CicCommon.cic_print_double
[       OK ] CicCommon.cic_print_double (0 ms)
[ RUN      ] CicCommon.byteswap16_array
[       OK ] CicCommon.byteswap16_array (0 ms)
[----------] 32 tests from CicCommon (0 ms total)

[----------] 2 tests from CicErrorCounter
[ RUN      ] CicErrorCounter.register_error_stdout
[       OK ] CicErrorCounter.register_error_stdout (1 ms)
[ RUN      ] CicErrorCounter.register_error_file
[       OK ] CicErrorCounter.register_error_file (0 ms)
[----------] 2 tests from CicErrorCounter (1 ms total)

[----------] 2 tests from CicCommandTest
[ RUN      ] CicCommandTest.subscribeOk
[cic_freq_mgr.cpp:161] (0 == 0x00000000)
[       OK ] CicCommandTest.subscribeOk (0 ms)
[ RUN      ] CicCommandTest.subscribeFail
[cic_freq_mgr.cpp:161] (0 == 0x00000000)
[       OK ] CicCommandTest.subscribeFail (0 ms)
[----------] 2 tests from CicCommandTest (0 ms total)

[----------] 2 tests from CicFreqManagerTest
[ RUN      ] CicFreqManagerTest.SetGetFrequency
[os/FreeRTOS/tasks.c:xTaskCreate] freq_mgr_task
[New Thread 0x7ffff60d5700 (LWP 5588)]
[cic_freq_mgr_test.cpp:96] Settings file: 'cic_freq_mgr_settings.txt'
[os/FreeRTOS/tasks.c:xTaskPriorityDisinherit:pxTCB]         gtest_task
[os/FreeRTOS/tasks.c:xTaskPriorityDisinherit:pxCurrentTCB]  gtest_task
[os/FreeRTOS/tasks.c:xTaskPriorityDisinherit:pxTCB]         gtest_task
[os/FreeRTOS/tasks.c:xTaskPriorityDisinherit:pxCurrentTCB]  gtest_task
[os/FreeRTOS/tasks.c:xTaskPriorityDisinherit:pxTCB]         gtest_task
[os/FreeRTOS/tasks.c:xTaskPriorityDisinherit:pxCurrentTCB]  gtest_task
[os/FreeRTOS/tasks.c:vTaskSwitchContext:3094] pxCurrentTCB = freq_mgr_task
[os/FreeRTOS/tasks.c:vTaskSwitchContext:3094] pxCurrentTCB = gtest_task
[os/FreeRTOS/tasks.c:xTaskPriorityDisinherit:pxTCB]         freq_mgr_task
[os/FreeRTOS/tasks.c:xTaskPriorityDisinherit:pxCurrentTCB]  gtest_task
ASSERT-os/FreeRTOS/tasks.c-4182

Thread 3 "CIC_GTEST.exe" received signal SIGABRT, Aborted.
[Switching to Thread 0x7ffff0019640 (LWP 5585)]
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) thread apply all bt

Thread 6 (Thread 0x7ffff60d5700 (LWP 5588)):
#0  futex_wait_cancelable (private=, expected=0, futex_word=0x7fffe800aaa4) at ../sysdeps/nptl/futex-internal.h:183
#1  __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x7fffe800aa50, cond=0x7fffe800aa78) at pthread_cond_wait.c:508
#2  __pthread_cond_wait (cond=0x7fffe800aa78, mutex=0x7fffe800aa50) at pthread_cond_wait.c:638
#3  0x0000555555584376 in event_wait (ev=0x7fffe800aa50) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/utils/wait_for_event.c:41
#4  0x0000555555583c54 in prvSuspendSelf (thread=thread@entry=0x7fffe8004a88) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:496
#5  0x0000555555583c9b in prvSwitchThread (pxThreadToResume=, pxThreadToSuspend=pxThreadToSuspend@entry=0x7fffe8004a88) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:474
#6  0x0000555555583d28 in vPortYieldFromISR () at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:279
#7  0x0000555555584175 in vPortYield () at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:287
#8  0x0000555555582112 in vTaskDelay (xTicksToDelay=xTicksToDelay@entry=100) at os/FreeRTOS/tasks.c:1371
#9  0x00005555555a2d7e in CicFreqManager::freq_mgr_task (this=0x7fffe800a490) at cic/src/cic_freq_mgr.cpp:398
#10 0x00005555555a2e69 in CicFreqManager::freq_mgr_task_entry (param=) at cic/src/cic_freq_mgr.cpp:392
#11 0x000055555558403f in prvWaitForStart (pvParams=0x7fffe8004a88) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:440
#12 0x00007ffff79fe609 in start_thread (arg=) at pthread_create.c:477
#13 0x00007ffff7ee2293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 5 (Thread 0x7ffff68d6700 (LWP 5587)):
#0  futex_wait_cancelable (private=, expected=0, futex_word=0x7ffff001bda4) at ../sysdeps/nptl/futex-internal.h:183
#1  __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x7ffff001bd50, cond=0x7ffff001bd78) at pthread_cond_wait.c:508
#2  __pthread_cond_wait (cond=0x7ffff001bd78, mutex=0x7ffff001bd50) at pthread_cond_wait.c:638
#3  0x0000555555584376 in event_wait (ev=0x7ffff001bd50) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/utils/wait_for_event.c:41
#4  0x0000555555583c54 in prvSuspendSelf (thread=thread@entry=0x7ffff001bc48) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:496
#5  0x0000555555583c9b in prvSwitchThread (pxThreadToResume=, pxThreadToSuspend=pxThreadToSuspend@entry=0x7ffff001bc48) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:474
#6  0x0000555555583d28 in vPortYieldFromISR () at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:279
#7  0x0000555555584175 in vPortYield () at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:287
#8  0x0000555555583a14 in prvProcessTimerOrBlockTask (xNextExpireTime=, xListWasEmpty=1) at os/FreeRTOS/timers.c:633
#9  0x0000555555583bd6 in prvTimerTask (pvParameters=) at os/FreeRTOS/timers.c:579
#10 0x000055555558403f in prvWaitForStart (pvParams=0x7ffff001bc48) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:440
#11 0x00007ffff79fe609 in start_thread (arg=) at pthread_create.c:477
#12 0x00007ffff7ee2293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 4 (Thread 0x7ffff70d7700 (LWP 5586)):
#0  futex_wait_cancelable (private=, expected=0, futex_word=0x7ffff001ab20) at ../sysdeps/nptl/futex-internal.h:183
#1  __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x7ffff001aad0, cond=0x7ffff001aaf8) at pthread_cond_wait.c:508
#2  __pthread_cond_wait (cond=0x7ffff001aaf8, mutex=0x7ffff001aad0) at pthread_cond_wait.c:638
#3  0x0000555555584376 in event_wait (ev=0x7ffff001aad0) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/utils/wait_for_event.c:41
#4  0x0000555555583c54 in prvSuspendSelf (thread=thread@entry=0x7ffff001a9c8) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:496
#5  0x0000555555584029 in prvWaitForStart (pvParams=0x7ffff001a9c8) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:433
#6  0x00007ffff79fe609 in start_thread (arg=) at pthread_create.c:477
#7  0x00007ffff7ee2293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 3 (Thread 0x7ffff0019640 (LWP 5585)):
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007ffff7de5859 in __GI_abort () at abort.c:79
#2  0x000055555558505c in cic_assert_failed (file=file@entry=0x55555562c014 "os/FreeRTOS/tasks.c", line=line@entry=4182) at gtest/ports/src/cic_common_port.c:29
#3  0x0000555555582ba9 in xTaskPriorityDisinherit (pxMutexHolder=0x7fffe8004ac0) at os/FreeRTOS/tasks.c:4182
#4  0x0000555555580856 in prvCopyDataToQueue (pxQueue=pxQueue@entry=0x7fffe800a3a0, pvItemToQueue=pvItemToQueue@entry=0x0, xPosition=xPosition@entry=0) at os/FreeRTOS/queue.c:2144
#5  0x0000555555580b98 in xQueueGenericSend (xQueue=xQueue@entry=0x7fffe800a3a0, pvItemToQueue=pvItemToQueue@entry=0x0, xTicksToWait=, xTicksToWait@entry=0, xCopyPosition=xCopyPosition@entry=0) at os/FreeRTOS/queue.c:866
#6  0x00005555555c6980 in CicMutex::~CicMutex (this=0x7ffff0018a88, __in_chrg=) at cic/inc/cic_mutex.hpp:42
#7  CicNvm::write (this=, area=area@entry=CIC_NVM_AREA_PROD_DATA, buf_p=buf_p@entry=0x7fffe800ad60, buf_size=8) at gtes--Type  for more, q to quit, c to continue without paging--c
t/ports/src/cic_nvm_port.cpp:121
#8  0x00005555555d6bde in CicSettingsMock::create_nvm_file (this=this@entry=0x7fffe8003280, settings_file_name_p=settings_file_name_p@entry=0x55555563667d "prod_data.txt", nvm_area=nvm_area@entry=CIC_NVM_AREA_PROD_DATA) at gtest/mocks/src/cic_settings_mock.cpp:58
#9  0x00005555555d6c5d in CicSettingsMock::config (this=0x7fffe8003280, settings_file_name_p=settings_file_name_p@entry=0x5555556393df "cic_freq_mgr_settings.txt") at gtest/mocks/src/cic_settings_mock.cpp:42
#10 0x00005555555f96d8 in CicFreqManagerTest::SetUp (this=0x7fffe800a350) at gtest/tests/src/cic_freq_mgr_test.cpp:97
#11 0x000055555562b091 in testing::internal::HandleSehExceptionsInMethodIfSupported (location=0x55555563a473 "SetUp()", method=, object=0x7fffe800a350) at ./googletest/src/gtest.cc:2414
#12 testing::internal::HandleExceptionsInMethodIfSupported (object=object@entry=0x7fffe800a350, method=, location=location@entry=0x55555563a473 "SetUp()") at ./googletest/src/gtest.cc:2469
#13 0x000055555561e641 in testing::Test::Run (this=0x7fffe800a350) at ./googletest/src/gtest.cc:2503
#14 testing::Test::Run (this=0x7fffe800a350) at ./googletest/src/gtest.cc:2498
#15 0x000055555561e815 in testing::TestInfo::Run (this=0x5555556a21b0) at ./googletest/src/gtest.cc:2684
#16 testing::TestInfo::Run (this=0x5555556a21b0) at ./googletest/src/gtest.cc:2657
#17 0x000055555561e8fd in testing::TestSuite::Run (this=0x5555556a2380) at ./googletest/src/gtest.cc:2816
#18 testing::TestSuite::Run (this=0x5555556a2380) at ./googletest/src/gtest.cc:2795
#19 0x000055555561ee1c in testing::internal::UnitTestImpl::RunAllTests (this=0x55555569d0a0) at /usr/include/c++/9/bits/stl_vector.h:1040
#20 0x000055555562b601 in testing::internal::HandleSehExceptionsInMethodIfSupported (location=0x55555563b848 "auxiliary test code (environments or event listeners)", method=, object=0x55555569d0a0) at ./googletest/src/gtest.cc:2414
#21 testing::internal::HandleExceptionsInMethodIfSupported (object=0x55555569d0a0, method=, location=location@entry=0x55555563b848 "auxiliary test code (environments or event listeners)") at ./googletest/src/gtest.cc:2469
#22 0x000055555561f04c in testing::UnitTest::Run (this=0x55555568a3e0 ) at ./googletest/include/gtest/gtest.h:1412
#23 0x00005555555d6d21 in RUN_ALL_TESTS () at /usr/include/gtest/gtest.h:2490
#24 gtest_task (param=) at gtest/main_gtest.cpp:19
#25 0x000055555558403f in prvWaitForStart (pvParams=0x7ffff0019f48) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:440
#26 0x00007ffff79fe609 in start_thread (arg=) at pthread_create.c:477
#27 0x00007ffff7ee2293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 2 (Thread 0x7ffff78d8700 (LWP 5584)):
#0  0x00007ffff7e07322 in __GI___sigtimedwait (set=set@entry=0x7ffff78d7e40, info=info@entry=0x7ffff78d7d80, timeout=timeout@entry=0x0) at ../sysdeps/unix/sysv/linux/sigtimedwait.c:29
#1  0x00007ffff7e066ac in __GI___sigwait (set=set@entry=0x7ffff78d7e40, sig=sig@entry=0x7ffff78d7e3c) at ../sysdeps/unix/sysv/linux/sigwait.c:28
#2  0x000055555558422e in xPortStartScheduler () at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:197
#3  0x0000555555581ccc in vTaskStartScheduler () at os/FreeRTOS/tasks.c:2090
#4  0x00005555555d6d02 in free_rtos_thread (data=) at gtest/main_gtest.cpp:50
#5  0x00007ffff79fe609 in start_thread (arg=) at pthread_create.c:477
#6  0x00007ffff7ee2293 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95

Thread 1 (Thread 0x7ffff78d9740 (LWP 5580)):
#0  vPortSystemTickHandler (sig=14) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:369
#1  
#2  0x00007ffff7ea03bf in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7fffffffde90, rem=rem@entry=0x7fffffffde90) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
#3  0x00007ffff7ea6047 in __GI___nanosleep (requested_time=requested_time@entry=0x7fffffffde90, remaining=remaining@entry=0x7fffffffde90) at nanosleep.c:27
#4  0x00007ffff7ea5f7e in __sleep (seconds=0) at ../sysdeps/posix/sleep.c:55
#5  0x00005555555d6de6 in main (argc=, argv=) at gtest/main_gtest.cpp:72
(gdb) 

Martin, just a side issue question:

Do I read it correctly that you spend a significant amount of time to pinpoint a problem that does not show in the field software but may be attributed to something in the emulation layer whose sole purpose is to run a unit test?

No criticism whatsoever, just out of curiosity.

Btw, what results did your analysis concerning potentially unprotected sys tick handler yield?

Haha, well it’s hard to leave a mystery unsolved. But of course I’d really like this unit test to work because I need to know my code can handle improbable situations. As a programmer I consider myself flawless when writing code, but when adding unit tests which throws all possible inputs to API’s it unfortunately turns out embarrassingly clear I’m not. I’d rather keep that for myself than letting a customer find out :slight_smile: Also, I think someone else will want to be able to setup unit tests with FreeRTOS like myself. The possibilities of testing units with a semi-simulated environment on a desktop are endless. It takes more time to run unit test with an RTOS running, but on the other hand one can feed it with any input.

I think the problem is with main, which is a thread at the end of the day, not controlled by FreeRTOS, and has its signals not masked.
if you look at your main thread backtrace

Thread 1 (Thread 0x7ffff78d9740 (LWP 5580)):
#0  vPortSystemTickHandler (sig=14) at os/FreeRTOS/portable/ThirdParty/GCC/Posix/port.c:369
#1  
#2  0x00007ffff7ea03bf in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7fffffffde90, rem=rem@entry=0x7fffffffde90) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
#3  0x00007ffff7ea6047 in __GI___nanosleep (requested_time=requested_time@entry=0x7fffffffde90, remaining=remaining@entry=0x7fffffffde90) at nanosleep.c:27
#4  0x00007ffff7ea5f7e in __sleep (seconds=0) at ../sysdeps/posix/sleep.c:55
#5  0x00005555555d6de6 in main (argc=, argv=) at gtest/main_gtest.cpp:72

main should not be executing vPortSystemTickHandler .

So either call vTaskStartScheduler(); from main or mask its(main) signals as described in the documentation.

1 Like

I can confirm that it was the main thread which caused the problems :slight_smile: Thank you very much! I created a test without my units just to test tasks, mutexes and delays, and it seems fine.


int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);

    // Mask out all signals to main thread
    {
        sigset_t set;
        sigfillset( &set );
        pthread_sigmask( SIG_SETMASK, &set, NULL );
    }

    // Create the FreeRTOS scheduler thread and wait until it is done
    pthread_create(&m_freertos_thread_id, nullptr, &free_rtos_thread, nullptr);

    while (!m_test_is_done)
    {
        sleep(1);
    }

    end_free_rtos();

    return m_result;
}
1 Like

Great news!
I am glad your problem is solved :slight_smile: