I’m using Ceedling to test the code contains FreeRTOS. After each ceedling test I need to end scheduler using vTaskEndScheduler() function to check results.
The problem is - when i restart scheduler with vTaskStartScheduler() function, already created tasks, queues and timers behaves not as I expect.
How can i free all resources, which were allocated for tasks, timer etc on POSIX port?
If the scheduler isn’t stopped, the demo code indicates it will never return, how does one exit cleanly from the posix application in that case? Note that while calling exit could be an option, this will result in a ton of leaked memory that will cause trouble with valgrind.
/* Start the scheduler itself. */
vTaskStartScheduler();
/* Should never get here unless there was not enough heap space to create
* the idle and other system tasks. */
return 0;
}
I investigated this a bit this week. It’s clear to me from the code that FreeRTOS does not like to be started, stopped, and restarted. Here are a few issues I noticed:
Many of FreeRTOS’s global variables aren’t in a good state after stopping and restarting (e.g.xSchedulerEnd is not reset to True)
The use of pthread_once to call prvSetupSignalsAndSchedulerPolicy will only happen once per execution (not on a stop/start of FreeRTOS)
Running tasks are not killed when the scheduler is stopped (ie vPortCancelThread is not called on all tasks, only on the timer and idle tasks)
I believe the signal handling might be messed up on subsequent runs, though I struggled to debug this one.
That said, I’m getting reliable graceful shutdowns when only starting/stopping once. Here’s what I do:
// The FreeRTOS tick handler happens via SIGALRM, and it also kicks off preemptive task
// switching, which is not what we want on the main thread, since it's not a real FreeRTOS task.
// Just disable SIGALRM on this thread so that it only happens on FreeRTOS tasks.
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
// Start the FreeRTOS scheduler
std::thread schedulerThread([]() {
xTaskCreate(appMainTask, "app_main", 10000, NULL, 1, NULL);
vTaskStartScheduler();
log_i("Scheduler thread done");
});
while (mainLoop()) {
usleep(1000000.0 / 60.0);
}
log_i("Shutting down");
vTaskEndScheduler();
schedulerThread.join();
I had to remove these two lines from vTaskEndScheduler() for this to work (not sure how these are supposed to work):
Maybe a good starting point would be to add code to vPortEndScheduler to clean up all the resources, then at least valgrind results would be cleaner, and then that could be expanded into better start/stop/start behavior if someone was sufficiently motivated.