From b00be955ee0e06e6c04439f3dc9a4abe90bb7704 Mon Sep 17 00:00:00 2001 From: Konstantin Kondrashov Date: Wed, 7 Nov 2018 19:47:51 +0800 Subject: [PATCH] newlib: Fix UT adjtime --- components/newlib/test/test_time.c | 103 +++++++++++++++++------------ 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/components/newlib/test/test_time.c b/components/newlib/test/test_time.c index aab7ff53f..4a55b303e 100644 --- a/components/newlib/test/test_time.c +++ b/components/newlib/test/test_time.c @@ -11,7 +11,7 @@ #include "sdkconfig.h" #include "soc/rtc.h" #include "esp_clk.h" - +#include "esp_system.h" #if portNUM_PROCESSORS == 2 @@ -133,8 +133,6 @@ TEST_CASE("test adjtime function", "[newlib]") } static volatile bool exit_flag; -static bool adjtime_test_result; -static bool gettimeofday_test_result; static void adjtimeTask2(void *pvParameters) { @@ -205,26 +203,51 @@ TEST_CASE("test for no interlocking adjtime, gettimeofday and settimeofday funct } } +#ifndef CONFIG_FREERTOS_UNICORE +static xSemaphoreHandle gettime_start_sema; +static xSemaphoreHandle adjtime_continue_sema; static void adjtimeTask(void *pvParameters) { - struct timeval delta = {.tv_sec = 0, .tv_usec = 0}; - struct timeval outdelta = {.tv_sec = 0, .tv_usec = 0}; + const uint64_t adjtime_us = 2000000000; // 2000 sec + struct timeval delta = {.tv_sec = adjtime_us / 1000000, .tv_usec = 900000}; + struct timeval outdelta; + struct timeval tv_time; + int shift = 1; + int cycle = 0; // although exit flag is set in another task, checking (exit_flag == false) is safe while (exit_flag == false) { - delta.tv_sec = 1000; - delta.tv_usec = 0; - if(adjtime(&delta, &outdelta) != 0) { - adjtime_test_result = true; - exit_flag = true; + gettimeofday(&tv_time, NULL); + uint64_t start_time_us = (uint64_t)tv_time.tv_sec * 1000000L + tv_time.tv_usec; + + ++cycle; + if (shift > 3000) { + shift = 1; } - delta.tv_sec = 0; - delta.tv_usec = 1000; - if(adjtime(&delta, &outdelta) != 0) { - adjtime_test_result = true; - exit_flag = true; + int i_shift = shift++; + + xSemaphoreGive(gettime_start_sema); + while (--i_shift) { + __asm__ __volatile__ ("nop": : : "memory"); + }; + adjtime(&delta, &outdelta); + xSemaphoreTake(adjtime_continue_sema, portMAX_DELAY); + + gettimeofday(&tv_time, NULL); + uint64_t end_time_us = (uint64_t)tv_time.tv_sec * 1000000L + tv_time.tv_usec; + + if (!(start_time_us < end_time_us) || (end_time_us - start_time_us > adjtime_us) + || (end_time_us - start_time_us > 300) || (end_time_us - start_time_us < 30)) { + printf("ERROR: start_time_us %lld usec.\n", start_time_us); + printf("ERROR: end_time_us %lld usec.\n", end_time_us); + printf("ERROR: dt %lld usec.\n", end_time_us - start_time_us); + printf("ERROR: cycle %d\n", cycle); + printf("ERROR: shift %d\n", shift); + TEST_FAIL_MESSAGE("The time is corrupted due to the lack of locks for the adjtime function."); } } + xSemaphoreGive(adjtime_continue_sema); + xSemaphoreGive(gettime_start_sema); vTaskDelete(NULL); } @@ -232,52 +255,48 @@ static void gettimeofdayTask(void *pvParameters) { struct timeval tv_time; - gettimeofday(&tv_time, NULL); - uint64_t time_old = (uint64_t)tv_time.tv_sec * 1000000L + tv_time.tv_usec; // although exit flag is set in another task, checking (exit_flag == false) is safe while (exit_flag == false) { + xSemaphoreTake(gettime_start_sema, portMAX_DELAY); gettimeofday(&tv_time, NULL); - uint64_t time = (uint64_t)tv_time.tv_sec * 1000000L + tv_time.tv_usec; - if(((time - time_old) > 1000000LL) || (time_old > time)) { - printf("ERROR: time jumped for %lld/1000 seconds. No locks. Need to use locks.\n", (time - time_old)/1000000LL); - gettimeofday_test_result = true; - exit_flag = true; - } - time_old = time; + xSemaphoreGive(adjtime_continue_sema); } + xSemaphoreGive(adjtime_continue_sema); + xSemaphoreGive(gettime_start_sema); vTaskDelete(NULL); } TEST_CASE("test for thread safety adjtime and gettimeofday functions", "[newlib]") { - TaskHandle_t th[4]; exit_flag = false; - adjtime_test_result = false; - gettimeofday_test_result = false; - struct timeval tv_time = { .tv_sec = 1520000000, .tv_usec = 900000 }; - TEST_ASSERT_EQUAL(settimeofday(&tv_time, NULL), 0); + struct timeval tv_time = { .tv_sec = 1520000000, .tv_usec = 0 }; + TEST_ASSERT_EQUAL(0, settimeofday(&tv_time, NULL)); + + gettime_start_sema = xSemaphoreCreateBinary(); + adjtime_continue_sema = xSemaphoreCreateBinary(); -#ifndef CONFIG_FREERTOS_UNICORE printf("CPU0 and CPU1. Tasks run: 1 - adjtimeTask, 2 - gettimeofdayTask\n"); - xTaskCreatePinnedToCore(adjtimeTask, "adjtimeTask1", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, &th[0], 0); - xTaskCreatePinnedToCore(gettimeofdayTask, "gettimeofdayTask1", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, &th[1], 1); - xTaskCreatePinnedToCore(gettimeofdayTask, "gettimeofdayTask2", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, &th[2], 0); -#else - printf("Only one CPU. Tasks run: 1 - adjtimeTask, 2 - gettimeofdayTask\n"); - xTaskCreate(adjtimeTask, "adjtimeTask1", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, &th[0]); - xTaskCreate(gettimeofdayTask, "gettimeofdayTask1", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, &th[1]); -#endif + xTaskCreatePinnedToCore(adjtimeTask, "adjtimeTask", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, NULL, 0); + xTaskCreatePinnedToCore(gettimeofdayTask, "gettimeofdayTask", 2048, NULL, UNITY_FREERTOS_PRIORITY - 1, NULL, 1); - printf("start wait for 5 seconds\n"); - vTaskDelay(5000 / portTICK_PERIOD_MS); + printf("start wait for 10 seconds\n"); + vTaskDelay(10000 / portTICK_PERIOD_MS); // set exit flag to let thread exit exit_flag = true; - vTaskDelay(20 / portTICK_PERIOD_MS); + vTaskDelay(2000 / portTICK_PERIOD_MS); - TEST_ASSERT(adjtime_test_result == false && gettimeofday_test_result == false); + if (!xSemaphoreTake(gettime_start_sema, 1000 / portTICK_PERIOD_MS)) { + TEST_FAIL_MESSAGE("gettime_start_semaphore not released by test task"); + } + if (!xSemaphoreTake(adjtime_continue_sema, 1000 / portTICK_PERIOD_MS)) { + TEST_FAIL_MESSAGE("adjtime_continue_semaphore not released by test task"); + } + vSemaphoreDelete(gettime_start_sema); + vSemaphoreDelete(adjtime_continue_sema); } +#endif #if defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 ) #define WITH_RTC 1