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/hrtimer.c b/testing/ostest/hrtimer.c index 48ed46b9904..3220ef2db7b 100644 --- a/testing/ostest/hrtimer.c +++ b/testing/ostest/hrtimer.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -38,39 +39,31 @@ * Pre-processor Definitions ****************************************************************************/ -/* Timer constants */ +/* HRTimer test 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_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 a 1ms margin to allow hrtimertest to pass in QEMU. +/* Tolerable latency for timer expiration * - * 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. + * 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 - * 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) - -/* 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) +#define HRTIMER_TEST_TOLERENT_LATENCY (10 * NSEC_PER_MSEC) + +/* Helper macro for nanosecond delay */ + +#define hrtimer_test_ndelay(delay_ns) usleep((delay_ns) / 1000 + 1) /**************************************************************************** * Private Types @@ -78,172 +71,769 @@ /* 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 */ + 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 (used for synchronization tests) */ +} hrtimer_test_t; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: hrtimer_test_init + * Name: hrtimer_test_callback_oneshot * * Description: - * Initialize a hrtimer_test_s structure for a new test. + * 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: - * hrtimer_test - Pointer to the test structure to initialize - * period - Expected timer period in nanoseconds + * timer - Pointer to the HRTimer instance + * expired_ns - Time when the timer expired (unused) * * Returned Value: - * None + * 0 (oneshot hrtimer) * ****************************************************************************/ -static void hrtimer_test_init(FAR struct hrtimer_test_s *hrtimer_test, - uint32_t period) +static uint64_t hrtimer_test_callback_oneshot(FAR const hrtimer_t *timer, + uint64_t expired_ns) { - hrtimer_test->previous = 0; - hrtimer_test->count = 0; - hrtimer_test->active = true; - hrtimer_test->period = period; + FAR hrtimer_test_t *param = (FAR hrtimer_test_t *)timer; + + /* Record the exact timestamp when the callback was triggered */ + + param->timestamp = clock_systime_nsec(); + + /* Increment the callback count */ + + param->count++; + + return 0; } /**************************************************************************** - * Name: test_hrtimer_callback + * Name: hrtimer_test_checkdelay * * Description: - * HRTimer callback function for test. + * 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; + + /* 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] hrtimer latency %" PRId64 + " ns is too late (> %u ns)\n", diff, + (unsigned)HRTIMER_TEST_TOLERENT_LATENCY); + } +} + +/**************************************************************************** + * Name: hrtimer_test_oneshot * - * - Verifies the timer interval is exactly 500ms (nanosecond precision) - * - Stops the test after 15 expirations - * - Re-arms the timer in absolute mode + * 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: - * hrtimer - Pointer to the expired HRTimer instance - * expired - The expired value of hrtimer + * param - Test context structure containing timer and state information + * delay - Delay in nanoseconds for the one-shot timer * * Returned Value: - * Timer period in nanoseconds (NSEC_PER_50MS) + * None. * ****************************************************************************/ -static uint64_t -test_hrtimer_callback(FAR const hrtimer_t *hrtimer, uint64_t expired) +static void hrtimer_test_oneshot(FAR hrtimer_test_t *param, uint64_t delay) { - struct timespec ts; - uint32_t diff; - uint64_t now; - int ret; + uint64_t count; + uint64_t now; + FAR hrtimer_t *timer = ¶m->timer; - UNUSED(expired); + printf("hrtimer_test_oneshot: delay = %" PRIu64 " ns\n", delay); - FAR struct hrtimer_test_s *test = - (FAR struct hrtimer_test_s *)hrtimer; + /* Save the current callback count and system time */ - /* Increment expiration count */ + count = param->count; + now = clock_systime_nsec(); - test->count++; + /* Start the one-shot timer */ - /* Get current system time */ + ASSERT(hrtimer_start(timer, hrtimer_test_callback_oneshot, + delay + now, HRTIMER_MODE_ABS) == OK); - clock_systime_timespec(&ts); - now = clock_time2nsec(&ts); + /* Wait until the callback is triggered exactly once */ - /* Skip comparison for first two invocations */ + while (count + 1 != param->count) + { + hrtimer_test_ndelay(delay); + } - if (test->count > 2) + /* Verify the delay is within acceptable tolerance */ + + hrtimer_test_checkdelay(param->timestamp, now + delay); + + /* 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 delay */ + + ASSERT(hrtimer_start(timer, hrtimer_test_callback_oneshot, UINT64_MAX, + HRTIMER_MODE_REL) == OK); + + /* Sleep for at least 100ms to verify timer doesn't expire */ + + hrtimer_test_ndelay(USEC_PER_SEC / 100); + + /* 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_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; + uint64_t now; + unsigned int idx; + uint64_t delay; + irqstate_t flags; + FAR hrtimer_t *timer = ¶m->timer; + + printf("hrtimer_test_rand: max delay = %" PRIu64 " ns\n", rand_ns); + + /* Perform multiple iterations with random delays */ + + for (idx = 0; idx < HRTIMER_TEST_RAND_ITER; idx++) { - /* Verify the timer interval is exactly - * 500ms with nsec resolution - */ + /* Generate a random delay within the specified range */ + + delay = rand() % rand_ns; - diff = (uint32_t)(now - test->previous); + ASSERT(timer->func == NULL); - HRTIMER_TEST(NSEC_PER_50MS < diff + HRTIMER_TEST_MARGIN, true); - HRTIMER_TEST(NSEC_PER_50MS > diff - HRTIMER_TEST_MARGIN, true); + /* 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); } - test->previous = now; + hrtimer_cancel_sync(timer); +} - /* Stop the test after PERIOD_TEST_COUNT expirations */ +/**************************************************************************** + * 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) + * + ****************************************************************************/ - if (test->count < PERIOD_TEST_COUNT) +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); + + /* Calculate random sleep delay based on period */ + + delay = expired_ns % param->period; + + /* Check if the expiration time matches (prevents duplicate processing) */ + + if (expired_ns == timer->expired) { - return test->period; + param->timestamp = clock_systime_nsec(); + + /* Increment the callback count */ + + param->count++; } - else + + 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) +{ + 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: max delay = %" PRIu64 " ns\n", rand_ns); + + param->period = 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; + + 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 to finish */ + + 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); } /**************************************************************************** - * Name: hrtimer_test_callback + * Name: hrtimer_test_callback_period * * Description: - * Simple HRTimer callback for threaded tests. + * 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(FAR const hrtimer_t *hrtimer, uint64_t expired) +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; +} + +/**************************************************************************** + * 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) +{ + uint64_t timestamp; + uint64_t count = param->count; + FAR hrtimer_t *timer = ¶m->timer; + + printf("hrtimer_test_period: period = %" PRIu64 " ns, iters = %u\n", + delay_ns, iters); + + 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); + + /* Wait for expected number of periods */ + + hrtimer_test_ndelay(iters * delay_ns); + + hrtimer_cancel_sync(timer); + ASSERT(timer->func == NULL); + + /* 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_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 if in initial state */ + + if (param->state == 0) + { + param->state = 1; + param->count++; + } + + /* Verify state wasn't changed by another critical section */ + + ASSERT(param->state == 1); + param->state = 0; + return 0; } /**************************************************************************** - * Name: hrtimer_test_thread + * 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 if in expected state */ + + if (param->state == 1) + { + param->state = 0; + param->count++; + } + + /* Verify state wasn't changed by another critical section */ + + ASSERT(param->state == 0); + param->state = 1; + + 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) +{ + FAR hrtimer_test_t *param = (FAR hrtimer_test_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: - * Thread function to repeatedly test HRTimer start/cancel behavior. + * 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_thread(void *arg) +static void hrtimer_test_cancel_sync(FAR hrtimer_test_t *param) { - hrtimer_t timer; - int ret; - int i = 0; + unsigned int idx = 0; - hrtimer_init(&timer); + ASSERT(!param->timer.func); - while (i < THREAD_LOOP_COUNT) + param->count = 0; + + for (idx = 0; idx < HRTIMER_TEST_CSECTION; ) { - i++; - uint64_t delay = rand() % NSEC_PER_MSEC; + param->state = 0; + hrtimer_start(¶m->timer, hrtimer_test_callback_crita, + 0, HRTIMER_MODE_REL); - /* Cancel timer */ + hrtimer_cancel_sync(¶m->timer); + param->state = 1; + hrtimer_start(¶m->timer, hrtimer_test_callback_critb, + 0, HRTIMER_MODE_REL); - ret = hrtimer_cancel(&timer); - HRTIMER_TEST(ret >= 0, true); + if (++idx % (HRTIMER_TEST_CSECTION / 4) == 0) + { + printf("hrtimer_test_cancel_sync: passed %u times\n", idx); + } - /* Start timer with fixed period */ + hrtimer_cancel_sync(¶m->timer); + } +} - ret = hrtimer_start(&timer, hrtimer_test_callback, - 10 * NSEC_PER_USEC, HRTIMER_MODE_REL); - HRTIMER_TEST(ret, OK); +/**************************************************************************** + * 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; + unsigned int idx = 0; + FAR spinlock_t *lock = ¶m->lock; + + ASSERT(!param->timer.func); + + param->count = 0; + + for (idx = 0; idx < HRTIMER_TEST_CSECTION; idx++) + { + irqstate_t flags = spin_lock_irqsave(lock); - /* Start timer with random delay */ + hrtimer_start(¶m->timer, hrtimer_test_callback_critdelay, + 0, HRTIMER_MODE_REL); - ret = hrtimer_start(&timer, hrtimer_test_callback, - delay, HRTIMER_MODE_REL); - HRTIMER_TEST(ret, OK); + 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 restart after 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 %u times, count = %" + PRIu64 "\n", idx, param->count); + } } - /* Cancel the timer synchronously */ + hrtimer_cancel_sync(¶m->timer); +} +#endif + +/**************************************************************************** + * Name: hrtimer_test_thread + * + * Description: + * 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) +{ + hrtimer_test_t param = + { + 0 + }; + + hrtimer_init(¶m.timer); + + /* Test one-shot timers with various delays */ + + /* Delay = 0 */ + + hrtimer_test_oneshot(¶m, 0u); + + /* 0 < Delay < 10000 */ + + 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); + + /* 10000 < Delay < 10000000 */ + + hrtimer_test_oneshot(¶m, 100000u); + hrtimer_test_oneshot(¶m, 1000000u); + hrtimer_test_oneshot(¶m, 10000000u); + +#ifdef CONFIG_SMP + /* Test SMP-specific cancellation behavior */ + + hrtimer_test_cancel_sync(¶m); + hrtimer_test_cancel_periodic(¶m); +#endif - ret = hrtimer_cancel_sync(&timer); - HRTIMER_TEST(ret >= 0, true); + /* Test maximum delay handling */ - return NULL; + hrtimer_test_maximum(¶m); + + /* Test periodic timer with 1ms period */ + + hrtimer_test_period(¶m, 1000000u, 128u); + + /* Test random delay and cancel scenarios */ + + hrtimer_test_rand(¶m, 12345u); + hrtimer_test_rand_cancel(¶m, 67890u); + + return 0; } /**************************************************************************** @@ -271,45 +861,25 @@ 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]; - struct hrtimer_test_s hrtimer_test; - int ret; - - /* Initialize test structure */ - - hrtimer_test_init(&hrtimer_test, NSEC_PER_50MS); - - /* Initialize the high-resolution timer */ + unsigned int thread_id; + pthread_attr_t attr; + pthread_t pthreads[HRTIMER_TEST_THREAD_NR]; - hrtimer_init(&hrtimer_test.timer); + printf("hrtimer_test start...\n"); - /* Start the timer with 500ms relative timeout */ + /* Initialize thread attributes */ - ret = hrtimer_start(&hrtimer_test.timer, - test_hrtimer_callback, - hrtimer_test.period, - HRTIMER_MODE_REL); - - HRTIMER_TEST(ret, OK); - - /* Wait until the test completes */ - - while (hrtimer_test.active) - { - usleep(USEC_PER_MSEC); - } - - pthread_attr_init(&attr); + ASSERT(pthread_attr_init(&attr) == 0); sparam.sched_priority = PTHREAD_DEFAULT_PRIORITY; - pthread_attr_setschedparam(&attr, &sparam); + ASSERT(pthread_attr_setschedparam(&attr, &sparam) == 0); + + /* Create multiple test threads */ 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 */ @@ -319,5 +889,9 @@ void hrtimer_test(void) pthread_join(pthreads[thread_id], NULL); } - HRTIMER_TEST(pthread_attr_destroy(&attr), 0); + /* Clean up thread attributes */ + + ASSERT(pthread_attr_destroy(&attr) == 0); + + printf("hrtimer_test end...\n"); } 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