bryce78 wrote on Friday, September 22, 2017:
Hello Community,
I have a “what happens if…” type question related to using the Idle Task Hook (configUSE_IDLE_HOOK is set to 1 in FreeRTOSConfig.h).
Background: The Idle Task runs at the lowest priority (tskIDLE_PRIORITY) and therefore only runs when there is no higher priority task(s) to run. Furthermore the hook, vApplicationIdleHook(), is called from the Idle Task so it, too, runs at the lowest priority. This means vApplicationIdleHook() can be preempted if a higher priority task becomes scheduled to run (becomes in the Ready state) during execution of vApplicationIdleHook().
Scenario: In my FreeRTOS v9.0.0 project I use vApplicationIdleHook() for periodic (say, once per minute) low prioirty application “maintenance” – say updating some runtime statistics/counters. Once vApplicationIdleHook() returns the application typically enters low-power tickless idle mode (portSUPPRESS_TICKS_AND_SLEEP()) shortly thereafter. However, during vApplicationIdleHook() an interrupt could occur, ultimately making a high priority task state become Ready.
What happens if that interrupt were to occur? My understanding is that when the interrupt handler returns execution will jump immediately to the high priority task instead of returning to vApplicationIdleHook(). Let’s suppose the high priority task keeps busy for a long time… After a while the high priority task has nothing to do and becomes Blocked, and (I expect) vApplicationIdleHook() resumes from whereever it was at the time of the original interrupt…and as in the typical case, enters low-power tickless idle mode.
Is my understanding correct?
I am concerned of vApplicationIdleHook() being interrupted (as above) if it has something critical to do and which is expected to complete, like write application data to non-volatile FLASH memory (which would be bad if interrupted).
What is the right way to ensure code executing at even lowest prioity (like vApplicationIdleTask()) will complete without context switch until the critical code has finished?
Is the solution just to wrap the critical bit of vApplicationIdleHook() around taskENTER_CRITICAL() and taskEXIT_CRITICAL()?
Lastly, its mentioned here that vApplicationIdleHook() mustn’t call any API function that can block. Presumably this includes xSemaphoreTake(…, (TickType_t) portMAX_DELAY) and xQueueSendToBack(…, …, ( TickType_t ) portMAX_DELAY). So, how does one add to task queues (if occasionally needed) without these blocking API calls? Is it better (or best) practice to avoid inserting anything to task queues from vApplicationIdleHook()? (After all, the application is supposed to be idle?!)
Thanks for reading this far – hope I explained clearly
Best,
Bryce