Merge branch 'contrib/github_pr_15132_v5.3' into 'release/v5.3'

fix(newlib): usleep returning early (GitHub PR) (v5.3)

See merge request espressif/esp-idf!38709
This commit is contained in:
Marius Vikhammer
2025-05-13 14:38:55 +08:00
5 changed files with 74 additions and 10 deletions

View File

@@ -1,2 +1,2 @@
idf_component_register(SRCS "test_cxx_general.cpp" idf_component_register(SRCS "test_cxx_general.cpp"
PRIV_REQUIRES unity driver) PRIV_REQUIRES unity driver esp_timer)

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -14,6 +14,9 @@
#include "unity.h" #include "unity.h"
#include "unity_test_utils.h" #include "unity_test_utils.h"
#include "soc/soc.h" #include "soc/soc.h"
#include <chrono>
#include <thread>
#include "esp_timer.h"
extern "C" void setUp() extern "C" void setUp()
{ {
@@ -197,7 +200,7 @@ struct PriorityInitTest {
int PriorityInitTest::order = 0; int PriorityInitTest::order = 0;
// init_priority objects are initialized from the lowest to the heighest priority number // init_priority objects are initialized from the lowest to the highest priority number
// Default init_priority is always the lowest (highest priority number) // Default init_priority is always the lowest (highest priority number)
PriorityInitTest g_static_init_priority_test2; PriorityInitTest g_static_init_priority_test2;
PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(1000))); PriorityInitTest g_static_init_priority_test1 __attribute__((init_priority(1000)));
@@ -289,6 +292,29 @@ TEST_CASE("stack smashing protection CXX", "[stack_smash]")
recur_and_smash_cxx(); recur_and_smash_cxx();
} }
TEST_CASE("test std::this_thread::sleep_for basic functionality", "[misc]")
{
const int us_per_tick = portTICK_PERIOD_MS * 1000;
// Test sub-tick sleep
const auto short_sleep = std::chrono::microseconds(us_per_tick / 4);
int64_t start = esp_timer_get_time();
std::this_thread::sleep_for(short_sleep);
int64_t end = esp_timer_get_time();
int64_t elapsed_us = end - start;
printf("short sleep: %lld us\n", elapsed_us);
TEST_ASSERT_GREATER_OR_EQUAL(short_sleep.count(), elapsed_us);
// Test multi-tick sleep
const auto long_sleep = std::chrono::microseconds(us_per_tick * 2);
start = esp_timer_get_time();
std::this_thread::sleep_for(long_sleep);
end = esp_timer_get_time();
elapsed_us = end - start;
printf("long sleep: %lld us\n", elapsed_us);
TEST_ASSERT_GREATER_OR_EQUAL(long_sleep.count(), elapsed_us);
}
extern "C" void app_main(void) extern "C" void app_main(void)
{ {
printf("CXX GENERAL TEST\n"); printf("CXX GENERAL TEST\n");

View File

@@ -167,7 +167,7 @@ static uint32_t pcnt_get_pulse_number(pcnt_unit_handle_t pwm_pcnt_unit, int capt
int count_value = 0; int count_value = 0;
TEST_ESP_OK(pcnt_unit_clear_count(pwm_pcnt_unit)); TEST_ESP_OK(pcnt_unit_clear_count(pwm_pcnt_unit));
TEST_ESP_OK(pcnt_unit_start(pwm_pcnt_unit)); TEST_ESP_OK(pcnt_unit_start(pwm_pcnt_unit));
usleep(capture_window_ms * 1000); vTaskDelay(pdMS_TO_TICKS(capture_window_ms));
TEST_ESP_OK(pcnt_unit_stop(pwm_pcnt_unit)); TEST_ESP_OK(pcnt_unit_stop(pwm_pcnt_unit));
TEST_ESP_OK(pcnt_unit_get_count(pwm_pcnt_unit, &count_value)); TEST_ESP_OK(pcnt_unit_get_count(pwm_pcnt_unit, &count_value));
printf("count value: %d\r\n", count_value); printf("count value: %d\r\n", count_value);

View File

@@ -1,11 +1,12 @@
/* /*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
#include <unistd.h>
#include "unity.h" #include "unity.h"
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
@@ -93,6 +94,27 @@ TEST_CASE("Reading RTC registers on APP CPU doesn't affect clock", "[newlib]")
#endif // (CONFIG_FREERTOS_NUMBER_OF_CORES == 2) && CONFIG_IDF_TARGET_ARCH_XTENSA #endif // (CONFIG_FREERTOS_NUMBER_OF_CORES == 2) && CONFIG_IDF_TARGET_ARCH_XTENSA
TEST_CASE("test usleep basic functionality", "[newlib]")
{
const int us_per_tick = portTICK_PERIOD_MS * 1000;
// Test sub-tick sleep such that usleep() uses ROM delay path
const int short_sleep_us = us_per_tick / 4;
int64_t start = esp_timer_get_time();
TEST_ASSERT_EQUAL(0, usleep(short_sleep_us));
int64_t end = esp_timer_get_time();
printf("short sleep: %lld us\n", end - start);
TEST_ASSERT_GREATER_OR_EQUAL(short_sleep_us, end - start);
// Test multi-tick sleep using vTaskDelay path
const int long_sleep_us = us_per_tick * 2;
start = esp_timer_get_time();
TEST_ASSERT_EQUAL(0, usleep(long_sleep_us));
end = esp_timer_get_time();
printf("long sleep: %lld us\n", end - start);
TEST_ASSERT_GREATER_OR_EQUAL(long_sleep_us, end - start);
}
TEST_CASE("test adjtime function", "[newlib]") TEST_CASE("test adjtime function", "[newlib]")
{ {
struct timeval tv_time; struct timeval tv_time;

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -207,10 +207,26 @@ int usleep(useconds_t us)
if (us < us_per_tick) { if (us < us_per_tick) {
esp_rom_delay_us((uint32_t) us); esp_rom_delay_us((uint32_t) us);
} else { } else {
/* since vTaskDelay(1) blocks for anywhere between 0 and portTICK_PERIOD_MS, /* vTaskDelay may return up to (n-1) tick periods due to the tick ISR
* round up to compensate. being asynchronous to the call. We must sleep at least the specified
*/ time, or longer. Checking the monotonic clock allows making an
vTaskDelay((us + us_per_tick - 1) / us_per_tick); additional call to vTaskDelay when needed to ensure minimal time is
actually slept. Adding `us_per_tick - 1` prevents ever passing 0 to
vTaskDelay().
*/
uint64_t now_us = esp_time_impl_get_time();
uint64_t target_us = now_us + us;
do {
vTaskDelay((((target_us - now_us) + us_per_tick - 1) / us_per_tick));
now_us = esp_time_impl_get_time();
/* It is possible that the time left until the target time is less
* than a tick period. However, we let usleep() to sleep for an
* entire tick period. This, could result in usleep() sleeping for
* a longer time than the requested time but that does not violate
* the spec of usleep(). Additionally, it allows FreeRTOS to schedule
* other tasks while the current task is sleeping.
*/
} while (now_us < target_us);
} }
return 0; return 0;
} }