Restart FreeRTOS kernel on POSIX port

Hello!

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?

I have not used seedling but why do you need to end scheduler between tests?

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):

    xCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
    prvSuspendSelf( xCurrentThread );

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.

2 Likes

PR opened here to address signal deadlock issues, shutting down the scheduler cleanly, and being able to restart the scheduler: Improve POSIX port functionality by cmorganBE · Pull Request #914 · FreeRTOS/FreeRTOS-Kernel · GitHub

@johnboiles for sure the signals were causing issues. The approach of using signals to interrupt execution is neat but also was causing deadlocks.

Example applications used to debug and test are here: GitHub - cmorganBE/freertos_posix

1 Like

the cleanup in this PR also gets valgrind running cleanly.

@aggarg thoughts on if/who I would reach out to to get review on the PR?

I will share with someone in my team. Thank you for your change.

Hey @cmorganBE, thanks for raising your PR! I’ve started reviewing it and have left some comments on the PR itself