Semaphore for ISR-to-task signaling in FreeRTOS - Time & Space Complexity
When using a semaphore to signal from an interrupt to a task in FreeRTOS, it is important to understand how the time taken grows as the system runs.
We want to know how the number of operations changes as more signals happen.
Analyze the time complexity of the following code snippet.
void ISR_Handler(void) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void Task(void *pvParameters) {
for(;;) {
if(xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
// Process event
}
}
}
This code shows an interrupt giving a semaphore to unblock a task waiting on it.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The task repeatedly waits on the semaphore in a loop.
- How many times: The loop runs indefinitely, waiting for each semaphore signal from the ISR.
Each time the ISR signals, the task wakes and processes one event. The number of operations grows directly with the number of signals.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 semaphore takes and event processes |
| 100 | 100 semaphore takes and event processes |
| 1000 | 1000 semaphore takes and event processes |
Pattern observation: The work grows linearly with the number of ISR signals.
Time Complexity: O(n)
This means the total work grows in direct proportion to how many times the ISR signals the semaphore.
[X] Wrong: "The semaphore take inside the task loop runs in constant time regardless of how many signals happen."
[OK] Correct: Each semaphore take corresponds to one signal, so more signals mean more takes and more processing, increasing total operations.
Understanding how signaling between interrupts and tasks scales helps you design responsive and efficient real-time systems.
"What if the task processed multiple events per semaphore take? How would the time complexity change?"
Practice
Solution
Step 1: Understand semaphore role in FreeRTOS
Semaphores are synchronization tools used to signal between tasks or between ISRs and tasks.Step 2: Identify ISR-to-task signaling purpose
In FreeRTOS, semaphores let an ISR notify a task safely without blocking or complex synchronization.Final Answer:
To safely notify a task from an interrupt service routine (ISR) -> Option CQuick Check:
Semaphore signals task from ISR = A [OK]
- Thinking semaphores create tasks
- Confusing semaphores with disabling interrupts
- Using semaphores for memory allocation
Solution
Step 1: Recall ISR-safe semaphore functions
FreeRTOS provides special functions for ISR context to avoid blocking and ensure safety.Step 2: Identify the correct ISR semaphore give function
The function to give a semaphore from an ISR isxSemaphoreGiveFromISR().Final Answer:
xSemaphoreGiveFromISR() -> Option AQuick Check:
Give semaphore from ISR = xSemaphoreGiveFromISR() [OK]
- Using xSemaphoreGive() inside ISR (not safe)
- Confusing take and give functions
- Assuming xSemaphoreCreateFromISR() exists
SemaphoreHandle_t xSemaphore;
void ISR_Handler() {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
}
void TaskFunction(void *pvParameters) {
if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
printf("Semaphore received\n");
}
}Solution
Step 1: Analyze ISR giving semaphore
The ISR callsxSemaphoreGiveFromISR()which releases the semaphore.Step 2: Analyze task waiting on semaphore
The task waits indefinitely withxSemaphoreTake()and prints "Semaphore received" when it gets the semaphore.Final Answer:
Semaphore received -> Option DQuick Check:
Task prints after semaphore take = C [OK]
- Thinking semaphore is given twice
- Assuming no output if ISR runs
- Expecting runtime error without initialization
void ISR_Handler() {
xSemaphoreGive(xSemaphore);
}Solution
Step 1: Check function suitability for ISR
xSemaphoreGive()is not safe to call inside an ISR because it may block or cause race conditions.Step 2: Identify correct ISR function
UsexSemaphoreGiveFromISR()inside ISRs to safely give semaphores.Final Answer:
xSemaphoreGive() cannot be called from an ISR -> Option AQuick Check:
Use xSemaphoreGiveFromISR() in ISR, not xSemaphoreGive() [OK]
- Calling xSemaphoreGive() inside ISR
- Ignoring ISR context restrictions
- Assuming semaphore must be taken before giving
Solution
Step 1: Identify correct semaphore type and usage
Binary semaphore is suitable for signaling events from ISR to task.Step 2: Confirm correct function calls and order
ISR must callxSemaphoreGiveFromISR()to signal; task waits withxSemaphoreTake()blocking indefinitely (portMAX_DELAY) until signaled.Final Answer:
Create binary semaphore; ISR calls xSemaphoreGiveFromISR(); task calls xSemaphoreTake() with portMAX_DELAY -> Option BQuick Check:
Binary semaphore + ISR give + task take = A [OK]
- Using mutex instead of semaphore
- Calling give in task and take in ISR
- Using zero timeout causing missed signals
Ready to prove it?
Pass the test and this pattern moves unknown
