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"
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
*/
@ -14,6 +14,9 @@
#include "unity.h"
#include "unity_test_utils.h"
#include "soc/soc.h"
#include <chrono>
#include <thread>
#include "esp_timer.h"
extern "C" void setUp()
{
@ -197,7 +200,7 @@ struct PriorityInitTest {
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)
PriorityInitTest g_static_init_priority_test2;
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();
}
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)
{
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;
TEST_ESP_OK(pcnt_unit_clear_count(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_get_count(pwm_pcnt_unit, &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
*/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include "unity.h"
#include <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
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]")
{
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
*/
@ -207,10 +207,26 @@ int usleep(useconds_t us)
if (us < us_per_tick) {
esp_rom_delay_us((uint32_t) us);
} else {
/* since vTaskDelay(1) blocks for anywhere between 0 and portTICK_PERIOD_MS,
* round up to compensate.
*/
vTaskDelay((us + us_per_tick - 1) / us_per_tick);
/* vTaskDelay may return up to (n-1) tick periods due to the tick ISR
being asynchronous to the call. We must sleep at least the specified
time, or longer. Checking the monotonic clock allows making an
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;
}