How to properly stop freertos simulation (FreeRTOS Kernel V10.4.6)

Hey guys,
I’m using Freertos in a Device and in the Windows and Linux Simulation.
Some of our Unittests need a Freertos Context (because they use FreeRTOS Mutexes and Threads etc.)
However I did not found a way how to terminate my WIndows ad Linux Port properly

static void RunGTestInTask(void* pvParameters)
{
const int iRes = RUN_ALL_TESTS();
vTaskEndScheduler();
}

int main(int argc, char* argv)
{
::testing::InitGoogleTest(&argc, argv);
configASSERT(pdTRUE == xTaskCreate(
RunGTestInTask, /* Function that implements the task. /
“GTestTask”, /
Text name for the task. /
200, /
Stack size in words, not bytes. /
(void
)1, /* Parameter passed into the task. /
5,/
Priority at which the task is created. /
&mg_gtestTask)); /
Used to pass out the created task’s handle. */

/* Start the tasks and timer running. */
vTaskStartScheduler();

//is there any way to return to main() after launching the scheduler?
return 0;
}

However I have noticed that 3 Threads are still running even after vTaskEndScheduler()

  1. Idle Task
  2. Timer Task
  3. Simulated Peripheral Timer

The Simulated Peripheral Timer crashes in prvSimulatedPeripheralTimer() in the configassert

/* The interrupt is now pending - notify the simulated interrupt
handler thread. Must be outside of a critical section to get here so
the handler thread can execute immediately pvInterruptEventMutex is
released. */
configASSERT( ulCriticalNesting == 0UL );

The ideal way would be a solution which allows me to return to main().
But I’m open to other suggestions how to make my test application to stop :slight_smile:

Could you help me out here?

If you are trying to unit test your application, can you not mock FreeRTOS APIs? If you cannot do so and want to run the scheduler, you may try the following options (note that I have not tested any of these):

  1. Call exit(0) after RUN_ALL_TESTS.
  2. Write a wrapper program which executes the test application and reads output from it. Once it detects that tests are complete (some sort of end output marker), it kills the test application.

Hey Gaurav,
thank you for your feedback.
In some cases we can remove freertos dependencies for the tests, in most cases this is not possible. It is possible to wrap a FreeRTOS task into a std::thread (likewise for for Mutex). However wrapping a eventgroup into a std::condition_variable is not that simple.

Also wrapping in C is only possible with GCC via GCCs Linker flag wrap=xxx not in MSVC. Also since FreeRTOS is written in C, we cannot use inheritance to overwrite functions. What kind of wrapping would you suggest?

I have tried calling exit(0) directly after RUN_ALL_TESTS() but the program won’t stop since the Simulated Peripheral Timer Task, the Timer Task and the Idle Task are still running. :frowning:

Writing a wrapper which basically starts the unittest as an external process would be possible, however debugging the unittest will be hard/impossible :wink:

After some testing I found out the on windows it’s the simulated timer tick task which keeps the program from exiting properly
However I have made some few changes to the windows port

in prvSimulatedPeripheralTimer() replace the

1. )for(;;) with while(pdTRUE == xPortRunning)
2. )add an if (xPortRunning == pdTRUE) { ...} after the sleep

in vPortEndScheduler()

1.) replace the exit(0) with xPortRunning = pdFALSE;

(from my understanding vPortEndScheduler() should only terminate the scheduler, not the whole program. => User can call exit() in his application at some point he likes

=>would it be possible to add these changes to the official windows port? I can’t believe I’m the only person who tried to stop freertos properly in the simulation :wink:

We use CMock for mocking - https://github.com/FreeRTOS/FreeRTOS/tree/main/FreeRTOS/Test/CMock

Would you please elaborate why do you think so? Your wrapper should launch your unit test application, parse the output from it and terminate it upon detecting some end marker in the output. If so, you should be able to run the unit test application independently for debugging purpose?

It is not common for a FreeRTOS application to end the scheduler and therefore, vPortEndScheduler is not implemented in many ports.

I think that a simple wrapper (if it works for your use case) would probably better as vPortEndScheduler is not rigorously tested. But if you want to go with these changes, please raise a PR and we will take a look.

Thanks.

Hey Gaurav,
thx for your quick reply.
I’ll have a look at CMock

Would you please elaborate why do you think so? Your wrapper should launch your unit test application, parse the output from it and terminate it upon detecting some end marker in the output. If so, you should be able to run the unit test application independently for debugging purpose?

My understand was that you suggested to pack the simulation into a separate executable.
The simulation is started from the Unittest for ex. via QProcess or std::system(). Unittest and the simulation communicate with TCP IP localhost.
Now in this scenario it’s very hard to Debug the simulation as it is a separate executable.
Or what alternative did you have in mind?

I think that a simple wrapper (if it works for your use case) would probably better as vPortEndScheduler is not rigorously tested. But if you want to go with these changes, please raise a PR and we will take a look.

Alright I will try that.
Thx for your feedback :slight_smile:

I was thinking like you have the following 2 executable -

  1. Unit Test Application - This is a standalone application that runs all the tests and prints the results to stdout/stderr. After it finishes, it continues to run only idle task as it cannot cleanly exit.
  2. Wrapper Application - It launches the Unit Test Application and reads the output from that using IPC. Once it detects that the application is done executing tests, it terminates that.

In that case how would you debug the Unittest application.
From my understanding this standalone application just runs in an endless loop until it gets a command from the Wrapper Application to run Test_Function_A().

If I’d like to debug the Unittest Application I’ll have to mock the commands right?

No - this standalone application runs all the tests from start to end without needing any command.