// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "esp_rom_sys.h" #include "hal/interrupt_controller_hal.h" #include "unity.h" #include "test_utils.h" /* Test Best Effort Round Robin Scheduling: The following test case tests the "Best Effort Round Robin Scheduling" that fixes the skipping behavior found in older versions of the ESP-IDF SMP FreeRTOS (see docs for more details about Best Effort Round Robin Scheduling). This test... - Only runs under dual core configuration - Will disable the tick interrupts of both cores Test flow as follows: 1. Stop preemption on core 0 by raising the priority of the unity task 2. Stop preemption on core 0 by creating a blocker task 3. Disable tick interrupts on both cores 4. Create N spin tasks on each core, each with a sequential task_code 5. Unblock those spin tasks in a sequential order 6. Lower priority of unity task and stop the blocker task so that spin tasks are run 7. Each time a spin task is run (i.e., an iteration) it will send its task code to a queue 8. Spin tasks will clean themselves up 9. The queue should contain the task codes of the spin tasks in the order they were started in, thus showing that round robin schedules the tasks in a sequential order. */ #if !defined(CONFIG_FREERTOS_UNICORE) && (defined(CONFIG_FREERTOS_CORETIMER_0) || defined(CONFIG_FREERTOS_CORETIMER_1)) #define SPIN_TASK_PRIO (CONFIG_UNITY_FREERTOS_PRIORITY + 1) #define SPIN_TASK_NUM_ITER 3 #define TASK_STACK_SIZE 1024 #define NUM_PINNED_SPIN_TASK_PER_CORE 3 #if defined(CONFIG_FREERTOS_CORETIMER_0) #define TICK_INTR_IDX 6 #else //defined(CONFIG_FREERTOS_CORETIMER_1) #define TICK_INTR_IDX 15 #endif static QueueHandle_t core0_run_order_queue; static QueueHandle_t core1_run_order_queue; static uint32_t total_iter_count[portNUM_PROCESSORS] = {0}; static void spin_task(void *arg) { uint32_t task_code = (uint32_t)arg; QueueHandle_t run_order_queue = ((task_code >> 4) == 0) ? core0_run_order_queue : core1_run_order_queue; //Wait to be started ulTaskNotifyTake(pdTRUE, portMAX_DELAY); for (int i = 0; i < SPIN_TASK_NUM_ITER; i++) { xQueueSend(run_order_queue, &task_code, 0); //No need for critical sections as tick interrupt is disabled total_iter_count[xPortGetCoreID()]++; taskYIELD(); } //Last iteration of the last spin task on this core. Reenable this core's tick interrupt if (total_iter_count[xPortGetCoreID()] == (NUM_PINNED_SPIN_TASK_PER_CORE * SPIN_TASK_NUM_ITER)) { interrupt_controller_hal_enable_interrupts(1 <