fix: properly implement requestUpdateAndWait() (#1218)

## Summary

Properly implement `requestUpdateAndWait()` using freeRTOS direct task
notification.

FWIW, I think most of the current use cases of `requestUpdateAndWait()`
are redundant, better to be replaced by `requestUpdate(true)`. But just
keeping them in case we can find a proper use case for it in the future.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? **YES**, it's trivial, so
I asked an AI to write the code

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Xuan-Son Nguyen
2026-03-01 02:12:57 +01:00
committed by GitHub
parent 3da2cd3cf8
commit a57c62f0b4
4 changed files with 49 additions and 6 deletions

View File

@@ -38,6 +38,15 @@ void ActivityManager::renderTaskLoop() {
HalPowerManager::Lock powerLock; // Ensure we don't go into low-power mode while rendering
currentActivity->render(std::move(lock));
}
// Notify any task blocked in requestUpdateAndWait() that the render is done.
TaskHandle_t waiter = nullptr;
taskENTER_CRITICAL(nullptr);
waiter = waitingTaskHandle;
waitingTaskHandle = nullptr;
taskEXIT_CRITICAL(nullptr);
if (waiter) {
xTaskNotify(waiter, 1, eIncrement);
}
}
}
@@ -225,6 +234,36 @@ void ActivityManager::requestUpdate(bool immediate) {
requestedUpdate = true;
}
}
void ActivityManager::requestUpdateAndWait() {
if (!renderTaskHandle) {
return;
}
// Atomic section to perform checks
taskENTER_CRITICAL(nullptr);
auto currTaskHandler = xTaskGetCurrentTaskHandle();
auto mutexHolder = xSemaphoreGetMutexHolder(renderingMutex);
bool isRenderTask = (currTaskHandler == renderTaskHandle);
bool alreadyWaiting = (waitingTaskHandle != nullptr);
bool holdingRenderLock = (mutexHolder == currTaskHandler);
if (!alreadyWaiting && !isRenderTask && !holdingRenderLock) {
waitingTaskHandle = currTaskHandler;
}
taskEXIT_CRITICAL(nullptr);
// Render task cannot call requestUpdateAndWait() or it will cause a deadlock
assert(!isRenderTask && "Render task cannot call requestUpdateAndWait()");
// There should never be the case where 2 tasks are waiting for a render at the same time
assert(!alreadyWaiting && "Already waiting for a render to complete");
// Cannot call while holding RenderLock or it will cause a deadlock
assert(!holdingRenderLock && "Cannot call requestUpdateAndWait() while holding RenderLock");
xTaskNotify(renderTaskHandle, 1, eIncrement);
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
// RenderLock
RenderLock::RenderLock() {