From f2f9170abc190e75e5407a342000674dc6118210 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 28 Sep 2017 10:58:32 +1000 Subject: [PATCH 1/3] freertos: Fix bug with xTaskResumeAll() not resuming all tasks Previously if multiple tasks had been added to xPendingReadyList for the CPU, only the first one was resumed. Includes a test case for resuming multiple (pending) tasks on xTaskResumeAll(). Document the limitation that while scheduler is suspended on one CPU, it can't wake tasks on either CPU. --- components/freertos/tasks.c | 1 - .../freertos/test/test_suspend_scheduler.c | 111 +++++- docs/api-guides/freertos-smp.rst | 10 +- tools/unit-test-app/sdkconfig | 332 ++++++++++-------- 4 files changed, 294 insertions(+), 160 deletions(-) diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 15d2e135d3..15d588662c 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -2177,7 +2177,6 @@ BaseType_t xAlreadyYielded = pdFALSE; { /* We can schedule the awoken task on this CPU. */ xYieldPending[xPortGetCoreID()] = pdTRUE; - break; } else { diff --git a/components/freertos/test/test_suspend_scheduler.c b/components/freertos/test/test_suspend_scheduler.c index d3c8ed86a2..c96eabbc8c 100644 --- a/components/freertos/test/test_suspend_scheduler.c +++ b/components/freertos/test/test_suspend_scheduler.c @@ -12,7 +12,7 @@ #include "driver/timer.h" static SemaphoreHandle_t isr_semaphore; -static volatile unsigned isr_count, task_count; +static volatile unsigned isr_count; /* Timer ISR increments an ISR counter, and signals a mutex semaphore to wake up another counter task */ @@ -29,12 +29,18 @@ static void timer_group0_isr(void *vp_arg) } } -static void counter_task_fn(void *ignore) +typedef struct { + SemaphoreHandle_t trigger_sem; + volatile unsigned counter; +} counter_config_t; + +static void counter_task_fn(void *vp_config) { + counter_config_t *config = (counter_config_t *)vp_config; printf("counter_task running...\n"); while(1) { - xSemaphoreTake(isr_semaphore, portMAX_DELAY); - task_count++; + xSemaphoreTake(config->trigger_sem, portMAX_DELAY); + config->counter++; } } @@ -45,18 +51,21 @@ static void counter_task_fn(void *ignore) */ TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]") { - task_count = 0; isr_count = 0; isr_semaphore = xSemaphoreCreateMutex(); TaskHandle_t counter_task; intr_handle_t isr_handle = NULL; + counter_config_t count_config = { + .trigger_sem = isr_semaphore, + .counter = 0, + }; xTaskCreatePinnedToCore(counter_task_fn, "counter", 2048, - NULL, UNITY_FREERTOS_PRIORITY + 1, + &count_config, UNITY_FREERTOS_PRIORITY + 1, &counter_task, UNITY_FREERTOS_CPU); /* Configure timer ISR */ - const timer_config_t config = { + const timer_config_t timer_config = { .alarm_en = 1, .auto_reload = 1, .counter_dir = TIMER_COUNT_UP, @@ -65,7 +74,7 @@ TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]" .counter_en = TIMER_PAUSE, }; /* Configure timer */ - timer_init(TIMER_GROUP_0, TIMER_0, &config); + timer_init(TIMER_GROUP_0, TIMER_0, &timer_config); timer_pause(TIMER_GROUP_0, TIMER_0); timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0); timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1000); @@ -76,20 +85,20 @@ TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]" vTaskDelay(5); // Check some counts have been triggered via the ISR - TEST_ASSERT(task_count > 10); + TEST_ASSERT(count_config.counter > 10); TEST_ASSERT(isr_count > 10); for (int i = 0; i < 20; i++) { vTaskSuspendAll(); esp_intr_noniram_disable(); - unsigned no_sched_task = task_count; + unsigned no_sched_task = count_config.counter; // scheduler off on this CPU... ets_delay_us(20 * 1000); //TEST_ASSERT_NOT_EQUAL(no_sched_isr, isr_count); - TEST_ASSERT_EQUAL(task_count, no_sched_task); + TEST_ASSERT_EQUAL(count_config.counter, no_sched_task); // disable timer interrupts timer_disable_intr(TIMER_GROUP_0, TIMER_0); @@ -99,7 +108,7 @@ TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]" esp_intr_noniram_enable(); xTaskResumeAll(); - TEST_ASSERT_NOT_EQUAL(task_count, no_sched_task); + TEST_ASSERT_NOT_EQUAL(count_config.counter, no_sched_task); } esp_intr_free(isr_handle); @@ -108,3 +117,81 @@ TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]" vTaskDelete(counter_task); vSemaphoreDelete(isr_semaphore); } + +/* Multiple tasks on different cores can be added to the pending ready list + while scheduler is suspended, and should be started once the scheduler + resumes. +*/ +TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]") +{ + #define TASKS_PER_PROC 4 + TaskHandle_t tasks[portNUM_PROCESSORS][TASKS_PER_PROC] = { 0 }; + counter_config_t counters[portNUM_PROCESSORS][TASKS_PER_PROC] = { 0 }; + + /* Start all the tasks, they will block on isr_semaphore */ + for (int p = 0; p < portNUM_PROCESSORS; p++) { + for (int t = 0; t < TASKS_PER_PROC; t++) { + counters[p][t].trigger_sem = xSemaphoreCreateMutex(); + TEST_ASSERT_NOT_NULL( counters[p][t].trigger_sem ); + TEST_ASSERT( xSemaphoreTake(counters[p][t].trigger_sem, 0) ); + xTaskCreatePinnedToCore(counter_task_fn, "counter", 2048, + &counters[p][t], UNITY_FREERTOS_PRIORITY + 1, + &tasks[p][t], p); + TEST_ASSERT_NOT_NULL( tasks[p][t] ); + } + } + + /* takes a while to initialize tasks on both cores, sometimes... */ + vTaskDelay(TASKS_PER_PROC * portNUM_PROCESSORS * 3); + + /* Check nothing is counting, each counter should be blocked on its trigger_sem */ + for (int p = 0; p < portNUM_PROCESSORS; p++) { + for (int t = 0; t < TASKS_PER_PROC; t++) { + TEST_ASSERT_EQUAL(0, counters[p][t].counter); + } + } + + /* Suspend scheduler on this CPU */ + vTaskSuspendAll(); + + /* Give all the semaphores once. You might expect this will wake up tasks on the other + CPU (where the scheduler is not suspended) but it doesn't do this in the current implementation + - all tasks are added to xPendingReadyList and woken up later. See note in the freertos-smp docs. + */ + for (int p = 0; p < portNUM_PROCESSORS; p++) { + for (int t = 0; t < TASKS_PER_PROC; t++) { + xSemaphoreGive(counters[p][t].trigger_sem); + } + } + + ets_delay_us(2 * 1000); /* Can't vTaskDelay() while scheduler is suspended, but let other CPU do some things */ + + for (int p = 0; p < portNUM_PROCESSORS; p++) { + for (int t = 0; t < TASKS_PER_PROC; t++) { + /* You might expect that this is '1' for the other CPU, but it's not (see comment above) */ + ets_printf("Checking CPU %d task %d (expected 0 actual %d)\n", p, t, counters[p][t].counter); + TEST_ASSERT_EQUAL(0, counters[p][t].counter); + } + } + + /* Resume scheduler */ + xTaskResumeAll(); + + vTaskDelay(TASKS_PER_PROC * 2); + + /* Now the tasks on both CPUs should have been woken once and counted once. */ + for (int p = 0; p < portNUM_PROCESSORS; p++) { + for (int t = 0; t < TASKS_PER_PROC; t++) { + ets_printf("Checking CPU %d task %d (expected 1 actual %d)\n", p, t, counters[p][t].counter); + TEST_ASSERT_EQUAL(1, counters[p][t].counter); + } + } + + /* Clean up */ + for (int p = 0; p < portNUM_PROCESSORS; p++) { + for (int t = 0; t < TASKS_PER_PROC; t++) { + vTaskDelete(tasks[p][t]); + vSemaphoreDelete(counters[p][t].trigger_sem); + } + } +} diff --git a/docs/api-guides/freertos-smp.rst b/docs/api-guides/freertos-smp.rst index 7ccba1b10a..f135c017a6 100644 --- a/docs/api-guides/freertos-smp.rst +++ b/docs/api-guides/freertos-smp.rst @@ -227,6 +227,14 @@ protection against simultaneous access. Consider using critical sections (disables interrupts) or semaphores (does not disable interrupts) instead when protecting shared resources in ESP-IDF FreeRTOS. +If the task running on the CPU with scheduler suspended calls a function (like +``xSemaphoreGive``, ``xQueueSend``) that wakes another task, this task will not run +until after ``vTaskResumeAll()`` is called. This is true even if the woken task is +on the other CPU (where the scheduler is still running). + +In general, it's better to use other RTOS primitives like mutex semaphores to protect +against data shared between tasks, rather than ``vTaskSuspendAll()``. + .. _tick-interrupt-synchronicity: Tick Interrupt Synchronicity @@ -366,4 +374,4 @@ functionality of ``xTaskCreateStaticPinnedToCore()`` in ESP-IDF FreeRTOS :ref:`CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION` will trigger a halt in particular functions in ESP-IDF FreeRTOS which have not been fully tested in an SMP context. - \ No newline at end of file + diff --git a/tools/unit-test-app/sdkconfig b/tools/unit-test-app/sdkconfig index b11a35cef7..fcd25585e1 100644 --- a/tools/unit-test-app/sdkconfig +++ b/tools/unit-test-app/sdkconfig @@ -8,74 +8,75 @@ # CONFIG_TOOLPREFIX="xtensa-esp32-elf-" CONFIG_PYTHON="python" +CONFIG_MAKE_WARN_UNDEFINED_VARIABLES=y # # Bootloader config # -# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set +CONFIG_LOG_BOOTLOADER_LEVEL_NONE= +CONFIG_LOG_BOOTLOADER_LEVEL_ERROR= CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y -# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set -# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set +CONFIG_LOG_BOOTLOADER_LEVEL_INFO= +CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG= +CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE= CONFIG_LOG_BOOTLOADER_LEVEL=2 # # Security features # -# CONFIG_SECURE_BOOT_ENABLED is not set -# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +CONFIG_SECURE_BOOT_ENABLED= +CONFIG_FLASH_ENCRYPTION_ENABLED= # # Serial flasher config # CONFIG_ESPTOOLPY_PORT="/dev/ttyUSB0" -# CONFIG_ESPTOOLPY_BAUD_115200B is not set -# CONFIG_ESPTOOLPY_BAUD_230400B is not set +CONFIG_ESPTOOLPY_BAUD_115200B= +CONFIG_ESPTOOLPY_BAUD_230400B= CONFIG_ESPTOOLPY_BAUD_921600B=y -# CONFIG_ESPTOOLPY_BAUD_2MB is not set -# CONFIG_ESPTOOLPY_BAUD_OTHER is not set +CONFIG_ESPTOOLPY_BAUD_2MB= +CONFIG_ESPTOOLPY_BAUD_OTHER= CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 CONFIG_ESPTOOLPY_BAUD=921600 CONFIG_ESPTOOLPY_COMPRESSED=y -# CONFIG_FLASHMODE_QIO is not set -# CONFIG_FLASHMODE_QOUT is not set +CONFIG_FLASHMODE_QIO= +CONFIG_FLASHMODE_QOUT= CONFIG_FLASHMODE_DIO=y -# CONFIG_FLASHMODE_DOUT is not set +CONFIG_FLASHMODE_DOUT= CONFIG_ESPTOOLPY_FLASHMODE="dio" -# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_80M= CONFIG_ESPTOOLPY_FLASHFREQ_40M=y -# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set -# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set +CONFIG_ESPTOOLPY_FLASHFREQ_26M= +CONFIG_ESPTOOLPY_FLASHFREQ_20M= CONFIG_ESPTOOLPY_FLASHFREQ="40m" -# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_1MB= +CONFIG_ESPTOOLPY_FLASHSIZE_2MB= CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y -# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set -# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set +CONFIG_ESPTOOLPY_FLASHSIZE_8MB= +CONFIG_ESPTOOLPY_FLASHSIZE_16MB= CONFIG_ESPTOOLPY_FLASHSIZE="4MB" CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y CONFIG_ESPTOOLPY_BEFORE_RESET=y -# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set +CONFIG_ESPTOOLPY_BEFORE_NORESET= CONFIG_ESPTOOLPY_BEFORE="default_reset" CONFIG_ESPTOOLPY_AFTER_RESET=y -# CONFIG_ESPTOOLPY_AFTER_NORESET is not set +CONFIG_ESPTOOLPY_AFTER_NORESET= CONFIG_ESPTOOLPY_AFTER="hard_reset" -# CONFIG_MONITOR_BAUD_9600B is not set -# CONFIG_MONITOR_BAUD_57600B is not set +CONFIG_MONITOR_BAUD_9600B= +CONFIG_MONITOR_BAUD_57600B= CONFIG_MONITOR_BAUD_115200B=y -# CONFIG_MONITOR_BAUD_230400B is not set -# CONFIG_MONITOR_BAUD_921600B is not set -# CONFIG_MONITOR_BAUD_2MB is not set -# CONFIG_MONITOR_BAUD_OTHER is not set +CONFIG_MONITOR_BAUD_230400B= +CONFIG_MONITOR_BAUD_921600B= +CONFIG_MONITOR_BAUD_2MB= +CONFIG_MONITOR_BAUD_OTHER= CONFIG_MONITOR_BAUD_OTHER_VAL=115200 CONFIG_MONITOR_BAUD=115200 # # Partition Table # -# CONFIG_PARTITION_TABLE_SINGLE_APP is not set -# CONFIG_PARTITION_TABLE_TWO_OTA is not set +CONFIG_PARTITION_TABLE_SINGLE_APP= +CONFIG_PARTITION_TABLE_TWO_OTA= CONFIG_PARTITION_TABLE_CUSTOM=y CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partition_table_unit_test_app.csv" CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 @@ -86,10 +87,10 @@ CONFIG_APP_OFFSET=0x10000 # Compiler options # CONFIG_OPTIMIZATION_LEVEL_DEBUG=y -# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set +CONFIG_OPTIMIZATION_LEVEL_RELEASE= CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y -# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set -# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set +CONFIG_OPTIMIZATION_ASSERTIONS_SILENT= +CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED= # # Component config @@ -98,36 +99,36 @@ CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y # # Application Level Tracing # -# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set +CONFIG_ESP32_APPTRACE_DEST_TRAX= CONFIG_ESP32_APPTRACE_DEST_NONE=y -# CONFIG_ESP32_APPTRACE_ENABLE is not set +CONFIG_ESP32_APPTRACE_ENABLE= CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y # # FreeRTOS SystemView Tracing # -# CONFIG_AWS_IOT_SDK is not set -# CONFIG_BT_ENABLED is not set +CONFIG_AWS_IOT_SDK= +CONFIG_BT_ENABLED= CONFIG_BT_RESERVE_DRAM=0 # # ESP32-specific # -# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set -# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set +CONFIG_ESP32_DEFAULT_CPU_FREQ_80= +CONFIG_ESP32_DEFAULT_CPU_FREQ_160= CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 CONFIG_MEMMAP_SMP=y -# CONFIG_SPIRAM_SUPPORT is not set -# CONFIG_MEMMAP_TRACEMEM is not set -# CONFIG_MEMMAP_TRACEMEM_TWOBANKS is not set -# CONFIG_ESP32_TRAX is not set +CONFIG_SPIRAM_SUPPORT= +CONFIG_MEMMAP_TRACEMEM= +CONFIG_MEMMAP_TRACEMEM_TWOBANKS= +CONFIG_ESP32_TRAX= CONFIG_TRACEMEM_RESERVE_DRAM=0x0 -# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set -# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set +CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH= +CONFIG_ESP32_ENABLE_COREDUMP_TO_UART= CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y -# CONFIG_ESP32_ENABLE_COREDUMP is not set -# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set +CONFIG_ESP32_ENABLE_COREDUMP= +CONFIG_TWO_UNIVERSAL_MAC_ADDRESS= CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 @@ -136,59 +137,59 @@ CONFIG_MAIN_TASK_STACK_SIZE=4096 CONFIG_IPC_TASK_STACK_SIZE=1024 CONFIG_TIMER_TASK_STACK_SIZE=4096 CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y -# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set -# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set -# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set -# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set +CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF= +CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR= +CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF= +CONFIG_NEWLIB_STDIN_LINE_ENDING_LF= CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y -# CONFIG_NEWLIB_NANO_FORMAT is not set +CONFIG_NEWLIB_NANO_FORMAT= CONFIG_CONSOLE_UART_DEFAULT=y -# CONFIG_CONSOLE_UART_CUSTOM is not set -# CONFIG_CONSOLE_UART_NONE is not set +CONFIG_CONSOLE_UART_CUSTOM= +CONFIG_CONSOLE_UART_NONE= CONFIG_CONSOLE_UART_NUM=0 CONFIG_CONSOLE_UART_BAUDRATE=115200 CONFIG_ULP_COPROC_ENABLED=y CONFIG_ULP_COPROC_RESERVE_MEM=512 -# CONFIG_ESP32_PANIC_PRINT_HALT is not set +CONFIG_ESP32_PANIC_PRINT_HALT= CONFIG_ESP32_PANIC_PRINT_REBOOT=y -# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set -# CONFIG_ESP32_PANIC_GDBSTUB is not set +CONFIG_ESP32_PANIC_SILENT_REBOOT= +CONFIG_ESP32_PANIC_GDBSTUB= CONFIG_ESP32_DEBUG_OCDAWARE=y CONFIG_INT_WDT=y CONFIG_INT_WDT_TIMEOUT_MS=300 CONFIG_INT_WDT_CHECK_CPU1=y -# CONFIG_TASK_WDT is not set +CONFIG_TASK_WDT= CONFIG_BROWNOUT_DET=y CONFIG_BROWNOUT_DET_LVL_SEL_0=y -# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set -# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set +CONFIG_BROWNOUT_DET_LVL_SEL_1= +CONFIG_BROWNOUT_DET_LVL_SEL_2= +CONFIG_BROWNOUT_DET_LVL_SEL_3= +CONFIG_BROWNOUT_DET_LVL_SEL_4= +CONFIG_BROWNOUT_DET_LVL_SEL_5= +CONFIG_BROWNOUT_DET_LVL_SEL_6= +CONFIG_BROWNOUT_DET_LVL_SEL_7= CONFIG_BROWNOUT_DET_LVL=0 -# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set +CONFIG_ESP32_TIME_SYSCALL_USE_RTC= CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y -# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set -# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set +CONFIG_ESP32_TIME_SYSCALL_USE_FRC1= +CONFIG_ESP32_TIME_SYSCALL_USE_NONE= CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y -# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set +CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL= CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 -# CONFIG_ESP32_XTAL_FREQ_40 is not set -# CONFIG_ESP32_XTAL_FREQ_26 is not set +CONFIG_ESP32_XTAL_FREQ_40= +CONFIG_ESP32_XTAL_FREQ_26= CONFIG_ESP32_XTAL_FREQ_AUTO=y CONFIG_ESP32_XTAL_FREQ=0 -# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set -# CONFIG_NO_BLOBS is not set +CONFIG_DISABLE_BASIC_ROM_CONSOLE= +CONFIG_NO_BLOBS= # # Wi-Fi # CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=0 -# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set +CONFIG_ESP32_WIFI_STATIC_TX_BUFFER= CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 @@ -198,10 +199,10 @@ CONFIG_ESP32_WIFI_RX_BA_WIN=6 CONFIG_ESP32_WIFI_NVS_ENABLED=y # -# Phy +# PHY # CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y -# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set +CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION= CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 CONFIG_ESP32_PHY_MAX_TX_POWER=20 @@ -210,70 +211,71 @@ CONFIG_ESP32_PHY_MAX_TX_POWER=20 # CONFIG_DMA_RX_BUF_NUM=10 CONFIG_DMA_TX_BUF_NUM=10 -# CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE is not set +CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE= CONFIG_EMAC_TASK_PRIORITY=20 # # FAT Filesystem support # CONFIG_FATFS_CODEPAGE_ASCII=y -# CONFIG_FATFS_CODEPAGE_437 is not set -# CONFIG_FATFS_CODEPAGE_720 is not set -# CONFIG_FATFS_CODEPAGE_737 is not set -# CONFIG_FATFS_CODEPAGE_771 is not set -# CONFIG_FATFS_CODEPAGE_775 is not set -# CONFIG_FATFS_CODEPAGE_850 is not set -# CONFIG_FATFS_CODEPAGE_852 is not set -# CONFIG_FATFS_CODEPAGE_855 is not set -# CONFIG_FATFS_CODEPAGE_857 is not set -# CONFIG_FATFS_CODEPAGE_860 is not set -# CONFIG_FATFS_CODEPAGE_861 is not set -# CONFIG_FATFS_CODEPAGE_862 is not set -# CONFIG_FATFS_CODEPAGE_863 is not set -# CONFIG_FATFS_CODEPAGE_864 is not set -# CONFIG_FATFS_CODEPAGE_865 is not set -# CONFIG_FATFS_CODEPAGE_866 is not set -# CONFIG_FATFS_CODEPAGE_869 is not set -# CONFIG_FATFS_CODEPAGE_932 is not set -# CONFIG_FATFS_CODEPAGE_936 is not set -# CONFIG_FATFS_CODEPAGE_949 is not set -# CONFIG_FATFS_CODEPAGE_950 is not set +CONFIG_FATFS_CODEPAGE_437= +CONFIG_FATFS_CODEPAGE_720= +CONFIG_FATFS_CODEPAGE_737= +CONFIG_FATFS_CODEPAGE_771= +CONFIG_FATFS_CODEPAGE_775= +CONFIG_FATFS_CODEPAGE_850= +CONFIG_FATFS_CODEPAGE_852= +CONFIG_FATFS_CODEPAGE_855= +CONFIG_FATFS_CODEPAGE_857= +CONFIG_FATFS_CODEPAGE_860= +CONFIG_FATFS_CODEPAGE_861= +CONFIG_FATFS_CODEPAGE_862= +CONFIG_FATFS_CODEPAGE_863= +CONFIG_FATFS_CODEPAGE_864= +CONFIG_FATFS_CODEPAGE_865= +CONFIG_FATFS_CODEPAGE_866= +CONFIG_FATFS_CODEPAGE_869= +CONFIG_FATFS_CODEPAGE_932= +CONFIG_FATFS_CODEPAGE_936= +CONFIG_FATFS_CODEPAGE_949= +CONFIG_FATFS_CODEPAGE_950= CONFIG_FATFS_CODEPAGE=1 CONFIG_FATFS_MAX_LFN=255 # # FreeRTOS # -# CONFIG_FREERTOS_UNICORE is not set +CONFIG_FREERTOS_UNICORE= CONFIG_FREERTOS_CORETIMER_0=y -# CONFIG_FREERTOS_CORETIMER_1 is not set +CONFIG_FREERTOS_CORETIMER_1= CONFIG_FREERTOS_HZ=1000 CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y -# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set -# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE= +CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL= CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK=y +CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=3 CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y -# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set -# CONFIG_FREERTOS_ASSERT_DISABLE is not set +CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE= +CONFIG_FREERTOS_ASSERT_DISABLE= CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y -# CONFIG_ENABLE_MEMORY_DEBUG is not set +CONFIG_ENABLE_MEMORY_DEBUG= CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1024 CONFIG_FREERTOS_ISR_STACKSIZE=1536 -# CONFIG_FREERTOS_LEGACY_HOOKS is not set +CONFIG_FREERTOS_LEGACY_HOOKS= CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 -# CONFIG_SUPPORT_STATIC_ALLOCATION is not set +CONFIG_SUPPORT_STATIC_ALLOCATION= CONFIG_TIMER_TASK_PRIORITY=1 CONFIG_TIMER_TASK_STACK_DEPTH=2048 CONFIG_TIMER_QUEUE_LENGTH=10 -# CONFIG_FREERTOS_DEBUG_INTERNALS is not set +CONFIG_FREERTOS_DEBUG_INTERNALS= # # Heap memory debugging # -# CONFIG_HEAP_POISONING_DISABLED is not set -# CONFIG_HEAP_POISONING_LIGHT is not set +CONFIG_HEAP_POISONING_DISABLED= +CONFIG_HEAP_POISONING_LIGHT= CONFIG_HEAP_POISONING_COMPREHENSIVE=y CONFIG_HEAP_TRACING=y CONFIG_HEAP_TRACING_STACK_DEPTH=2 @@ -281,26 +283,29 @@ CONFIG_HEAP_TRACING_STACK_DEPTH=2 # # Log output # -# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set -# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set -# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set +CONFIG_LOG_DEFAULT_LEVEL_NONE= +CONFIG_LOG_DEFAULT_LEVEL_ERROR= +CONFIG_LOG_DEFAULT_LEVEL_WARN= CONFIG_LOG_DEFAULT_LEVEL_INFO=y -# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set -# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set +CONFIG_LOG_DEFAULT_LEVEL_DEBUG= +CONFIG_LOG_DEFAULT_LEVEL_VERBOSE= CONFIG_LOG_DEFAULT_LEVEL=3 CONFIG_LOG_COLORS=y # # LWIP # -# CONFIG_L2_TO_L3_COPY is not set +CONFIG_L2_TO_L3_COPY= CONFIG_LWIP_MAX_SOCKETS=4 CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX=0 -# CONFIG_LWIP_SO_REUSE is not set -# CONFIG_LWIP_SO_RCVBUF is not set +CONFIG_LWIP_SO_REUSE= +CONFIG_LWIP_SO_RCVBUF= CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 -# CONFIG_LWIP_IP_FRAG is not set -# CONFIG_LWIP_IP_REASSEMBLY is not set +CONFIG_LWIP_IP_FRAG= +CONFIG_LWIP_IP_REASSEMBLY= +CONFIG_LWIP_STATS= +CONFIG_LWIP_ETHARP_TRUST_IP_MAC=y +CONFIG_TCPIP_RECVMBOX_SIZE=32 # # TCP @@ -308,43 +313,44 @@ CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 CONFIG_TCP_MAXRTX=12 CONFIG_TCP_SYNMAXRTX=6 CONFIG_TCP_MSS=1436 +CONFIG_TCP_MSL=60000 CONFIG_TCP_SND_BUF_DEFAULT=5744 CONFIG_TCP_WND_DEFAULT=5744 CONFIG_TCP_RECVMBOX_SIZE=6 CONFIG_TCP_QUEUE_OOSEQ=y CONFIG_TCP_OVERSIZE_MSS=y -# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set -# CONFIG_TCP_OVERSIZE_DISABLE is not set +CONFIG_TCP_OVERSIZE_QUARTER_MSS= +CONFIG_TCP_OVERSIZE_DISABLE= # # UDP # CONFIG_UDP_RECVMBOX_SIZE=6 -# CONFIG_LWIP_DHCP_DOES_ARP_CHECK is not set +CONFIG_LWIP_DHCP_DOES_ARP_CHECK= CONFIG_TCPIP_TASK_STACK_SIZE=2048 -# CONFIG_PPP_SUPPORT is not set +CONFIG_PPP_SUPPORT= # # ICMP # -# CONFIG_LWIP_MULTICAST_PING is not set -# CONFIG_LWIP_BROADCAST_PING is not set +CONFIG_LWIP_MULTICAST_PING= +CONFIG_LWIP_BROADCAST_PING= # # mbedTLS # CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384 -# CONFIG_MBEDTLS_DEBUG is not set +CONFIG_MBEDTLS_DEBUG= CONFIG_MBEDTLS_HARDWARE_AES=y CONFIG_MBEDTLS_HARDWARE_MPI=y CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y CONFIG_MBEDTLS_HARDWARE_SHA=y CONFIG_MBEDTLS_HAVE_TIME=y -# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set +CONFIG_MBEDTLS_HAVE_TIME_DATE= CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y -# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set -# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set -# CONFIG_MBEDTLS_TLS_DISABLED is not set +CONFIG_MBEDTLS_TLS_SERVER_ONLY= +CONFIG_MBEDTLS_TLS_CLIENT_ONLY= +CONFIG_MBEDTLS_TLS_DISABLED= CONFIG_MBEDTLS_TLS_SERVER=y CONFIG_MBEDTLS_TLS_CLIENT=y CONFIG_MBEDTLS_TLS_ENABLED=y @@ -352,7 +358,7 @@ CONFIG_MBEDTLS_TLS_ENABLED=y # # TLS Key Exchange Methods # -# CONFIG_MBEDTLS_PSK_MODES is not set +CONFIG_MBEDTLS_PSK_MODES= CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y @@ -361,11 +367,11 @@ CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y CONFIG_MBEDTLS_SSL_RENEGOTIATION=y -# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set +CONFIG_MBEDTLS_SSL_PROTO_SSL3= CONFIG_MBEDTLS_SSL_PROTO_TLS1=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y -# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set +CONFIG_MBEDTLS_SSL_PROTO_DTLS= CONFIG_MBEDTLS_SSL_ALPN=y CONFIG_MBEDTLS_SSL_SESSION_TICKETS=y @@ -373,16 +379,16 @@ CONFIG_MBEDTLS_SSL_SESSION_TICKETS=y # Symmetric Ciphers # CONFIG_MBEDTLS_AES_C=y -# CONFIG_MBEDTLS_CAMELLIA_C is not set -# CONFIG_MBEDTLS_DES_C is not set +CONFIG_MBEDTLS_CAMELLIA_C= +CONFIG_MBEDTLS_DES_C= CONFIG_MBEDTLS_RC4_DISABLED=y -# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set -# CONFIG_MBEDTLS_RC4_ENABLED is not set -# CONFIG_MBEDTLS_BLOWFISH_C is not set -# CONFIG_MBEDTLS_XTEA_C is not set +CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT= +CONFIG_MBEDTLS_RC4_ENABLED= +CONFIG_MBEDTLS_BLOWFISH_C= +CONFIG_MBEDTLS_XTEA_C= CONFIG_MBEDTLS_CCM_C=y CONFIG_MBEDTLS_GCM_C=y -# CONFIG_MBEDTLS_RIPEMD160_C is not set +CONFIG_MBEDTLS_RIPEMD160_C= # # Certificates @@ -411,16 +417,50 @@ CONFIG_MBEDTLS_ECP_NIST_OPTIM=y # # OpenSSL # -# CONFIG_OPENSSL_DEBUG is not set +CONFIG_OPENSSL_DEBUG= CONFIG_OPENSSL_ASSERT_DO_NOTHING=y -# CONFIG_OPENSSL_ASSERT_EXIT is not set +CONFIG_OPENSSL_ASSERT_EXIT= + +# +# PThreads +# +CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 +CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=2048 # # SPI Flash driver # -# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set +CONFIG_SPI_FLASH_ENABLE_COUNTERS= CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y +# +# SPIFFS Configuration +# +CONFIG_SPIFFS_MAX_PARTITIONS=3 + +# +# SPIFFS Cache Configuration +# +CONFIG_SPIFFS_CACHE=y +CONFIG_SPIFFS_CACHE_WR=y +CONFIG_SPIFFS_CACHE_STATS= +CONFIG_SPIFFS_PAGE_CHECK=y +CONFIG_SPIFFS_GC_MAX_RUNS=10 +CONFIG_SPIFFS_GC_STATS= +CONFIG_SPIFFS_OBJ_NAME_LEN=32 +CONFIG_SPIFFS_USE_MAGIC=y +CONFIG_SPIFFS_USE_MAGIC_LENGTH=y + +# +# Debug Configuration +# +CONFIG_SPIFFS_DBG= +CONFIG_SPIFFS_API_DBG= +CONFIG_SPIFFS_GC_DBG= +CONFIG_SPIFFS_CACHE_DBG= +CONFIG_SPIFFS_CHECK_DBG= +CONFIG_SPIFFS_TEST_VISUALISATION= + # # tcpip adapter # @@ -429,6 +469,6 @@ CONFIG_IP_LOST_TIMER_INTERVAL=120 # # Wear Levelling # -# CONFIG_WL_SECTOR_SIZE_512 is not set +CONFIG_WL_SECTOR_SIZE_512= CONFIG_WL_SECTOR_SIZE_4096=y CONFIG_WL_SECTOR_SIZE=4096 From 3e62c2e0520324f41531fe7f8a2ea2271f833c52 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 28 Sep 2017 11:46:53 +1000 Subject: [PATCH 2/3] freertos: When scheduler is disabled, tasks on other core should immediately resume ... if triggered by a SemaphoreGive/etc. Previously they would resume after scheduler was resumed, on next RTOS tick of other CPU. --- components/freertos/tasks.c | 20 +++++++++++++++++-- .../freertos/test/test_suspend_scheduler.c | 15 ++++++-------- docs/api-guides/freertos-smp.rst | 5 ----- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 15d588662c..15cdaad652 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -3038,6 +3038,8 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) { TCB_t *pxUnblockedTCB; BaseType_t xReturn; +BaseType_t xTaskCanBeReady; +UBaseType_t i; /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be called from a critical section within an ISR. */ @@ -3061,7 +3063,21 @@ BaseType_t xReturn; return pdFALSE; } - if( uxSchedulerSuspended[ xPortGetCoreID() ] == ( UBaseType_t ) pdFALSE ) + /* Determine if the task can possibly be run on either CPU now, either because the scheduler + the task is pinned to is running or because a scheduler is running on any CPU. */ + xTaskCanBeReady = pdFALSE; + if ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) { + for (i = 0; i < portNUM_PROCESSORS; i++) { + if ( uxSchedulerSuspended[ i ] == ( UBaseType_t ) pdFALSE ) { + xTaskCanBeReady = pdTRUE; + break; + } + } + } else { + xTaskCanBeReady = uxSchedulerSuspended[ pxUnblockedTCB->xCoreID ] == ( UBaseType_t ) pdFALSE; + } + + if( xTaskCanBeReady ) { ( void ) uxListRemove( &( pxUnblockedTCB->xGenericListItem ) ); prvAddTaskToReadyList( pxUnblockedTCB ); @@ -3069,7 +3085,7 @@ BaseType_t xReturn; else { /* The delayed and ready lists cannot be accessed, so hold this task - pending until the scheduler is resumed. */ + pending until the scheduler is resumed on this CPU. */ vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxUnblockedTCB->xEventListItem ) ); } diff --git a/components/freertos/test/test_suspend_scheduler.c b/components/freertos/test/test_suspend_scheduler.c index c96eabbc8c..b429c7c391 100644 --- a/components/freertos/test/test_suspend_scheduler.c +++ b/components/freertos/test/test_suspend_scheduler.c @@ -154,9 +154,8 @@ TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]" /* Suspend scheduler on this CPU */ vTaskSuspendAll(); - /* Give all the semaphores once. You might expect this will wake up tasks on the other - CPU (where the scheduler is not suspended) but it doesn't do this in the current implementation - - all tasks are added to xPendingReadyList and woken up later. See note in the freertos-smp docs. + /* Give all the semaphores once. This will wake tasks immediately on the other + CPU, but they are deferred here until the scheduler resumes. */ for (int p = 0; p < portNUM_PROCESSORS; p++) { for (int t = 0; t < TASKS_PER_PROC; t++) { @@ -164,21 +163,19 @@ TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]" } } - ets_delay_us(2 * 1000); /* Can't vTaskDelay() while scheduler is suspended, but let other CPU do some things */ + ets_delay_us(1000); /* Let the other CPU do some things */ for (int p = 0; p < portNUM_PROCESSORS; p++) { for (int t = 0; t < TASKS_PER_PROC; t++) { - /* You might expect that this is '1' for the other CPU, but it's not (see comment above) */ - ets_printf("Checking CPU %d task %d (expected 0 actual %d)\n", p, t, counters[p][t].counter); - TEST_ASSERT_EQUAL(0, counters[p][t].counter); + int expected = (p == UNITY_FREERTOS_CPU) ? 0 : 1; // Has run if it was on the other CPU + ets_printf("Checking CPU %d task %d (expected %d actual %d)\n", p, t, expected, counters[p][t].counter); + TEST_ASSERT_EQUAL(expected, counters[p][t].counter); } } /* Resume scheduler */ xTaskResumeAll(); - vTaskDelay(TASKS_PER_PROC * 2); - /* Now the tasks on both CPUs should have been woken once and counted once. */ for (int p = 0; p < portNUM_PROCESSORS; p++) { for (int t = 0; t < TASKS_PER_PROC; t++) { diff --git a/docs/api-guides/freertos-smp.rst b/docs/api-guides/freertos-smp.rst index f135c017a6..a706320d84 100644 --- a/docs/api-guides/freertos-smp.rst +++ b/docs/api-guides/freertos-smp.rst @@ -227,11 +227,6 @@ protection against simultaneous access. Consider using critical sections (disables interrupts) or semaphores (does not disable interrupts) instead when protecting shared resources in ESP-IDF FreeRTOS. -If the task running on the CPU with scheduler suspended calls a function (like -``xSemaphoreGive``, ``xQueueSend``) that wakes another task, this task will not run -until after ``vTaskResumeAll()`` is called. This is true even if the woken task is -on the other CPU (where the scheduler is still running). - In general, it's better to use other RTOS primitives like mutex semaphores to protect against data shared between tasks, rather than ``vTaskSuspendAll()``. From 353e81da633f9fc50815bcaa6415628bf06f7541 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 28 Sep 2017 12:08:34 +1000 Subject: [PATCH 3/3] freertos: Also test (& handle) the case where scheduler is disabled on other CPU... ie CPU A has scheduler disabled and task blocked on Q. CPU B sends to Q (or gives mutex, etc.) Task on CPU A should be woken on scheduler resume. --- components/freertos/tasks.c | 9 ++- .../freertos/test/test_suspend_scheduler.c | 61 ++++++++++++++++++- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 15cdaad652..f20715903d 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -3039,7 +3039,7 @@ BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) TCB_t *pxUnblockedTCB; BaseType_t xReturn; BaseType_t xTaskCanBeReady; -UBaseType_t i; +UBaseType_t i, uxTargetCPU; /* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be called from a critical section within an ISR. */ @@ -3067,6 +3067,7 @@ UBaseType_t i; the task is pinned to is running or because a scheduler is running on any CPU. */ xTaskCanBeReady = pdFALSE; if ( pxUnblockedTCB->xCoreID == tskNO_AFFINITY ) { + uxTargetCPU = xPortGetCoreID(); for (i = 0; i < portNUM_PROCESSORS; i++) { if ( uxSchedulerSuspended[ i ] == ( UBaseType_t ) pdFALSE ) { xTaskCanBeReady = pdTRUE; @@ -3074,7 +3075,9 @@ UBaseType_t i; } } } else { - xTaskCanBeReady = uxSchedulerSuspended[ pxUnblockedTCB->xCoreID ] == ( UBaseType_t ) pdFALSE; + uxTargetCPU = pxUnblockedTCB->xCoreID; + xTaskCanBeReady = uxSchedulerSuspended[ uxTargetCPU ] == ( UBaseType_t ) pdFALSE; + } if( xTaskCanBeReady ) @@ -3086,7 +3089,7 @@ UBaseType_t i; { /* The delayed and ready lists cannot be accessed, so hold this task pending until the scheduler is resumed on this CPU. */ - vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxUnblockedTCB->xEventListItem ) ); + vListInsertEnd( &( xPendingReadyList[ uxTargetCPU ] ), &( pxUnblockedTCB->xEventListItem ) ); } if ( tskCAN_RUN_HERE(pxUnblockedTCB->xCoreID) && pxUnblockedTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) diff --git a/components/freertos/test/test_suspend_scheduler.c b/components/freertos/test/test_suspend_scheduler.c index b429c7c391..c613dc6474 100644 --- a/components/freertos/test/test_suspend_scheduler.c +++ b/components/freertos/test/test_suspend_scheduler.c @@ -49,7 +49,7 @@ static void counter_task_fn(void *vp_config) In the FreeRTOS implementation, this exercises the xPendingReadyList for that core. */ -TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]") +TEST_CASE("Scheduler disabled can handle a pending context switch on resume", "[freertos]") { isr_count = 0; isr_semaphore = xSemaphoreCreateMutex(); @@ -122,7 +122,7 @@ TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]" while scheduler is suspended, and should be started once the scheduler resumes. */ -TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]") +TEST_CASE("Scheduler disabled can wake multiple tasks on resume", "[freertos]") { #define TASKS_PER_PROC 4 TaskHandle_t tasks[portNUM_PROCESSORS][TASKS_PER_PROC] = { 0 }; @@ -163,7 +163,7 @@ TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]" } } - ets_delay_us(1000); /* Let the other CPU do some things */ + ets_delay_us(200); /* Let the other CPU do some things */ for (int p = 0; p < portNUM_PROCESSORS; p++) { for (int t = 0; t < TASKS_PER_PROC; t++) { @@ -192,3 +192,58 @@ TEST_CASE("Handle waking multiple tasks while scheduler suspended", "[freertos]" } } } + +static volatile bool sched_suspended; +static void suspend_scheduler_5ms_task_fn(void *ignore) +{ + vTaskSuspendAll(); + sched_suspended = true; + for (int i = 0; i <5; i++) { + ets_delay_us(1000); + } + xTaskResumeAll(); + sched_suspended = false; + vTaskDelete(NULL); +} + +#ifndef CONFIG_FREERTOS_UNICORE +/* If the scheduler is disabled on one CPU (A) with a task blocked on something, and a task + on B (where scheduler is running) wakes it, then the task on A should be woken on resume. +*/ +TEST_CASE("Scheduler disabled on CPU B, tasks on A can wake", "[freertos]") +{ + TaskHandle_t counter_task; + SemaphoreHandle_t wake_sem = xSemaphoreCreateMutex(); + xSemaphoreTake(wake_sem, 0); + counter_config_t count_config = { + .trigger_sem = wake_sem, + .counter = 0, + }; + xTaskCreatePinnedToCore(counter_task_fn, "counter", 2048, + &count_config, UNITY_FREERTOS_PRIORITY + 1, + &counter_task, !UNITY_FREERTOS_CPU); + + xTaskCreatePinnedToCore(suspend_scheduler_5ms_task_fn, "suspender", 2048, + NULL, UNITY_FREERTOS_PRIORITY - 1, + NULL, !UNITY_FREERTOS_CPU); + + /* counter task is now blocked on other CPU, waiting for wake_sem, and we expect + that this CPU's scheduler will be suspended for 5ms shortly... */ + while(!sched_suspended) { } + + xSemaphoreGive(wake_sem); + ets_delay_us(1000); + // Bit of a race here if the other CPU resumes its scheduler, but 5ms is a long time... */ + TEST_ASSERT(sched_suspended); + TEST_ASSERT_EQUAL(0, count_config.counter); // the other task hasn't woken yet, because scheduler is off + TEST_ASSERT(sched_suspended); + + /* wait for the rest of the 5ms... */ + while(sched_suspended) { } + + ets_delay_us(100); + TEST_ASSERT_EQUAL(1, count_config.counter); // when scheduler resumes, counter task should immediately count + + vTaskDelete(counter_task); +} +#endif