fix(displayidle): avoid LVGL->MCP lock inversion that could freeze RLCD
Read MCP override state outside LVGL lock in tick(). Previously: LVGL lock -> MCP mutex (tick) vs MCP mutex -> LVGL lock (video task startMcpScreensaver) = deadlock risk observed on RLCD when text tool called. Now: MCP state read first, then LVGL lock. Preserves <1s flash guard (isMcpActive). Board: waveshare-esp32-s3-rlcd 0x2b78b0 32%% free, flashed to /dev/cu.usbmodem101 Co-Authored-By: internal-model
This commit is contained in:
@@ -147,6 +147,16 @@ void DisplayIdleService::updateScreensaver() {
|
||||
}
|
||||
|
||||
void DisplayIdleService::tick() {
|
||||
// Check if MCP override is active — must not be auto-stopped by idle logic
|
||||
// READ OUTSIDE LVGL lock to avoid lock inversion:
|
||||
// MCP video task locks mutex -> LVGL, we must NOT do LVGL -> mutex
|
||||
bool isMcpActive = false;
|
||||
{
|
||||
auto& st = mcp::getState();
|
||||
std::lock_guard<std::mutex> lk(st.mutex);
|
||||
isMcpActive = (st.drawArea != nullptr) || st.overrideActive;
|
||||
}
|
||||
|
||||
if (!lvgl::lock(100)) {
|
||||
return;
|
||||
}
|
||||
@@ -163,14 +173,6 @@ void DisplayIdleService::tick() {
|
||||
uint32_t inactive_ms = 0;
|
||||
inactive_ms = lv_display_get_inactive_time(nullptr);
|
||||
|
||||
// Check if MCP override is active — it must not be auto-stopped by idle logic
|
||||
bool isMcpActive = false;
|
||||
{
|
||||
auto& st = mcp::getState();
|
||||
std::lock_guard<std::mutex> lk(st.mutex);
|
||||
isMcpActive = (st.drawArea != nullptr) || st.overrideActive;
|
||||
}
|
||||
|
||||
// Only update if not stopping (prevents lag on touch) — skip for MCP (no animation)
|
||||
if (displayDimmed && screensaverOverlay && !stopScreensaverRequested.load(std::memory_order_acquire) && !isMcpActive) {
|
||||
// Check if screensaver should auto-off after 5 minutes
|
||||
|
||||
Reference in New Issue
Block a user