Deferred interrupt processing pattern in FreeRTOS - Time & Space Complexity
When using deferred interrupt processing in FreeRTOS, we want to understand how the time to handle tasks grows as more interrupts occur.
We ask: How does the processing time change when more events need deferred handling?
Analyze the time complexity of the following code snippet.
void ISR_Handler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(xQueue, &data, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void DeferredTask(void *pvParameters) {
DataType data;
while(1) {
if(xQueueReceive(xQueue, &data, portMAX_DELAY) == pdPASS) {
ProcessData(data);
}
}
}
This code defers work from an interrupt to a task by sending data to a queue inside the ISR and processing it later in a task.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The task repeatedly waits and receives data from the queue in a loop.
- How many times: Once for each item sent by the ISR, which depends on interrupt frequency.
As more interrupts occur, more items are sent to the queue, so the task processes more data items one by one.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 queue receives and process calls |
| 100 | 100 queue receives and process calls |
| 1000 | 1000 queue receives and process calls |
Pattern observation: The total work grows directly with the number of deferred items to process.
Time Complexity: O(n)
This means the time to process deferred interrupts grows linearly with the number of interrupts that need handling.
[X] Wrong: "The ISR processing time dominates and the deferred task time is constant regardless of input."
[OK] Correct: The ISR only queues data quickly, but the deferred task does the real work for each item, so its time grows with the number of items.
Understanding deferred interrupt processing time helps you design responsive systems and shows you can reason about how tasks scale with workload.
"What if the deferred task processed multiple items in a batch instead of one by one? How would the time complexity change?"
Practice
Solution
Step 1: Understand ISR limitations
Interrupt Service Routines (ISRs) should be short to keep system responsive.Step 2: Role of deferred processing
Heavy or time-consuming work is moved to a task, triggered by ISR using semaphores or queues.Final Answer:
To move heavy processing from the ISR to a task for better system responsiveness -> Option AQuick Check:
Deferred processing = move work out of ISR [OK]
- Thinking all work should be done inside ISR
- Believing interrupts should be disabled during tasks
- Ignoring use of semaphores or queues
Solution
Step 1: Identify ISR-safe functions
Functions called from ISRs must be ISR-safe variants, like xSemaphoreGiveFromISR().Step 2: Compare options
xSemaphoreGive() is for tasks, not ISRs; vTaskDelay() is a task delay; xQueueSend() is not ISR-safe.Final Answer:
xSemaphoreGiveFromISR() -> Option CQuick Check:
Use FromISR functions inside ISRs [OK]
- Using task-only functions inside ISR
- Calling blocking functions in ISR
- Not using FromISR variants
BaseType_t xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken);What is the purpose of
portYIELD_FROM_ISR() here?Solution
Step 1: Understand xHigherPriorityTaskWoken
This flag indicates if giving the semaphore woke a higher priority task.Step 2: Role of portYIELD_FROM_ISR()
If the flag is true, portYIELD_FROM_ISR() requests a context switch to run the higher priority task immediately.Final Answer:
To request a context switch if a higher priority task was woken -> Option BQuick Check:
portYIELD_FROM_ISR triggers context switch [OK]
- Thinking it disables interrupts
- Assuming it delays ISR execution
- Confusing it with semaphore reset
void ISR_Handler(void) {
xSemaphoreGive(xSemaphore);
}
Why might this cause problems in FreeRTOS?Solution
Step 1: Check function usage in ISR
xSemaphoreGive() is a task-level function and is not safe to call inside an ISR.Step 2: Correct function to use
Inside ISR, xSemaphoreGiveFromISR() must be used to safely notify the task.Final Answer:
xSemaphoreGive() is not safe to call from an ISR -> Option AQuick Check:
Use FromISR functions in ISRs [OK]
- Calling task functions inside ISR
- Forgetting to clear interrupt flags
- Assuming semaphore gives always unblock tasks
Solution
Step 1: ISR role in deferred processing
ISR should be short and only notify the task using xSemaphoreGiveFromISR().Step 2: Task role in processing
The task waits on the semaphore and processes sensor data when notified.Final Answer:
ISR calls xSemaphoreGiveFromISR(), then task waits on semaphore and processes data -> Option DQuick Check:
ISR signals, task processes data [OK]
- Doing heavy work inside ISR
- Using blocking calls inside ISR
- Not synchronizing task and ISR properly
Ready to prove it?
Pass the test and this pattern moves unknown
