From a7a7449436c0e940a7388d88f04c25a9400c3c72 Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Thu, 29 Jan 2026 15:48:01 +0800 Subject: [PATCH 1/9] ostest/hrtimer: Add missing assert.h This commit added missing assert.h. Signed-off-by: ouyangxiangzhen --- testing/ostest/hrtimer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/ostest/hrtimer.c b/testing/ostest/hrtimer.c index 48ed46b9904..4cd9eb15704 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include From 463add50d2d0bf23d09937870657ad0723029b42 Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Thu, 29 Jan 2026 15:51:19 +0800 Subject: [PATCH 2/9] ostest/hrtimer: Remove HRTIMER_TEST to simplify the code. This commit removed HRTIMER_TEST to simplify the code. Signed-off-by: ouyangxiangzhen --- testing/ostest/hrtimer.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/testing/ostest/hrtimer.c b/testing/ostest/hrtimer.c index 4cd9eb15704..5b2961179ca 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -59,20 +59,6 @@ #define HRTIMER_TEST_MARGIN (NSEC_PER_MSEC) -/* Simple assertion macro for HRTimer test cases */ -#define HRTIMER_TEST(expr, value) \ - do \ - { \ - ret = (expr); \ - if (ret != (value)) \ - { \ - printf("ERROR: HRTimer test failed, line=%d ret=%d\n", \ - __LINE__, ret); \ - ASSERT(false); \ - } \ - } \ - while (0) - /**************************************************************************** * Private Types ****************************************************************************/ @@ -167,8 +153,8 @@ test_hrtimer_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) diff = (uint32_t)(now - test->previous); - HRTIMER_TEST(NSEC_PER_50MS < diff + HRTIMER_TEST_MARGIN, true); - HRTIMER_TEST(NSEC_PER_50MS > diff - HRTIMER_TEST_MARGIN, true); + ASSERT(NSEC_PER_50MS < diff + HRTIMER_TEST_MARGIN); + ASSERT(NSEC_PER_50MS > diff - HRTIMER_TEST_MARGIN); } test->previous = now; @@ -224,25 +210,24 @@ static void * hrtimer_test_thread(void *arg) /* Cancel timer */ ret = hrtimer_cancel(&timer); - HRTIMER_TEST(ret >= 0, true); + ASSERT(ret == OK); /* Start timer with fixed period */ ret = hrtimer_start(&timer, hrtimer_test_callback, 10 * NSEC_PER_USEC, HRTIMER_MODE_REL); - HRTIMER_TEST(ret, OK); + ASSERT(ret == OK); /* Start timer with random delay */ ret = hrtimer_start(&timer, hrtimer_test_callback, delay, HRTIMER_MODE_REL); - HRTIMER_TEST(ret, OK); + ASSERT(ret == OK); } /* Cancel the timer synchronously */ - ret = hrtimer_cancel_sync(&timer); - HRTIMER_TEST(ret >= 0, true); + ASSERT(hrtimer_cancel_sync(&timer) == OK); return NULL; } @@ -293,7 +278,8 @@ void hrtimer_test(void) hrtimer_test.period, HRTIMER_MODE_REL); - HRTIMER_TEST(ret, OK); + ASSERT(ret == OK); + /* Wait until the test completes */ @@ -309,8 +295,8 @@ void hrtimer_test(void) for (thread_id = 0; thread_id < HRTIMER_TEST_THREAD_NR; thread_id++) { - HRTIMER_TEST(pthread_create(&pthreads[thread_id], &attr, - hrtimer_test_thread, NULL), 0); + ASSERT(pthread_create(&pthreads[thread_id], &attr, + hrtimer_test_thread, NULL) == 0); } /* Wait for all threads to complete */ @@ -320,5 +306,5 @@ void hrtimer_test(void) pthread_join(pthreads[thread_id], NULL); } - HRTIMER_TEST(pthread_attr_destroy(&attr), 0); + ASSERT(pthread_attr_destroy(&attr) == 0); } From 76808cd4975498b394ade4603e560fe76241fcf4 Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Thu, 29 Jan 2026 16:02:10 +0800 Subject: [PATCH 3/9] sched/hrtimer: Simplify the hrtimer test. This commit simplified the hrtimer test. Signed-off-by: ouyangxiangzhen --- testing/ostest/hrtimer.c | 94 +++++++++++++--------------------------- 1 file changed, 29 insertions(+), 65 deletions(-) diff --git a/testing/ostest/hrtimer.c b/testing/ostest/hrtimer.c index 5b2961179ca..585c6f30a4b 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -65,43 +65,18 @@ /* Structure for HRTimer test tracking */ -struct hrtimer_test_s +typedef struct hrtimer_test_s { - hrtimer_t timer; /* HRTimer instance */ - uint64_t previous; /* Previous timestamp in nanoseconds */ - uint32_t count; /* Number of timer expirations */ - uint32_t period; /* Expected period between expirations */ - bool active; /* True while the test is still running */ -}; + struct hrtimer_s timer; /* HRTimer instance */ + volatile uint64_t timestamp; /* Previous timestamp in nanoseconds */ + volatile uint64_t count; /* Number of timer expirations */ + uint64_t period; /* Expected period between expirations */ +} hrtimer_test_t; /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: hrtimer_test_init - * - * Description: - * Initialize a hrtimer_test_s structure for a new test. - * - * Input Parameters: - * hrtimer_test - Pointer to the test structure to initialize - * period - Expected timer period in nanoseconds - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void hrtimer_test_init(FAR struct hrtimer_test_s *hrtimer_test, - uint32_t period) -{ - hrtimer_test->previous = 0; - hrtimer_test->count = 0; - hrtimer_test->active = true; - hrtimer_test->period = period; -} - /**************************************************************************** * Name: test_hrtimer_callback * @@ -129,8 +104,6 @@ test_hrtimer_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) uint64_t now; int ret; - UNUSED(expired); - FAR struct hrtimer_test_s *test = (FAR struct hrtimer_test_s *)hrtimer; @@ -151,13 +124,13 @@ test_hrtimer_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) * 500ms with nsec resolution */ - diff = (uint32_t)(now - test->previous); + diff = (uint32_t)(now - expired); ASSERT(NSEC_PER_50MS < diff + HRTIMER_TEST_MARGIN); ASSERT(NSEC_PER_50MS > diff - HRTIMER_TEST_MARGIN); } - test->previous = now; + test->timestamp = now; /* Stop the test after PERIOD_TEST_COUNT expirations */ @@ -196,11 +169,28 @@ hrtimer_test_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) static void * hrtimer_test_thread(void *arg) { - hrtimer_t timer; - int ret; - int i = 0; + hrtimer_test_t test; + int ret; + uint64_t stamp; + int i = 0; + hrtimer_t *timer = &test.timer; - hrtimer_init(&timer); + /* Initialize the high-resolution timer */ + + hrtimer_init(timer); + + /* Start the timer with 500ms relative timeout */ + + stamp = test.timestamp; + ASSERT(hrtimer_start(timer, test_hrtimer_callback, + NSEC_PER_50MS, HRTIMER_MODE_REL) == OK); + + /* Wait until the test completes */ + + while (test.timestamp != stamp) + { + usleep(USEC_PER_MSEC); + } while (i < THREAD_LOOP_COUNT) { @@ -260,34 +250,8 @@ void hrtimer_test(void) unsigned int thread_id; pthread_attr_t attr; pthread_t pthreads[HRTIMER_TEST_THREAD_NR]; - struct hrtimer_test_s hrtimer_test; int ret; - /* Initialize test structure */ - - hrtimer_test_init(&hrtimer_test, NSEC_PER_50MS); - - /* Initialize the high-resolution timer */ - - hrtimer_init(&hrtimer_test.timer); - - /* Start the timer with 500ms relative timeout */ - - ret = hrtimer_start(&hrtimer_test.timer, - test_hrtimer_callback, - hrtimer_test.period, - HRTIMER_MODE_REL); - - ASSERT(ret == OK); - - - /* Wait until the test completes */ - - while (hrtimer_test.active) - { - usleep(USEC_PER_MSEC); - } - pthread_attr_init(&attr); sparam.sched_priority = PTHREAD_DEFAULT_PRIORITY; From 8c7db3a9b669f4ac621c745e8d9c06f9dd9f19b0 Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Thu, 29 Jan 2026 16:08:24 +0800 Subject: [PATCH 4/9] sched/hrtimer: Fix test in QEMU. This commit fixed the hrtimer test. In a QEMU environment, the hrtimer latency can be arbitrary because vCPUs can be preempted. We can not assert the latency. we can only issue alerts for excessively high latency. Signed-off-by: ouyangxiangzhen --- testing/ostest/hrtimer.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/testing/ostest/hrtimer.c b/testing/ostest/hrtimer.c index 585c6f30a4b..d82cf171a0e 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -100,9 +100,9 @@ static uint64_t test_hrtimer_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) { struct timespec ts; - uint32_t diff; + int64_t diff; uint64_t now; - int ret; + int ret; FAR struct hrtimer_test_s *test = (FAR struct hrtimer_test_s *)hrtimer; @@ -116,18 +116,20 @@ test_hrtimer_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) clock_systime_timespec(&ts); now = clock_time2nsec(&ts); - /* Skip comparison for first two invocations */ + /* Verify the timer interval is exactly + * 500ms with nsec resolution + */ - if (test->count > 2) - { - /* Verify the timer interval is exactly - * 500ms with nsec resolution - */ + diff = now - expired; - diff = (uint32_t)(now - expired); + /* Ensure the time diff is valid. */ - ASSERT(NSEC_PER_50MS < diff + HRTIMER_TEST_MARGIN); - ASSERT(NSEC_PER_50MS > diff - HRTIMER_TEST_MARGIN); + ASSERT(diff >= 0); + + if (diff > HRTIMER_TEST_MARGIN) + { + printf("hrtimer_test: warning diff=%" PRIu64 " > %" PRIu64 "\n", + diff, HRTIMER_TEST_MARGIN); } test->timestamp = now; From 0032748085aa2d94644b044668a8b1172410409e Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Thu, 29 Jan 2026 16:13:52 +0800 Subject: [PATCH 5/9] sched/hrtimer: relocate the hrtimer test to simplify. This commit relocated the hrtimer test to simplify the code. Signed-off-by: ouyangxiangzhen --- testing/ostest/CMakeLists.txt | 7 +++---- testing/ostest/Makefile | 10 ++++------ testing/ostest/ostest.h | 10 ++++++---- testing/ostest/ostest_main.c | 16 ++++++++-------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/testing/ostest/CMakeLists.txt b/testing/ostest/CMakeLists.txt index 6096c7ce68d..fba7f4c47fc 100644 --- a/testing/ostest/CMakeLists.txt +++ b/testing/ostest/CMakeLists.txt @@ -157,16 +157,15 @@ if(CONFIG_TESTING_OSTEST) list(APPEND SRCS nxevent.c) endif() - if(CONFIG_HRTIMER AND CONFIG_BUILD_FLAT) - list(APPEND SRCS hrtimer.c) - endif() - if(CONFIG_ARCH_HAVE_PERF_EVENTS) list(APPEND SRCS perf_gettime.c) endif() if(CONFIG_BUILD_FLAT) list(APPEND SRCS wdog.c spinlock.c) + if(CONFIG_HRTIMER) + list(APPEND SRCS hrtimer.c) + endif() endif() set(OSTEST_SRCS ostest_main.c ${SRCS}) diff --git a/testing/ostest/Makefile b/testing/ostest/Makefile index 1f6a28b2f32..6fc3a7b7613 100644 --- a/testing/ostest/Makefile +++ b/testing/ostest/Makefile @@ -160,18 +160,16 @@ CSRCS += nxevent.c endif endif -ifeq ($(CONFIG_HRTIMER),y) -ifeq ($(CONFIG_BUILD_FLAT),y) -CSRCS += hrtimer.c -endif -endif - ifeq ($(CONFIG_ARCH_HAVE_PERF_EVENTS),y) CSRCS += perf_gettime.c endif ifeq ($(CONFIG_BUILD_FLAT),y) CSRCS += wdog.c spinlock.c + +ifeq ($(CONFIG_HRTIMER),y) +CSRCS += hrtimer.c +endif endif include $(APPDIR)/Application.mk diff --git a/testing/ostest/ostest.h b/testing/ostest/ostest.h index f4f09ca8b1d..0fb2b8d3121 100644 --- a/testing/ostest/ostest.h +++ b/testing/ostest/ostest.h @@ -215,6 +215,12 @@ void suspend_test(void); void wdog_test(void); +/* hrtimer.c ****************************************************************/ + +#ifdef CONFIG_HRTIMER +void hrtimer_test(void); +#endif + /* posixtimers.c ************************************************************/ void timer_test(void); @@ -314,8 +320,4 @@ int sem_nfreeholders(void); void nxevent_test(void); #endif -#if defined(CONFIG_HRTIMER) && defined(CONFIG_BUILD_FLAT) -void hrtimer_test(void); -#endif - #endif /* __APPS_TESTING_OSTEST_OSTEST_H */ diff --git a/testing/ostest/ostest_main.c b/testing/ostest/ostest_main.c index c711a8db6ab..89022b4bcec 100644 --- a/testing/ostest/ostest_main.c +++ b/testing/ostest/ostest_main.c @@ -555,6 +555,14 @@ static int user_main(int argc, char *argv[]) printf("\nuser_main: wdog test\n"); wdog_test(); check_test_memory_usage(); + + /* Verify hrtimer */ + +# ifdef CONFIG_HRTIMER + printf("\nuser_main: hrtimer test\n"); + hrtimer_test(); + check_test_memory_usage(); +# endif #endif #if !defined(CONFIG_DISABLE_POSIX_TIMERS) && \ @@ -643,14 +651,6 @@ static int user_main(int argc, char *argv[]) check_test_memory_usage(); #endif -#if defined(CONFIG_HRTIMER) && defined(CONFIG_BUILD_FLAT) - /* Verify hrtimer */ - - printf("\nuser_main: hrtimer test\n"); - hrtimer_test(); - check_test_memory_usage(); -#endif - /* Compare memory usage at time ostest_main started until * user_main exits. These should not be identical, but should * be similar enough that we can detect any serious OS memory From 7d49ed5d0e5d4f639fa243d63a9ff78164691844 Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Thu, 29 Jan 2026 16:18:14 +0800 Subject: [PATCH 6/9] sched/hrtimer: Improve code readability This commit improved the code readability. Signed-off-by: ouyangxiangzhen --- testing/ostest/hrtimer.c | 45 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/testing/ostest/hrtimer.c b/testing/ostest/hrtimer.c index d82cf171a0e..eedd53b8671 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -41,23 +41,22 @@ /* Timer constants */ -#define NSEC_PER_50MS (50 * NSEC_PER_MSEC) -#define PERIOD_TEST_COUNT 15 -#define THREAD_LOOP_COUNT 50 -#define HRTIMER_TEST_THREAD_NR (CONFIG_SMP_NCPUS * 5) +#define HRTIMER_PERIOD_TEST_NR 15 +#define HRTIMER_THREAD_LOOP_NR 50 +#define HRTIMER_TEST_THREAD_NR (CONFIG_SMP_NCPUS * 5) -/* Set a 1ms margin to allow hrtimertest to pass in QEMU. +/* Set a 1ms latency to allow hrtimertest to pass in QEMU. * * QEMU is a virtual platform, and its timer resolution and scheduling * latency may be less precise than on real hardware. Using a larger - * margin ensures that tests do not fail due to timing inaccuracies. + * latency ensures that tests do not fail due to timing inaccuracies. * * On real hardware (verified on the a2g-tc397-5v-tft board), this - * margin can be reduced to less than 5 ns because timers are precise + * latency can be reduced to less than 5 ns because timers are precise * and deterministic. */ -#define HRTIMER_TEST_MARGIN (NSEC_PER_MSEC) +#define HRTIMER_TEST_TOLERENT_LATENCY (NSEC_PER_MSEC) /**************************************************************************** * Private Types @@ -126,17 +125,17 @@ test_hrtimer_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) ASSERT(diff >= 0); - if (diff > HRTIMER_TEST_MARGIN) + if (diff > HRTIMER_TEST_TOLERENT_LATENCY) { printf("hrtimer_test: warning diff=%" PRIu64 " > %" PRIu64 "\n", - diff, HRTIMER_TEST_MARGIN); + diff, HRTIMER_TEST_TOLERENT_LATENCY); } test->timestamp = now; - /* Stop the test after PERIOD_TEST_COUNT expirations */ + /* Stop the test after HRTIMER_PERIOD_TEST_NR expirations */ - if (test->count < PERIOD_TEST_COUNT) + if (test->count < HRTIMER_PERIOD_TEST_NR) { return test->period; } @@ -174,7 +173,7 @@ static void * hrtimer_test_thread(void *arg) hrtimer_test_t test; int ret; uint64_t stamp; - int i = 0; + int loop_cnt = 0; hrtimer_t *timer = &test.timer; /* Initialize the high-resolution timer */ @@ -185,7 +184,7 @@ static void * hrtimer_test_thread(void *arg) stamp = test.timestamp; ASSERT(hrtimer_start(timer, test_hrtimer_callback, - NSEC_PER_50MS, HRTIMER_MODE_REL) == OK); + 50 * NSEC_PER_MSEC, HRTIMER_MODE_REL) == OK); /* Wait until the test completes */ @@ -194,9 +193,8 @@ static void * hrtimer_test_thread(void *arg) usleep(USEC_PER_MSEC); } - while (i < THREAD_LOOP_COUNT) + while (loop_cnt++ < HRTIMER_THREAD_LOOP_NR) { - i++; uint64_t delay = rand() % NSEC_PER_MSEC; /* Cancel timer */ @@ -249,15 +247,16 @@ static void * hrtimer_test_thread(void *arg) void hrtimer_test(void) { struct sched_param sparam; - unsigned int thread_id; - pthread_attr_t attr; - pthread_t pthreads[HRTIMER_TEST_THREAD_NR]; - int ret; + unsigned int thread_id; + pthread_attr_t attr; + pthread_t pthreads[HRTIMER_TEST_THREAD_NR]; - pthread_attr_init(&attr); + printf("hrtimer_test start...\n"); + + ASSERT(pthread_attr_init(&attr) == 0); sparam.sched_priority = PTHREAD_DEFAULT_PRIORITY; - pthread_attr_setschedparam(&attr, &sparam); + ASSERT(pthread_attr_setschedparam(&attr, &sparam) == 0); for (thread_id = 0; thread_id < HRTIMER_TEST_THREAD_NR; thread_id++) { @@ -273,4 +272,6 @@ void hrtimer_test(void) } ASSERT(pthread_attr_destroy(&attr) == 0); + + printf("hrtimer_test end...\n"); } From 730a0e065c6848d43032b826f285054cf37a14eb Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Mon, 2 Feb 2026 16:17:22 +0800 Subject: [PATCH 7/9] ostest/hrtimer: Increase the tolerent latency. For QEMU, virtual CPUs can be preempted by any high priority thread in test environments. This can cause the timer to be triggered later than expected. This commit increased the tolerant latency to avoid the test failures. Signed-off-by: ouyangxiangzhen --- testing/ostest/hrtimer.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/testing/ostest/hrtimer.c b/testing/ostest/hrtimer.c index eedd53b8671..3cf847eb3ee 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -45,18 +45,22 @@ #define HRTIMER_THREAD_LOOP_NR 50 #define HRTIMER_TEST_THREAD_NR (CONFIG_SMP_NCPUS * 5) -/* Set a 1ms latency to allow hrtimertest to pass in QEMU. +/* Set the tolerent latency to 10ms to allow hrtimer_test to pass + * in QEMU. * - * QEMU is a virtual platform, and its timer resolution and scheduling - * latency may be less precise than on real hardware. Using a larger - * latency ensures that tests do not fail due to timing inaccuracies. + * QEMU is a virtual platform, vCPUs can be preempted by any + * high priority thread. This can cause the timer to be triggered + * later than expected. This is especially true on QEMU because it + * has a lot of overhead. The timer resolution is also less precise + * than on real hardware. Using a larger latency ensures that tests + * do not fail due to timing inaccuracies. * * On real hardware (verified on the a2g-tc397-5v-tft board), this * latency can be reduced to less than 5 ns because timers are precise * and deterministic. */ -#define HRTIMER_TEST_TOLERENT_LATENCY (NSEC_PER_MSEC) +#define HRTIMER_TEST_TOLERENT_LATENCY (10 * NSEC_PER_MSEC) /**************************************************************************** * Private Types From 88778c9e1bb93730598970c46089044069df3835 Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Wed, 25 Feb 2026 09:48:19 +0800 Subject: [PATCH 8/9] sched/hrtimer: Refactor the hrtimer_test. This commit refactored the hrtimer_test and provided significantly improved test-cases for both SMP and non-SMP. Signed-off-by: ouyangxiangzhen --- testing/ostest/hrtimer.c | 546 ++++++++++++++++++++++++++++++++------- 1 file changed, 453 insertions(+), 93 deletions(-) diff --git a/testing/ostest/hrtimer.c b/testing/ostest/hrtimer.c index 3cf847eb3ee..63040697c5c 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -41,9 +41,9 @@ /* Timer constants */ -#define HRTIMER_PERIOD_TEST_NR 15 -#define HRTIMER_THREAD_LOOP_NR 50 -#define HRTIMER_TEST_THREAD_NR (CONFIG_SMP_NCPUS * 5) +#define HRTIMER_TEST_RAND_ITER (1024 * 2) +#define HRTIMER_TEST_CSECTION 1024 +#define HRTIMER_TEST_THREAD_NR (CONFIG_SMP_NCPUS * 8) /* Set the tolerent latency to 10ms to allow hrtimer_test to pass * in QEMU. @@ -62,6 +62,8 @@ #define HRTIMER_TEST_TOLERENT_LATENCY (10 * NSEC_PER_MSEC) +#define hrtimer_test_ndelay(delay_ns) usleep(delay_ns / 1000 + 1) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -71,99 +73,458 @@ typedef struct hrtimer_test_s { struct hrtimer_s timer; /* HRTimer instance */ + spinlock_t lock; /* Spinlock */ volatile uint64_t timestamp; /* Previous timestamp in nanoseconds */ volatile uint64_t count; /* Number of timer expirations */ uint64_t period; /* Expected period between expirations */ + volatile uint8_t state; /* Test state */ } hrtimer_test_t; /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: test_hrtimer_callback - * - * Description: - * HRTimer callback function for test. - * - * - Verifies the timer interval is exactly 500ms (nanosecond precision) - * - Stops the test after 15 expirations - * - Re-arms the timer in absolute mode - * - * Input Parameters: - * hrtimer - Pointer to the expired HRTimer instance - * expired - The expired value of hrtimer - * - * Returned Value: - * Timer period in nanoseconds (NSEC_PER_50MS) - * - ****************************************************************************/ - -static uint64_t -test_hrtimer_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) +static uint64_t hrtimer_test_callback_oneshot(FAR const hrtimer_t *timer, + uint64_t expired_ns) { - struct timespec ts; - int64_t diff; - uint64_t now; - int ret; + FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; - FAR struct hrtimer_test_s *test = - (FAR struct hrtimer_test_s *)hrtimer; + /* Save the timestamp when the callback was triggered */ - /* Increment expiration count */ + param->timestamp = clock_systime_nsec(); - test->count++; + /* Increment the callback count */ - /* Get current system time */ + param->count++; - clock_systime_timespec(&ts); - now = clock_time2nsec(&ts); - - /* Verify the timer interval is exactly - * 500ms with nsec resolution - */ + return 0; +} - diff = now - expired; +static void hrtimer_test_checkdelay(uint64_t timestamp, uint64_t expected) +{ + int64_t diff = timestamp - expected; - /* Ensure the time diff is valid. */ + /* Ensure the hrtimer trigger time is not earlier than expected. */ ASSERT(diff >= 0); + /* If the timer latency exceeds the tolerance, print a warning. */ + if (diff > HRTIMER_TEST_TOLERENT_LATENCY) { - printf("hrtimer_test: warning diff=%" PRIu64 " > %" PRIu64 "\n", - diff, HRTIMER_TEST_TOLERENT_LATENCY); + printf("hrtimer_test: [WARNING] hrtimer latency %" PRId64 + " is too late!!! (> %u)\n", diff, + (unsigned)HRTIMER_TEST_TOLERENT_LATENCY); } +} + +static void hrtimer_test_oneshot(FAR hrtimer_test_t *param, uint64_t delay) +{ + uint64_t count; + uint64_t now; + FAR hrtimer_t *timer = ¶m->timer; + + printf("hrtimer_test_oneshot %" PRIu64 " ns\n", delay); + + /* Save the current callback count. */ + + count = param->count; - test->timestamp = now; + /* Save the current system time. */ - /* Stop the test after HRTIMER_PERIOD_TEST_NR expirations */ + now = clock_systime_nsec(); - if (test->count < HRTIMER_PERIOD_TEST_NR) + ASSERT(hrtimer_start(timer, hrtimer_test_callback_oneshot, + delay + now, HRTIMER_MODE_ABS) == OK); + + /* Wait until the callback is triggered exactly once. */ + + while (count + 1 != param->count) { - return test->period; + hrtimer_test_ndelay(delay); } - else + + /* Check if the delay is within the acceptable tolerance. */ + + hrtimer_test_checkdelay(param->timestamp, now + delay); + + /* Cancel the timer. */ + + hrtimer_cancel_sync(timer); +} + +static void hrtimer_test_maximum(FAR hrtimer_test_t *param) +{ + uint64_t count; + uint64_t rest; + FAR hrtimer_t *timer = ¶m->timer; + + count = param->count; + + /* Start the hrtimer with maximum */ + + ASSERT(hrtimer_start(timer, hrtimer_test_callback_oneshot, UINT64_MAX, + HRTIMER_MODE_REL) == OK); + + /* Sleep for at least 1s */ + + hrtimer_test_ndelay(USEC_PER_SEC / 100); + + /* Ensure hrtimer is not alarmed */ + + ASSERT(count == param->count); + + rest = hrtimer_gettime(timer); + + ASSERT(rest < UINT64_MAX); + + ASSERT(hrtimer_cancel_sync(timer) == OK); + + printf("hrtimer_start with maximum delay, rest %" PRIu64 "\n", rest); +} + +static void hrtimer_test_rand(FAR hrtimer_test_t *param, uint64_t rand_ns) +{ + uint64_t count; + uint64_t now; + unsigned int idx; + uint64_t delay; + irqstate_t flags; + FAR hrtimer_t *timer = ¶m->timer; + + printf("hrtimer_test_rand %" PRIu64 " ns\n", rand_ns); + + /* Perform multiple iterations with random delays. */ + + for (idx = 0; idx < HRTIMER_TEST_RAND_ITER; idx++) { - test->active = false; - return 0; + /* Generate a random delay within the specified range. */ + + delay = rand() % rand_ns; + + ASSERT(timer->func == NULL); + + /* Enter critical section if the callback count is odd. */ + + count = param->count; + + if (count % 2u) + { + flags = up_irq_save(); + } + + now = clock_systime_nsec(); + ASSERT(hrtimer_start(timer, hrtimer_test_callback_oneshot, + delay, HRTIMER_MODE_REL) == 0); + if (count % 2u) + { + up_irq_restore(flags); + } + + /* Decide to wait for the callback or cancel the hrtimer. */ + + if (delay % 2u) + { + /* Wait for the callback. */ + + while (count + 1u != param->count) + { + hrtimer_test_ndelay(delay); + } + + /* Check the delay if the callback count is odd. */ + + if (count % 2u) + { + hrtimer_test_checkdelay(param->timestamp, now + delay); + } + } + + hrtimer_cancel_sync(timer); + ASSERT(timer->func == NULL); } + + hrtimer_cancel_sync(timer); } -/**************************************************************************** - * Name: hrtimer_test_callback - * - * Description: - * Simple HRTimer callback for threaded tests. - * - ****************************************************************************/ +static uint64_t hrtimer_test_cancel_callback(FAR const hrtimer_t *timer, + uint64_t expired_ns) +{ + FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; + FAR spinlock_t *lock = ¶m->lock; + uint64_t delay = 0; + irqstate_t flags = spin_lock_irqsave(lock); + + /* Random sleep */ + + delay = expired_ns % param->period; + + /* Check if the version is same. */ -static uint64_t -hrtimer_test_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) + if (expired_ns == timer->expired) + { + param->timestamp = clock_systime_nsec(); + + /* Increment the callback count */ + + param->count++; + } + + spin_unlock_irqrestore(lock, flags); + + up_ndelay(delay); + + return 0; +} + +static void hrtimer_test_rand_cancel(FAR hrtimer_test_t *param, + uint64_t rand_ns) { + uint64_t now; + unsigned int idx; + uint64_t count; + uint64_t delay; + irqstate_t flags; + spinlock_t *lock = ¶m->lock; + + printf("hrtimer_test_rand cancel %" PRIu64 " ns\n", rand_ns); + + param->period = rand_ns; + + /* Perform multiple iterations with random delays. */ + + for (idx = 0; idx < HRTIMER_TEST_RAND_ITER; idx++) + { + /* Generate a random delay within the specified range. */ + + delay = rand() % rand_ns; + + flags = spin_lock_irqsave(lock); + + now = clock_systime_nsec(); + count = param->count; + ASSERT(hrtimer_start(¶m->timer, hrtimer_test_cancel_callback, + delay, HRTIMER_MODE_REL) == 0); + + spin_unlock_irqrestore(lock, flags); + + /* Decide to wait for the callback or cancel the hrtimer. */ + + if (delay % 2u) + { + /* Wait for the callback finished. */ + + while (param->count != count + 1u) + { + hrtimer_test_ndelay(delay); + } + + hrtimer_test_checkdelay(param->timestamp, now + delay); + } + + hrtimer_cancel(¶m->timer); + } + + hrtimer_cancel_sync(¶m->timer); +} + +static uint64_t hrtimer_test_callback_period(FAR const hrtimer_t *timer, + uint64_t expired_ns) +{ + FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; + uint64_t interval = param->period; + + param->count++; + param->timestamp = clock_systime_nsec(); + + return interval; +} + +static void hrtimer_test_period(FAR hrtimer_test_t *param, + uint64_t delay_ns, + unsigned int iters) +{ + uint64_t timestamp; + uint64_t count = param->count; + FAR hrtimer_t *timer = ¶m->timer; + + printf("hrtimer_test_period %" PRIu64 " ns\n", delay_ns); + + param->period = delay_ns; + ASSERT(param->period > 0); + + timestamp = clock_systime_nsec(); + + ASSERT(hrtimer_start(timer, hrtimer_test_callback_period, + delay_ns, HRTIMER_MODE_REL) == OK); + + hrtimer_test_ndelay(iters * delay_ns); + + hrtimer_cancel_sync(timer); + ASSERT(timer->func == NULL); + + printf("periodical hrtimer triggered %" PRIu64 " times, " + "elapsed nsec %" PRIu64 "\n", param->count - count, + param->timestamp - timestamp); + + if (param->count - count < iters) + { + printf("hrtimer_test: [WARNING] periodical hrtimer" + "triggered times < %u\n", iters); + } +} + +#ifdef CONFIG_SMP +static uint64_t hrtimer_test_callback_crita(FAR const hrtimer_t *timer, + uint64_t expired_ns) +{ + FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; + + /* change status */ + + if (param->state == 0) + { + param->state = 1; + param->count++; + } + + /* check whether parameter be changed by another critical section */ + + ASSERT(param->state == 1); + param->state = 0; + return 0; } +static uint64_t hrtimer_test_callback_critb(FAR const hrtimer_t *timer, + uint64_t expired_ns) +{ + FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; + + /* change status */ + + if (param->state == 1) + { + param->state = 0; + param->count++; + } + + /* check whether parameter be changed by another critical section */ + + ASSERT(param->state == 0); + param->state = 1; + + return 0; +} + +static uint64_t hrtimer_test_callback_critdelay(FAR const hrtimer_t *timer, + uint64_t expired_ns) +{ + FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; + FAR spinlock_t *lock = ¶m->lock; + irqstate_t flags; + + flags = spin_lock_irqsave(lock); + param->count++; + spin_unlock_irqrestore(lock, flags); + + up_ndelay(100 * NSEC_PER_USEC); + + return 300 * NSEC_PER_USEC; +} + +static void hrtimer_test_cancel_sync(FAR hrtimer_test_t *param) +{ + unsigned int idx = 0; + + ASSERT(!param->timer.func); + + param->count = 0; + + /* This test is to validate if the hrtimer can ensure the + * callback function be finished after the hrtimer_cancel_sync + * is called. + */ + + for (idx = 0; idx < HRTIMER_TEST_CSECTION; ) + { + param->state = 0; + hrtimer_start(¶m->timer, hrtimer_test_callback_crita, + 0, HRTIMER_MODE_REL); + + hrtimer_cancel_sync(¶m->timer); + param->state = 1; + hrtimer_start(¶m->timer, hrtimer_test_callback_critb, + 0, HRTIMER_MODE_REL); + + if (++idx % (HRTIMER_TEST_CSECTION / 4) == 0) + { + printf("hrtimer_test_cancel_sync passed %d times.\n", idx); + } + + hrtimer_cancel_sync(¶m->timer); + } +} + +static void hrtimer_test_cancel_periodic(FAR hrtimer_test_t *param) +{ + uint64_t count; + unsigned int idx = 0; + FAR spinlock_t *lock = ¶m->lock; + + ASSERT(!param->timer.func); + + param->count = 0; + + /* This test to check if the hrtimer can ensure the perodical callback + * can not restart the timer again after the hrtimer_cancel_sync is + * called. + */ + + for (idx = 0; idx < HRTIMER_TEST_CSECTION; idx++) + { + irqstate_t flags = spin_lock_irqsave(lock); + + hrtimer_start(¶m->timer, hrtimer_test_callback_critdelay, + 0, HRTIMER_MODE_REL); + + spin_unlock_irqrestore(lock, flags); + + up_ndelay(10000); + + flags = spin_lock_irqsave(lock); + + hrtimer_start(¶m->timer, hrtimer_test_callback_critdelay, + 0, HRTIMER_MODE_REL); + + spin_unlock_irqrestore(lock, flags); + + hrtimer_cancel(¶m->timer); + + up_ndelay(10000); + + /* The hrtimer should not be restarted again after the cancellation. */ + + ASSERT(!param->timer.func); + + hrtimer_cancel_sync(¶m->timer); + count = param->count; + + hrtimer_test_ndelay(10000); + + ASSERT(count == param->count); + + if (++idx % (HRTIMER_TEST_CSECTION / 4) == 0) + { + printf("hrtimer_test_cancel_periodic passed %d times. count %" + PRIu64 "\n", idx, param->count); + } + } + + hrtimer_cancel_sync(¶m->timer); +} +#endif + /**************************************************************************** * Name: hrtimer_test_thread * @@ -174,56 +535,55 @@ hrtimer_test_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) static void * hrtimer_test_thread(void *arg) { - hrtimer_test_t test; - int ret; - uint64_t stamp; - int loop_cnt = 0; - hrtimer_t *timer = &test.timer; + hrtimer_test_t param = + { + 0 + }; - /* Initialize the high-resolution timer */ + hrtimer_init(¶m.timer); - hrtimer_init(timer); + /* Delay = 0 */ - /* Start the timer with 500ms relative timeout */ + hrtimer_test_oneshot(¶m, 0u); - stamp = test.timestamp; - ASSERT(hrtimer_start(timer, test_hrtimer_callback, - 50 * NSEC_PER_MSEC, HRTIMER_MODE_REL) == OK); + /* 0 < Delay < 10000 */ - /* Wait until the test completes */ + hrtimer_test_oneshot(¶m, 1u); + hrtimer_test_oneshot(¶m, 10u); + hrtimer_test_oneshot(¶m, 100u); + hrtimer_test_oneshot(¶m, 1000u); + hrtimer_test_oneshot(¶m, 10000u); - while (test.timestamp != stamp) - { - usleep(USEC_PER_MSEC); - } + /* 10000 < Delay < 10000000 */ - while (loop_cnt++ < HRTIMER_THREAD_LOOP_NR) - { - uint64_t delay = rand() % NSEC_PER_MSEC; + hrtimer_test_oneshot(¶m, 100000u); + hrtimer_test_oneshot(¶m, 1000000u); + hrtimer_test_oneshot(¶m, 10000000u); - /* Cancel timer */ +#ifdef CONFIG_SMP + /* Test hrtimer_cancel_sync */ - ret = hrtimer_cancel(&timer); - ASSERT(ret == OK); + hrtimer_test_cancel_sync(¶m); - /* Start timer with fixed period */ + /* Test hrtimer_cancel */ - ret = hrtimer_start(&timer, hrtimer_test_callback, - 10 * NSEC_PER_USEC, HRTIMER_MODE_REL); - ASSERT(ret == OK); + hrtimer_test_cancel_periodic(¶m); +#endif - /* Start timer with random delay */ + /* Maximum hrtimer delay test. */ - ret = hrtimer_start(&timer, hrtimer_test_callback, - delay, HRTIMER_MODE_REL); - ASSERT(ret == OK); - } + hrtimer_test_maximum(¶m); + + /* Period hrtimer delay 100000ns */ - /* Cancel the timer synchronously */ + hrtimer_test_period(¶m, 1000000u, 128u); - ASSERT(hrtimer_cancel_sync(&timer) == OK); + /* Random delay 12345ns and 67890ns */ - return NULL; + hrtimer_test_rand(¶m, 12345u); + hrtimer_test_rand_cancel(¶m, 67890u); + + return 0; } /**************************************************************************** From d9ed169d05961fd24be94cfa21e478d0fb1deb24 Mon Sep 17 00:00:00 2001 From: ouyangxiangzhen Date: Wed, 25 Feb 2026 10:01:21 +0800 Subject: [PATCH 9/9] ostest/hrtimer: Update the comments. This commit updated the comments. Signed-off-by: ouyangxiangzhen --- testing/ostest/hrtimer.c | 388 ++++++++++++++++++++++++++++++++------- 1 file changed, 322 insertions(+), 66 deletions(-) diff --git a/testing/ostest/hrtimer.c b/testing/ostest/hrtimer.c index 63040697c5c..3220ef2db7b 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -39,14 +39,13 @@ * Pre-processor Definitions ****************************************************************************/ -/* Timer constants */ +/* HRTimer test constants */ -#define HRTIMER_TEST_RAND_ITER (1024 * 2) -#define HRTIMER_TEST_CSECTION 1024 -#define HRTIMER_TEST_THREAD_NR (CONFIG_SMP_NCPUS * 8) +#define HRTIMER_TEST_RAND_ITER (1024 * 2) /* Random delay iterations */ +#define HRTIMER_TEST_CSECTION 1024 /* Critical section iterations */ +#define HRTIMER_TEST_THREAD_NR (CONFIG_SMP_NCPUS * 8) /* Test threads */ -/* Set the tolerent latency to 10ms to allow hrtimer_test to pass - * in QEMU. +/* Tolerable latency for timer expiration * * QEMU is a virtual platform, vCPUs can be preempted by any * high priority thread. This can cause the timer to be triggered @@ -62,7 +61,9 @@ #define HRTIMER_TEST_TOLERENT_LATENCY (10 * NSEC_PER_MSEC) -#define hrtimer_test_ndelay(delay_ns) usleep(delay_ns / 1000 + 1) +/* Helper macro for nanosecond delay */ + +#define hrtimer_test_ndelay(delay_ns) usleep((delay_ns) / 1000 + 1) /**************************************************************************** * Private Types @@ -73,23 +74,40 @@ typedef struct hrtimer_test_s { struct hrtimer_s timer; /* HRTimer instance */ - spinlock_t lock; /* Spinlock */ + spinlock_t lock; /* Spinlock for thread-safe operations */ volatile uint64_t timestamp; /* Previous timestamp in nanoseconds */ volatile uint64_t count; /* Number of timer expirations */ uint64_t period; /* Expected period between expirations */ - volatile uint8_t state; /* Test state */ + volatile uint8_t state; /* Test state (used for synchronization tests) */ } hrtimer_test_t; /**************************************************************************** * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: hrtimer_test_callback_oneshot + * + * Description: + * One-shot timer callback function. This callback is invoked when a + * one-shot HRTimer expires. It records the exact timestamp and increments + * the expiration counter. + * + * Input Parameters: + * timer - Pointer to the HRTimer instance + * expired_ns - Time when the timer expired (unused) + * + * Returned Value: + * 0 (oneshot hrtimer) + * + ****************************************************************************/ + static uint64_t hrtimer_test_callback_oneshot(FAR const hrtimer_t *timer, uint64_t expired_ns) { FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; - /* Save the timestamp when the callback was triggered */ + /* Record the exact timestamp when the callback was triggered */ param->timestamp = clock_systime_nsec(); @@ -100,6 +118,24 @@ static uint64_t hrtimer_test_callback_oneshot(FAR const hrtimer_t *timer, return 0; } +/**************************************************************************** + * Name: hrtimer_test_checkdelay + * + * Description: + * Check timer delay against tolerance threshold. This function verifies + * that the actual timer expiration time is within the acceptable + * tolerance. + * It warns if the delay exceeds the threshold. + * + * Input Parameters: + * timestamp - Actual expiration timestamp (nanoseconds) + * expected - Expected expiration timestamp (nanoseconds) + * + * Returned Value: + * None. + * + ****************************************************************************/ + static void hrtimer_test_checkdelay(uint64_t timestamp, uint64_t expected) { int64_t diff = timestamp - expected; @@ -113,76 +149,131 @@ static void hrtimer_test_checkdelay(uint64_t timestamp, uint64_t expected) if (diff > HRTIMER_TEST_TOLERENT_LATENCY) { printf("hrtimer_test: [WARNING] hrtimer latency %" PRId64 - " is too late!!! (> %u)\n", diff, + " ns is too late (> %u ns)\n", diff, (unsigned)HRTIMER_TEST_TOLERENT_LATENCY); } } +/**************************************************************************** + * Name: hrtimer_test_oneshot + * + * Description: + * Test one-shot HRTimer functionality. This function tests a one-shot + * HRTimer by starting it with a specified delay and verifying that it + * expires at the expected time. + * + * Input Parameters: + * param - Test context structure containing timer and state information + * delay - Delay in nanoseconds for the one-shot timer + * + * Returned Value: + * None. + * + ****************************************************************************/ + static void hrtimer_test_oneshot(FAR hrtimer_test_t *param, uint64_t delay) { uint64_t count; uint64_t now; FAR hrtimer_t *timer = ¶m->timer; - printf("hrtimer_test_oneshot %" PRIu64 " ns\n", delay); + printf("hrtimer_test_oneshot: delay = %" PRIu64 " ns\n", delay); - /* Save the current callback count. */ + /* Save the current callback count and system time */ count = param->count; - - /* Save the current system time. */ - now = clock_systime_nsec(); + /* Start the one-shot timer */ + ASSERT(hrtimer_start(timer, hrtimer_test_callback_oneshot, delay + now, HRTIMER_MODE_ABS) == OK); - /* Wait until the callback is triggered exactly once. */ + /* Wait until the callback is triggered exactly once */ while (count + 1 != param->count) { hrtimer_test_ndelay(delay); } - /* Check if the delay is within the acceptable tolerance. */ + /* Verify the delay is within acceptable tolerance */ hrtimer_test_checkdelay(param->timestamp, now + delay); - /* Cancel the timer. */ + /* Cancel the timer to clean up */ hrtimer_cancel_sync(timer); } +/**************************************************************************** + * Name: hrtimer_test_maximum + * + * Description: + * Test HRTimer with maximum delay value. This function tests the behavior + * of HRTimer when started with the maximum possible delay (UINT64_MAX + * nanoseconds). The timer should not expire within a reasonable test + * period. + * + * Input Parameters: + * param - Test context structure containing timer and state information + * + * Returned Value: + * None. + * + ****************************************************************************/ + static void hrtimer_test_maximum(FAR hrtimer_test_t *param) { uint64_t count; uint64_t rest; FAR hrtimer_t *timer = ¶m->timer; + printf("hrtimer_test_maximum: testing with UINT64_MAX delay\n"); + count = param->count; - /* Start the hrtimer with maximum */ + /* Start the hrtimer with maximum delay */ ASSERT(hrtimer_start(timer, hrtimer_test_callback_oneshot, UINT64_MAX, HRTIMER_MODE_REL) == OK); - /* Sleep for at least 1s */ + /* Sleep for at least 100ms to verify timer doesn't expire */ hrtimer_test_ndelay(USEC_PER_SEC / 100); - /* Ensure hrtimer is not alarmed */ + /* Ensure hrtimer has not expired (count should remain unchanged) */ ASSERT(count == param->count); + /* Get the remaining time until expiration */ + rest = hrtimer_gettime(timer); + /* Verify the remaining time is still large (less than UINT64_MAX) */ + ASSERT(rest < UINT64_MAX); + /* Cancel the timer */ + ASSERT(hrtimer_cancel_sync(timer) == OK); - printf("hrtimer_start with maximum delay, rest %" PRIu64 "\n", rest); + printf("hrtimer_test_maximum: remaining time = %" PRIu64 " ns\n", rest); } +/**************************************************************************** + * Name: hrtimer_test_rand + * + * Description: + * Test HRTimer with random delays. This function tests HRTimer behavior + * with random delay values within a specified range. It performs multiple + * iterations, testing both timer expiration and cancellation scenarios. + * + * Input Parameters: + * param - Test context structure containing timer and state information + * rand_ns - Maximum random delay value in nanoseconds + * + ****************************************************************************/ + static void hrtimer_test_rand(FAR hrtimer_test_t *param, uint64_t rand_ns) { uint64_t count; @@ -192,19 +283,19 @@ static void hrtimer_test_rand(FAR hrtimer_test_t *param, uint64_t rand_ns) irqstate_t flags; FAR hrtimer_t *timer = ¶m->timer; - printf("hrtimer_test_rand %" PRIu64 " ns\n", rand_ns); + printf("hrtimer_test_rand: max delay = %" PRIu64 " ns\n", rand_ns); - /* Perform multiple iterations with random delays. */ + /* Perform multiple iterations with random delays */ for (idx = 0; idx < HRTIMER_TEST_RAND_ITER; idx++) { - /* Generate a random delay within the specified range. */ + /* Generate a random delay within the specified range */ delay = rand() % rand_ns; ASSERT(timer->func == NULL); - /* Enter critical section if the callback count is odd. */ + /* Enter critical section if the callback count is odd */ count = param->count; @@ -221,18 +312,18 @@ static void hrtimer_test_rand(FAR hrtimer_test_t *param, uint64_t rand_ns) up_irq_restore(flags); } - /* Decide to wait for the callback or cancel the hrtimer. */ + /* Decide to wait for the callback or cancel the hrtimer */ if (delay % 2u) { - /* Wait for the callback. */ + /* Wait for the callback */ while (count + 1u != param->count) { hrtimer_test_ndelay(delay); } - /* Check the delay if the callback count is odd. */ + /* Check the delay if the callback count is odd */ if (count % 2u) { @@ -247,6 +338,23 @@ static void hrtimer_test_rand(FAR hrtimer_test_t *param, uint64_t rand_ns) hrtimer_cancel_sync(timer); } +/**************************************************************************** + * Name: hrtimer_test_cancel_callback + * + * Description: + * Callback function for cancel test. This callback is used in the cancel + * test to simulate a long-running callback that can be interrupted by + * timer cancellation. + * + * Input Parameters: + * timer - Pointer to the HRTimer instance + * expired_ns - Time when the timer expired + * + * Returned Value: + * 0 (oneshot hrtimer) + * + ****************************************************************************/ + static uint64_t hrtimer_test_cancel_callback(FAR const hrtimer_t *timer, uint64_t expired_ns) { @@ -255,11 +363,11 @@ static uint64_t hrtimer_test_cancel_callback(FAR const hrtimer_t *timer, uint64_t delay = 0; irqstate_t flags = spin_lock_irqsave(lock); - /* Random sleep */ + /* Calculate random sleep delay based on period */ delay = expired_ns % param->period; - /* Check if the version is same. */ + /* Check if the expiration time matches (prevents duplicate processing) */ if (expired_ns == timer->expired) { @@ -272,11 +380,28 @@ static uint64_t hrtimer_test_cancel_callback(FAR const hrtimer_t *timer, spin_unlock_irqrestore(lock, flags); + /* Simulate work with random delay */ + up_ndelay(delay); return 0; } +/**************************************************************************** + * Name: hrtimer_test_rand_cancel + * + * Description: + * Test HRTimer cancellation with random delays. This function tests + * HRTimer cancellation behavior with random delay values. It verifies + * that timers can be properly cancelled and that callbacks behave + * correctly when cancellation occurs. + * + * Input Parameters: + * param - Test context structure containing timer and state information + * rand_ns - Maximum random delay value in nanoseconds + * + ****************************************************************************/ + static void hrtimer_test_rand_cancel(FAR hrtimer_test_t *param, uint64_t rand_ns) { @@ -287,15 +412,15 @@ static void hrtimer_test_rand_cancel(FAR hrtimer_test_t *param, irqstate_t flags; spinlock_t *lock = ¶m->lock; - printf("hrtimer_test_rand cancel %" PRIu64 " ns\n", rand_ns); + printf("hrtimer_test_rand_cancel: max delay = %" PRIu64 " ns\n", rand_ns); param->period = rand_ns; - /* Perform multiple iterations with random delays. */ + /* Perform multiple iterations with random delays */ for (idx = 0; idx < HRTIMER_TEST_RAND_ITER; idx++) { - /* Generate a random delay within the specified range. */ + /* Generate a random delay within the specified range */ delay = rand() % rand_ns; @@ -308,11 +433,11 @@ static void hrtimer_test_rand_cancel(FAR hrtimer_test_t *param, spin_unlock_irqrestore(lock, flags); - /* Decide to wait for the callback or cancel the hrtimer. */ + /* Decide to wait for the callback or cancel the hrtimer */ if (delay % 2u) { - /* Wait for the callback finished. */ + /* Wait for the callback to finish */ while (param->count != count + 1u) { @@ -328,6 +453,23 @@ static void hrtimer_test_rand_cancel(FAR hrtimer_test_t *param, hrtimer_cancel_sync(¶m->timer); } +/**************************************************************************** + * Name: hrtimer_test_callback_period + * + * Description: + * Periodic timer callback function. This callback is invoked when a + * periodic HRTimer expires. It records the timestamp, increments the + * count, and returns the interval for the next expiration. + * + * Input Parameters: + * timer - Pointer to the HRTimer instance + * expired_ns - Time when the timer expired (unused) + * + * Returned Value: + * The interval in nanoseconds for the next expiration + * + ****************************************************************************/ + static uint64_t hrtimer_test_callback_period(FAR const hrtimer_t *timer, uint64_t expired_ns) { @@ -340,6 +482,24 @@ static uint64_t hrtimer_test_callback_period(FAR const hrtimer_t *timer, return interval; } +/**************************************************************************** + * Name: hrtimer_test_period + * + * Description: + * Test periodic HRTimer functionality. This function tests a periodic + * HRTimer by starting it with a specified interval and verifying that + * it triggers multiple times as expected. + * + * Input Parameters: + * param - Test context structure containing timer and state information + * delay_ns - Period interval in nanoseconds + * iters - Expected number of timer expirations + * + * Returned Value: + * None. + * + ****************************************************************************/ + static void hrtimer_test_period(FAR hrtimer_test_t *param, uint64_t delay_ns, unsigned int iters) @@ -348,7 +508,8 @@ static void hrtimer_test_period(FAR hrtimer_test_t *param, uint64_t count = param->count; FAR hrtimer_t *timer = ¶m->timer; - printf("hrtimer_test_period %" PRIu64 " ns\n", delay_ns); + printf("hrtimer_test_period: period = %" PRIu64 " ns, iters = %u\n", + delay_ns, iters); param->period = delay_ns; ASSERT(param->period > 0); @@ -358,29 +519,52 @@ static void hrtimer_test_period(FAR hrtimer_test_t *param, ASSERT(hrtimer_start(timer, hrtimer_test_callback_period, delay_ns, HRTIMER_MODE_REL) == OK); + /* Wait for expected number of periods */ + hrtimer_test_ndelay(iters * delay_ns); hrtimer_cancel_sync(timer); ASSERT(timer->func == NULL); - printf("periodical hrtimer triggered %" PRIu64 " times, " + /* Report results */ + + printf("hrtimer_test_period: triggered %" PRIu64 " times, " "elapsed nsec %" PRIu64 "\n", param->count - count, param->timestamp - timestamp); + /* Warn if fewer expirations than expected */ + if (param->count - count < iters) { - printf("hrtimer_test: [WARNING] periodical hrtimer" + printf("hrtimer_test_period: [WARNING] periodical hrtimer " "triggered times < %u\n", iters); } } #ifdef CONFIG_SMP +/**************************************************************************** + * Name: hrtimer_test_callback_crita + * + * Description: + * Critical section test callback A. This callback is used to test + * critical section protection in SMP systems. It verifies that timer + * callbacks can safely access shared state. + * + * Input Parameters: + * timer - Pointer to the HRTimer instance + * expired_ns - Time when the timer expired (unused) + * + * Returned Value: + * 0 (oneshot hrtimer) + * + ****************************************************************************/ + static uint64_t hrtimer_test_callback_crita(FAR const hrtimer_t *timer, uint64_t expired_ns) { FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; - /* change status */ + /* Change status if in initial state */ if (param->state == 0) { @@ -388,7 +572,7 @@ static uint64_t hrtimer_test_callback_crita(FAR const hrtimer_t *timer, param->count++; } - /* check whether parameter be changed by another critical section */ + /* Verify state wasn't changed by another critical section */ ASSERT(param->state == 1); param->state = 0; @@ -396,12 +580,29 @@ static uint64_t hrtimer_test_callback_crita(FAR const hrtimer_t *timer, return 0; } +/**************************************************************************** + * Name: hrtimer_test_callback_critb + * + * Description: + * Critical section test callback B. This callback is used to test + * critical section protection in SMP systems. It verifies that timer + * callbacks can safely access shared state. + * + * Input Parameters: + * timer - Pointer to the HRTimer instance + * expired_ns - Time when the timer expired (unused) + * + * Returned Value: + * 0 (oneshot hrtimer) + * + ****************************************************************************/ + static uint64_t hrtimer_test_callback_critb(FAR const hrtimer_t *timer, uint64_t expired_ns) { FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; - /* change status */ + /* Change status if in expected state */ if (param->state == 1) { @@ -409,7 +610,7 @@ static uint64_t hrtimer_test_callback_critb(FAR const hrtimer_t *timer, param->count++; } - /* check whether parameter be changed by another critical section */ + /* Verify state wasn't changed by another critical section */ ASSERT(param->state == 0); param->state = 1; @@ -417,6 +618,23 @@ static uint64_t hrtimer_test_callback_critb(FAR const hrtimer_t *timer, return 0; } +/**************************************************************************** + * Name: hrtimer_test_callback_critdelay + * + * Description: + * Critical section delay test callback. This callback simulates a + * long-running timer callback with spinlock protection. It's used to + * test timer cancellation behavior with in-progress callbacks. + * + * Input Parameters: + * timer - Pointer to the HRTimer instance + * expired_ns - Time when the timer expired (unused) + * + * Returned Value: + * 300 microseconds (reschedules timer for periodic behavior) + * + ****************************************************************************/ + static uint64_t hrtimer_test_callback_critdelay(FAR const hrtimer_t *timer, uint64_t expired_ns) { @@ -424,15 +642,35 @@ static uint64_t hrtimer_test_callback_critdelay(FAR const hrtimer_t *timer, FAR spinlock_t *lock = ¶m->lock; irqstate_t flags; + /* Protect count increment with spinlock */ + flags = spin_lock_irqsave(lock); param->count++; spin_unlock_irqrestore(lock, flags); + /* Simulate work with 100 microsecond delay */ + up_ndelay(100 * NSEC_PER_USEC); + /* Return reschedule interval for periodic behavior */ + return 300 * NSEC_PER_USEC; } +/**************************************************************************** + * Name: hrtimer_test_cancel_sync + * + * Description: + * Test HRTimer cancel synchronization. This function tests that + * hrtimer_cancel_sync properly waits for callback completion before + * returning. It verifies that timer callbacks complete execution even + * when cancellation is requested. + * + * Input Parameters: + * param - Test context structure containing timer and state information + * + ****************************************************************************/ + static void hrtimer_test_cancel_sync(FAR hrtimer_test_t *param) { unsigned int idx = 0; @@ -441,11 +679,6 @@ static void hrtimer_test_cancel_sync(FAR hrtimer_test_t *param) param->count = 0; - /* This test is to validate if the hrtimer can ensure the - * callback function be finished after the hrtimer_cancel_sync - * is called. - */ - for (idx = 0; idx < HRTIMER_TEST_CSECTION; ) { param->state = 0; @@ -459,13 +692,27 @@ static void hrtimer_test_cancel_sync(FAR hrtimer_test_t *param) if (++idx % (HRTIMER_TEST_CSECTION / 4) == 0) { - printf("hrtimer_test_cancel_sync passed %d times.\n", idx); + printf("hrtimer_test_cancel_sync: passed %u times\n", idx); } hrtimer_cancel_sync(¶m->timer); } } +/**************************************************************************** + * Name: hrtimer_test_cancel_periodic + * + * Description: + * Test periodic HRTimer cancellation. This function tests that periodic + * timers can be properly cancelled and that they don't restart after + * cancellation. It verifies that timer cancellation is effective and + * persistent. + * + * Input Parameters: + * param - Test context structure containing timer and state information + * + ****************************************************************************/ + static void hrtimer_test_cancel_periodic(FAR hrtimer_test_t *param) { uint64_t count; @@ -476,11 +723,6 @@ static void hrtimer_test_cancel_periodic(FAR hrtimer_test_t *param) param->count = 0; - /* This test to check if the hrtimer can ensure the perodical callback - * can not restart the timer again after the hrtimer_cancel_sync is - * called. - */ - for (idx = 0; idx < HRTIMER_TEST_CSECTION; idx++) { irqstate_t flags = spin_lock_irqsave(lock); @@ -503,7 +745,7 @@ static void hrtimer_test_cancel_periodic(FAR hrtimer_test_t *param) up_ndelay(10000); - /* The hrtimer should not be restarted again after the cancellation. */ + /* The hrtimer should not restart after cancellation */ ASSERT(!param->timer.func); @@ -516,7 +758,7 @@ static void hrtimer_test_cancel_periodic(FAR hrtimer_test_t *param) if (++idx % (HRTIMER_TEST_CSECTION / 4) == 0) { - printf("hrtimer_test_cancel_periodic passed %d times. count %" + printf("hrtimer_test_cancel_periodic: passed %u times, count = %" PRIu64 "\n", idx, param->count); } } @@ -529,11 +771,20 @@ static void hrtimer_test_cancel_periodic(FAR hrtimer_test_t *param) * Name: hrtimer_test_thread * * Description: - * Thread function to repeatedly test HRTimer start/cancel behavior. + * HRTimer test thread function. This function runs a comprehensive test + * suite for HRTimer functionality. It tests various scenarios including + * one-shot timers, periodic timers, random delays, maximum delays, and + * cancellation behavior. + * + * Input Parameters: + * arg - Thread argument (unused) + * + * Returned Value: + * NULL. * ****************************************************************************/ -static void * hrtimer_test_thread(void *arg) +static void *hrtimer_test_thread(void *arg) { hrtimer_test_t param = { @@ -542,6 +793,8 @@ static void * hrtimer_test_thread(void *arg) hrtimer_init(¶m.timer); + /* Test one-shot timers with various delays */ + /* Delay = 0 */ hrtimer_test_oneshot(¶m, 0u); @@ -561,24 +814,21 @@ static void * hrtimer_test_thread(void *arg) hrtimer_test_oneshot(¶m, 10000000u); #ifdef CONFIG_SMP - /* Test hrtimer_cancel_sync */ + /* Test SMP-specific cancellation behavior */ hrtimer_test_cancel_sync(¶m); - - /* Test hrtimer_cancel */ - hrtimer_test_cancel_periodic(¶m); #endif - /* Maximum hrtimer delay test. */ + /* Test maximum delay handling */ hrtimer_test_maximum(¶m); - /* Period hrtimer delay 100000ns */ + /* Test periodic timer with 1ms period */ hrtimer_test_period(¶m, 1000000u, 128u); - /* Random delay 12345ns and 67890ns */ + /* Test random delay and cancel scenarios */ hrtimer_test_rand(¶m, 12345u); hrtimer_test_rand_cancel(¶m, 67890u); @@ -617,11 +867,15 @@ void hrtimer_test(void) printf("hrtimer_test start...\n"); + /* Initialize thread attributes */ + ASSERT(pthread_attr_init(&attr) == 0); sparam.sched_priority = PTHREAD_DEFAULT_PRIORITY; ASSERT(pthread_attr_setschedparam(&attr, &sparam) == 0); + /* Create multiple test threads */ + for (thread_id = 0; thread_id < HRTIMER_TEST_THREAD_NR; thread_id++) { ASSERT(pthread_create(&pthreads[thread_id], &attr, @@ -635,6 +889,8 @@ void hrtimer_test(void) pthread_join(pthreads[thread_id], NULL); } + /* Clean up thread attributes */ + ASSERT(pthread_attr_destroy(&attr) == 0); printf("hrtimer_test end...\n");