diff --git a/src/activities/dictionary/DictionaryMenuActivity.cpp b/src/activities/dictionary/DictionaryMenuActivity.cpp index 287a055..f783ef8 100644 --- a/src/activities/dictionary/DictionaryMenuActivity.cpp +++ b/src/activities/dictionary/DictionaryMenuActivity.cpp @@ -39,12 +39,14 @@ void DictionaryMenuActivity::onEnter() { void DictionaryMenuActivity::onExit() { Activity::onExit(); - // Wait until not rendering to delete task + // Take mutex to ensure task isn't in render() xSemaphoreTake(renderingMutex, portMAX_DELAY); if (displayTaskHandle) { + // Task is definitely not in render() because we hold the mutex. + // Delete the task - it will never run again. vTaskDelete(displayTaskHandle); displayTaskHandle = nullptr; - vTaskDelay(10 / portTICK_PERIOD_MS); // Let idle task free stack + vTaskDelay(10 / portTICK_PERIOD_MS); // Let idle task free the task's stack } vSemaphoreDelete(renderingMutex); renderingMutex = nullptr; @@ -56,7 +58,10 @@ void DictionaryMenuActivity::loop() { // Handle back button - cancel // Use wasReleased to consume the full button event if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { - onCancel(); + // Copy callback before invoking - the callback may destroy this object + // (and thus the original std::function) while still executing + auto callback = onCancel; + callback(); return; } @@ -64,7 +69,9 @@ void DictionaryMenuActivity::loop() { // Use wasReleased to consume the full button event if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { const DictionaryMode mode = (selectedIndex == 0) ? DictionaryMode::SELECT_FROM_SCREEN : DictionaryMode::ENTER_WORD; - onModeSelected(mode); + // Copy callback before invoking - the callback may destroy this object + auto callback = onModeSelected; + callback(mode); return; }