From f40ae10a5d49d536444b73e0a48a715701975b8a Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 5 Jun 2017 16:08:23 +1000 Subject: [PATCH 1/2] freertos: add test case for ISRs waking tasks when scheduler disabled --- .../freertos/test/test_suspend_scheduler.c | 106 ++++++++++++++++++ ...nd_resume.c => test_task_suspend_resume.c} | 0 tools/unit-test-app/sdkconfig | 9 +- 3 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 components/freertos/test/test_suspend_scheduler.c rename components/freertos/test/{test_suspend_resume.c => test_task_suspend_resume.c} (100%) diff --git a/components/freertos/test/test_suspend_scheduler.c b/components/freertos/test/test_suspend_scheduler.c new file mode 100644 index 000000000..3d2783b4f --- /dev/null +++ b/components/freertos/test/test_suspend_scheduler.c @@ -0,0 +1,106 @@ +/* Tests for FreeRTOS scheduler suspend & resume all tasks */ +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" +#include "freertos/xtensa_api.h" +#include "unity.h" +#include "soc/cpu.h" + +#include "driver/timer.h" + +static SemaphoreHandle_t isr_semaphore; +static volatile unsigned isr_count, task_count; + +/* Timer ISR increments an ISR counter, and signals a + mutex semaphore to wake up another counter task */ +static void timer_group0_isr(void *vp_arg) +{ + TIMERG0.int_clr_timers.t0 = 1; + TIMERG0.hw_timer[TIMER_0].update = 1; + TIMERG0.hw_timer[TIMER_0].config.alarm_en = 1; + portBASE_TYPE higher_awoken = pdFALSE; + isr_count++; + xSemaphoreGiveFromISR(isr_semaphore, &higher_awoken); + if (higher_awoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} + +static void counter_task_fn(void *ignore) +{ + printf("counter_task running...\n"); + while(1) { + xSemaphoreTake(isr_semaphore, portMAX_DELAY); + task_count++; + } +} + + +/* This test verifies that an interrupt can wake up a task while the scheduler is disabled. + + In the FreeRTOS implementation, this exercises the xPendingReadyList for that core. + */ +TEST_CASE("Handle pending context switch while scheduler disabled", "[freertos]") +{ + task_count = 0; + isr_count = 0; + isr_semaphore = xSemaphoreCreateMutex(); + TaskHandle_t counter_task; + + xTaskCreatePinnedToCore(counter_task_fn, "counter", 2048, + NULL, UNITY_FREERTOS_PRIORITY + 1, + &counter_task, UNITY_FREERTOS_CPU); + + /* Configure timer ISR */ + const timer_config_t config = { + .alarm_en = 1, + .auto_reload = 1, + .counter_dir = TIMER_COUNT_UP, + .divider = 1, + .intr_type = TIMER_INTR_LEVEL, + .counter_en = TIMER_PAUSE, + }; + /* Configure timer */ + timer_init(TIMER_GROUP_0, TIMER_0, &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); + timer_enable_intr(TIMER_GROUP_0, TIMER_0); + timer_isr_register(TIMER_GROUP_0, TIMER_0, timer_group0_isr, NULL, 0, NULL); + timer_start(TIMER_GROUP_0, TIMER_0); + + vTaskDelay(5); + + // Check some counts have been triggered via the ISR + TEST_ASSERT(task_count > 10); + TEST_ASSERT(isr_count > 10); + + for (int i = 0; i < 20; i++) { + vTaskSuspendAll(); + esp_intr_noniram_disable(); + + unsigned no_sched_task = task_count; + + // 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); + + // disable timer interrupts + timer_disable_intr(TIMER_GROUP_0, TIMER_0); + + // When we resume scheduler, we expect the counter task + // will preempt and count at least one more item + esp_intr_noniram_enable(); + xTaskResumeAll(); + + TEST_ASSERT_NOT_EQUAL(task_count, no_sched_task); + } + + vTaskDelete(counter_task); + vSemaphoreDelete(isr_semaphore); +} diff --git a/components/freertos/test/test_suspend_resume.c b/components/freertos/test/test_task_suspend_resume.c similarity index 100% rename from components/freertos/test/test_suspend_resume.c rename to components/freertos/test/test_task_suspend_resume.c diff --git a/tools/unit-test-app/sdkconfig b/tools/unit-test-app/sdkconfig index e4b897348..abbb29229 100644 --- a/tools/unit-test-app/sdkconfig +++ b/tools/unit-test-app/sdkconfig @@ -111,12 +111,9 @@ CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y # CONFIG_ESP32_APPTRACE_DEST_UART is not set CONFIG_ESP32_APPTRACE_DEST_NONE=y # CONFIG_ESP32_APPTRACE_ENABLE is not set -CONFIG_BASE_MAC_STORED_DEFAULT_EFUSE=y -# CONFIG_BASE_MAC_STORED_CUSTOMER_DEFINED_EFUSE is not set -# CONFIG_BASE_MAC_STORED_OTHER_CUSTOMER_DEFINED_PLACE is not set -# CONFIG_TWO_MAC_ADDRESS_FROM_EFUSE is not set -CONFIG_FOUR_MAC_ADDRESS_FROM_EFUSE=y -CONFIG_NUMBER_OF_MAC_ADDRESS_GENERATED_FROM_EFUSE=4 +# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set +CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y +CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048 CONFIG_MAIN_TASK_STACK_SIZE=4096 From b9fc5ecf684f5fe985dadae0c83510b75254ddb2 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Mon, 5 Jun 2017 16:08:46 +1000 Subject: [PATCH 2/2] freertos: Fix crash when waking task on CPU1 with scheduler disabled xPendingReadyList[1] was never initialised correctly, so if a task is added to this list (ie by xSemaphoreGiveFromISR() or similar) while scheduler is disabled, then it causes a null pointer dereference. Bug produces stack traces similar to: 0x40086e87: vListInsertEnd at /home/gus/esp/32/idf/components/freertos/./list.c:130 0x40084ba3: xTaskRemoveFromEventList at /home/gus/esp/32/idf/components/freertos/./tasks.c:3439 0x40083c54: xQueueGiveFromISR at /home/gus/esp/32/idf/components/freertos/./queue.c:2034 0x400f50a0: timer_group0_isr at /home/gus/esp/32/idf/components/freertos/test/./test_suspend_scheduler.c:27 0x40081d7d: _xt_lowint1 at xtensa_vectors.o:? --- components/freertos/tasks.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index d70a278b1..7bf51472c 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -3508,7 +3508,10 @@ UBaseType_t uxPriority; vListInitialise( &xDelayedTaskList1 ); vListInitialise( &xDelayedTaskList2 ); - vListInitialise( &xPendingReadyList[ xPortGetCoreID() ] ); + vListInitialise( &xPendingReadyList[ 0 ] ); + if (portNUM_PROCESSORS == 2) { + vListInitialise( &xPendingReadyList[ 1 ] ); + } #if ( INCLUDE_vTaskDelete == 1 ) {