Merge branch 'contrib/github_pr_15132' into 'master'

fix(newlib): usleep returning early (GitHub PR)

Closes IDFGH-14342

See merge request espressif/esp-idf!38483
This commit is contained in:
Sudeep Mohanty
2025-04-24 16:35:36 +08:00
4 changed files with 70 additions and 7 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()
{
@@ -319,6 +322,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)
{
s_testTLS.foo(); /* allocates memory that will be reused */

View File

@@ -207,10 +207,25 @@ 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();
/* If the time left until the target is less than 1 tick, then we use ROM delay to fill the gap */
uint64_t time_left = target_us - now_us;
if (time_left != 0 && time_left < us_per_tick) {
esp_rom_delay_us(time_left);
break;
}
} while (now_us < target_us);
}
return 0;
}

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>
@@ -77,6 +78,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;