From 8dc826527563c67d5f677cafe524eff434889d1d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 29 Jun 2022 11:53:10 -0700 Subject: [PATCH] Fix auto-wifi created crash The wifi event_handler runs on the other core so we need to be careful when calling into CP APIs. Fixes #6503 --- .../common-hal/microcontroller/__init__.c | 6 ++--- ports/espressif/common-hal/wifi/__init__.c | 22 ++++++++++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/ports/espressif/common-hal/microcontroller/__init__.c b/ports/espressif/common-hal/microcontroller/__init__.c index 3cf41ba7f0..81a512bdd6 100644 --- a/ports/espressif/common-hal/microcontroller/__init__.c +++ b/ports/espressif/common-hal/microcontroller/__init__.c @@ -65,6 +65,7 @@ volatile uint32_t nesting_count = 0; static portMUX_TYPE cp_mutex = portMUX_INITIALIZER_UNLOCKED; void common_hal_mcu_disable_interrupts(void) { + assert(xPortGetCoreID() == CONFIG_ESP_MAIN_TASK_AFFINITY); if (nesting_count == 0) { portENTER_CRITICAL(&cp_mutex); } @@ -72,9 +73,8 @@ void common_hal_mcu_disable_interrupts(void) { } void common_hal_mcu_enable_interrupts(void) { - if (nesting_count == 0) { - // Maybe log here because it's very bad. - } + assert(xPortGetCoreID() == CONFIG_ESP_MAIN_TASK_AFFINITY); + assert(nesting_count > 0); nesting_count--; if (nesting_count > 0) { return; diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index 3da0fc7297..80d01a253e 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -42,12 +42,25 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include "components/log/include/esp_log.h" +#include "supervisor/port.h" #include "supervisor/workflow.h" +#include "esp_ipc.h" + static const char *TAG = "wifi"; +STATIC void schedule_background_on_cp_core(void *arg) { + supervisor_workflow_request_background(); + + // CircuitPython's VM is run in a separate FreeRTOS task from wifi callbacks. So, we have to + // notify the main task every time in case it's waiting for us. + port_wake_main_task(); +} + static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) { + // This runs on the PRO CORE! It cannot share CP interrupt enable/disable + // directly. wifi_radio_obj_t *radio = arg; if (event_base == WIFI_EVENT) { switch (event_id) { @@ -108,7 +121,14 @@ static void event_handler(void *arg, esp_event_base_t event_base, radio->retries_left = radio->starting_retries; xEventGroupSetBits(radio->event_group_handle, WIFI_CONNECTED_BIT); } - supervisor_workflow_request_background(); + // Use IPC to ensure we run schedule background on the same core as CircuitPython. + #if defined(CONFIG_FREERTOS_UNICORE) && CONFIG_FREERTOS_UNICORE + schedule_background_on_cp_core(NULL); + #else + // This only blocks until the start of the function. That's ok since the PRO + // core shouldn't care what we do. + esp_ipc_call(CONFIG_ESP_MAIN_TASK_AFFINITY, schedule_background_on_cp_core, NULL); + #endif } static bool wifi_inited;