Stop and restart a FreeRTOS task on another core?

I had posted this on Stack Overflow here: c - Stop and restart a FreeRTOS task on another core? - Stack Overflow - but it seems this forum might be more appropriate, so I’ll repost here - hope that’s OK.

I’ll mention that in the meantime, I’ve seen Is there a way to reset = restart a task?

You can delete a task and re-create it which would essentially restart it. Why do you want to do it though?

… so I could rephrase my question as: is the task deletion and recreation still the right approach for what I describe in the post? And, I’ll mention that I want to do this, because I want to synchronize the processing done on core 1 to an external signal (an interrupt on core 0); and I also work with statically allocated tasks. Here is the the rest of the SO post:

Let’s say I work on a FreeRTOS application on an MCU with two cores. There are tasks running on core 1 of the format:

void mytask_01( void* pvParameters ) {
  while (1) {
    ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // sleep and wait for notification to wake
    do_something_first_01();
    do_something_else_02();
    do_something_different_03();
    // all done, go back to sleeping
  }
}

So, at any given time, core 1 might be running some of these tasks - or it might be idle.

Anyways - what I want to do is: if I receive a certain interrupt on core 0, I want to stop whatever task is running; and run another initialization task, and then let the core 1 processes run as if started anew.

First problem is, I cannot tell how to find the currently running FreeRTOS task hanlde on core 1 from an interrupt on core 0: the only thing I’ve found in the API so far is RTOS task (thread) utilities: xTaskGetCurrentTaskHandle(); however it has a signature:

TaskHandle_t xTaskGetCurrentTaskHandle( void );  // The handle of the currently running (calling) task.

… but I assume this would return currently running task on “this”/“current” core - and I’d want to get the currently running task on another core.

But let’s say I obtain that task handle somehow - how can I then “stop” the currently running task? Let’s say, when the interrupt hits on core 0, it is the mytask_01() above running on core 1, and it is executing the do_something_else_02(); function at that moment. Let’s say I get the mytask_01 task handle in this interrupt on core 0. If I just call vTaskSuspend():

void vTaskSuspend( TaskHandle_t xTaskToSuspend );

… I assume FreeRTOS will “freeze” mytask_01 at the point of execution, that is somewhere in the do_something_else_02() function - so if I afterwards call vTaskResume():

void vTaskResume( TaskHandle_t xTaskToResume );

… the mytask_01 would continue from the point in the do_something_else_02() function where it was suspended. But I do NOT want that - what I want is: once the mytask_01 has been stopped/suspended, next time it is woken, I want it to start from the beginning: i.e. enter the while(1) loop, then end up on the ulTaskNotifyTake() and sleep - and then when woken by a notification signal the next time, the mytask_01 should start with executing do_something_first_01().

How can I achieve something like this?

I suppose the first big question which you haven’t indicated, is what type of multi-core operation are you using? Is it AMP, where each core has its own copy of FreeRTOS, doing its own scheduling, or SMP, where one copy of FreeRTOS is handling both cores?

I will assume AMP, since SMP is fairly new to FreeRTOS and has only supported limited targets.

With AMP, since there are two separate copies of FreeRTOS running, the cores run very independently, and can only signal one another through things like stream buffers or user built signaling primitives.

If core 0 whats something to happen on core 1, it needs to signal (somehow, which is processor dependent) an interrupt on core 1, after placing in some shared memory, information for that ISR on core 1 about what to do.

If you have a lot of this sort of signaling, it might make sense to switch to SMP, if it is available, and just pin your tasks to the appropriate core, then the SMP internals while handle all those details.

In my mind, “deleting and recreating” a task is almost NEVER the right way to do things.

Note, you comment about “Stop whatever task is running” is almost certainly a recipe for putting a system into an unstable state. It can work on “big” system for PROCESSES, because they run isolated from each other, and the OS will cleanup after a process when it is killed. FreeRTOS does NOT have “Processes”, but “Tasks”, that are not any where near as isolated, and asynchronously aborting a task has the danger of leaving the system in a incorrect state, as everything that the task “owned” gets lost.

If you want the task to stop and restart, set a flag, that the task checks, and when it sees it, then it CLEANLY ends off what it is doing and restarts. Only the task itself knows when this can be safely done unless you follow VERY rigid coding practices.

1 Like

Thanks for the response @richard-damon :

Sorry about that - it is indeed SMP, and:

… this is what I have done as well.

Thanks for this comment - I really did not think of this perspective earlier.

However, on second thought, I could say, that most of my do_something*() functions basically read some global vars, do some processing, and then update some other global variables. So, I’m at risk here that for instance I’m interrupting halfway through all supposedly output global variables, but since I’m restarting the processing anyways, this does not worry me all that much - FreeRTOS task restarting should not have an influence on the supposedly input global variables, so it should not be able to corrupt them - and it is the inputs that matter to my processing.

Then again, I do have a few I2C writes from core1 as well, and I wouldn’t want to delete a task while I2C hardware operation is running … so yeah, this kind of a restart that I desire requires some more thought.

I had a thought about this, but didn’t follow it through, because I thought it would defeat the purpose of what I want to achieve, which is timing synchronization of the processing running on core 1, to an interrupt signal registered on core 0 (this might fire each second, but might fire on the interval level of hours as well). Since I cannot check for a flag arbitrarily fast, I must check it e.g. when each of the do_something* functions exits, and these might take a random amount of milliseconds to complete. So if I do this, I can expect the “restart” to happen a random amount of milliseconds after the ISR has been registered, which will introduce processing jitter, which is what I want to avoid; so that is why I was looking for a way to restart processing ASAP… but yeah, its tricky, needs some more thought.

I think you need to figure our your actual requirements and see what needs to be done to meet them. The old adage is that “ASAP” really means, I will get to it when everything else with a REAL priority has been met.

You are already accepting the delay time of the calculations to get these operations done, is an additional delay of the time it take to realize there is a new update and abort the old too much, or is the additional delay for the last items to be updated by restarting too much?

Another question is, are the 3 things to be done really sequential, or if some require I/O to perform, should you kick off 3 tasks, one for each operation? That would allow each one to implement its own “restart” policy based on what it needs.

Another small point, since you are using SMP, the fact that it is “another core” is irrelevant, as FreeRTOS will handle the core-to-core operations. You get exactly the same issues in a single core application. Killing an active process just causes a lot of problems.

1 Like

FreeRTOS threads are quite similar to threads in Windows or Linux or other OSes. It is a software concept of multiple executions paths (thread functions) running in a shared memory space, but with one stack per thread.

Hey @sdbbs, wanted to see if you were still looking for help with this, or if the answers provided by @richard-damon answered your questions?

1 Like

Thanks @skptak :

wanted to see if you were still looking for help with this, or if the answers provided by @richard-damon answered your questions?

Not looking for help anymore; the answers definitely made me rethink my approach in my actual problem, and I managed to solve it without the kind of a stop/restart that I otherwise imagined in the OP of the thread. So I marked one answer as accepted. Thanks again!

Thank you for taking the time to report back!