My application has two tasks:
Task A - Listens to new user requests
Task B - Implements current user request
If Task A detects new user request, ongoing Task B is deleted, and new Task B is created with updated request.
Task B is pretty complex( uses Wifi, I2S, SD card…) and incorporates a lot of features such as:
- Memory allocation/deallocation
- Opening/closing files
- Enabling/disabling peripherals
So, when Task A detects new request and kills Task B, I need to free its heap memory and bring the application back to the valid state. For example, if task B has enabled microphone, I need to disable it back.
What I initially planned to do is following:
Have an external struct which will hold all the required data to free the resources, for example:
struct Task_Resources {
bool USB_is_enabled;
bool file_is_opened;
FILE* file_name;
...
}
and a function to clean the resources:
void task_cleaner(Task_Resources* res) {
if(res->USB_is_enabled) {
disable_USB();
}
if(res->file_is_opened) {
close(file_name);
remove(file_name);
}
...
}
Once vTaskDelete(Task_B_handle) would be called, task_cleaner() function will free the memory and bring the application back to valid state.
The problem is that there are too many things to keep track of. And I will also have to suspend Task A a lot of times to get atomic behavior. For example:
Task B code {
...
ENABLE_USB();
TASK_RESOURCES.USB_is_enabled = true;
...
}
If TASK A kills the task between these two lines, peripheral will be enabled, but task_cleaner() won’t know about it. So, I will probably have to do something like that to prevent task deletion in between those lines:
Task B code {
...
xTaskSuspend(TASK_A);
TASK B - ENABLE_USB();
TASK B - TASK_RESOURCES.USB_is_enabled = true;
xTaskResume(TASK_A);
...
}
I was wondering your opinion on this approach. And if someone had similar situation, I would appreciate if you can tell me how did you solve it.