clean up deleted task 's resouce in sho...

vicui wrote on Monday, August 19, 2013:

HI :
is there a way to clean up deleted task’s resource in short time by IDLE task and create new task at once ?

vincent

richard_damon wrote on Monday, August 19, 2013:

Generally, it doesn’t make sense for the task to be deleted and then recreated right away, so you may be doing something wrong.

The idle task will run as soon as there is no higher priority task ready to use time, so there are two ways to make this happen:
1)  Make sure that all tasks are pending on something or,
2) Temporarily raise the priority of the idle task, and have code in the idle hook put it back down (the idle hook may need to let the idle task run twice, as it might be pass the point of doing the cleanup when the first cycle runs.

vicui wrote on Monday, August 19, 2013:

in web application, i need to create new tasked to deal something , then return back to web application , if i don’t create new task to do this , web application seems to be halt .
dues to increase system heap size, i plan to merge some task in one task

While this is an old thread, the issue of deleted task TCB memory not getting freed keeps coming up because the idle task may not get a chance to run quickly enough. Of course, if it doesn’t run for a while (e.g. 5 seconds) then the watchdog timer will expire since the idle task feeds it, but one can create tasks more quickly and experience running out of memory faster so one sees that as the failure mode.

While ideally every task would be written using function calls that would have it go into a blocked state while waiting for an action, such as waiting for events in a queue or suspending itself waiting to be awakened (unblocked) from an interrupt or another task, if this isn’t done then the idle task can get starved.

Note that a taskYIELD is not sufficient as it will only allow tasks with equal or higher priority to run while the idle task usually has lowest (0) priority.

If one has a main dispatch loop from which the tasks are created or has a polling loop (servicing serial input, for example), then one can force the idle task to run by calling a function that suspends this looping task and awakens from the idle task callback, such as using xTaskNotifyWaitIndexed / xTaskNotifyIndexed. So one can call a function like the following tasknotify_run_idle_task and have the function for the idle hook:

void tasknotify_run_idle_task(void)
{
	waiting_for_idle = 1;  // will have idle_hook() notify main task when it is run

	// The following suspends the main task so that the idle task can run.
	// It waits for the idle task to finish running so releasing memory from any
	// deleted tasks and resetting the (idle) task watchdog timer.
	xTaskNotifyWaitIndexed(TASK_INDEX_IDLE_RUN, 0, 0, NULL, portMAX_DELAY);

	// waiting_for_idle is set to 0 in idle_hook() just prior to the notify
}

static uint8_t waiting_for_idle = 0;

// This function is called whenever the idle task has been run.  It's called after any task
// memory cleanup and after feeding the task watchdog timer.
void vApplicationIdleHook(void)
{
	if (waiting_for_idle) {
		waiting_for_idle = 0;  // we only want to notify once
		xTaskNotifyIndexed(mainTaskHandle, TASK_INDEX_IDLE_RUN, 0, eNoAction);
	}
}

Instead of xTaskNotifyWaitIndexed / xTaskNotifyIndexed, one can use vTaskSuspend(NULL) / vTaskResume(taskHandle) instead but needs to set the taskHandle (usually this is the main task).

The concept of deleting the task and then recreating it is in my opinion, a very foolish concept. If the task can delete itself, it can do what is needed to instead reinitialize itself. If some other task deletes it, then you run the risk that the task wasn’t in a “clean” state when it was deleted, and you may have corrupted the system.

Generally, task will be “immortal”, and when not needed, block until they are needed again. If you need to have them terminate when not being used, to allow changing mixes of tasks, then the tasks should end themselves, and your then MUST give the idle task time to run. IF things happen so fast that you need the memory before the idle task gets to run, you are likely running your system too close to the limits to be reliable.

The one other option I see is that you create a “reaper” task at moderate to high priority, and task notify. the reaper when they are done, and then “block forever” in a clean state, and the reaper deletes the task. Note, you only need to wait for the idle task on a self-delete, as that is the case that runs into the issue of the task resources need to be availiable to run the clean-up code, but then they can’t be freed, so the Idle task takes over the final freeing.

Note, your waiting for idle hook above has a race condition, as if idle has just check for releasing memory, and seeing nothing is needed, it get interrupted, and a task deleted and the notification requested, the waiting for idle will get tested BEFORE the memory free will be checked.

Note, if your “main dispatch loop” doesn’t naturally block to allow the idle task to run, it should be also at priority level 0, so yield will work to let the idle task run.

Probably different behavior since the time of the original thread: The idle task is only responsible for freeing the TCB and stack allocated to tasks that delete themselves. The memory is freed immediately when one task deletes another.