ouyangxiangzhen a03ed46947 ostest/wdog: Remove periodical wdog test cases.
The peridiodical wdog test cases should be removed after removing of the periodical wdog APIs.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
2025-06-05 19:42:52 +08:00

386 lines
10 KiB
C

/****************************************************************************
* apps/testing/ostest/wdog.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/wdog.h>
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <syslog.h>
#include <unistd.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define WDOGTEST_RAND_ITER 1024
#define WDOGTEST_THREAD_NR (CONFIG_SMP_NCPUS * 4)
#define WDOGTEST_TOLERENT_TICK 10
#define wdtest_assert(x) _ASSERT(x, __FILE__, __LINE__)
#define wdtest_printf(...) printf(__VA_ARGS__)
#define wdtest_delay(delay_ns) usleep(delay_ns / 1000 + 1)
/****************************************************************************
* Private Type
****************************************************************************/
typedef struct wdtest_param_s
{
FAR struct wdog_s *wdog;
sclock_t interval;
uint64_t callback_cnt;
clock_t triggered_tick;
} wdtest_param_t;
/****************************************************************************
* Private Functions
****************************************************************************/
#ifdef CONFIG_BUILD_FLAT
static void wdtest_callback(wdparm_t param)
{
FAR wdtest_param_t *wdtest_param = (FAR wdtest_param_t *)param;
/* Increment the callback count */
wdtest_param->callback_cnt += 1;
/* Record the system tick at which the callback was triggered */
wdtest_param->triggered_tick = clock_systime_ticks();
}
static void wdtest_checkdelay(sclock_t diff, sclock_t delay_tick)
{
/* Ensure the watchdog trigger time is not earlier than expected. */
wdtest_assert(diff - delay_tick >= 0);
/* If the timer latency exceeds the tolerance, print a warning. */
if (diff - delay_tick > WDOGTEST_TOLERENT_TICK)
{
wdtest_printf("WARNING: wdog latency ticks %lld "
"(> %u may indicate timing error)\n",
(long long)diff - delay_tick,
WDOGTEST_TOLERENT_TICK);
}
}
static void wdtest_once(FAR struct wdog_s *wdog, FAR wdtest_param_t *param,
sclock_t delay_ns)
{
uint64_t cnt;
sclock_t diff;
clock_t wdset_tick;
irqstate_t flags;
sclock_t delay_tick = (sclock_t)NSEC2TICK((clock_t)delay_ns);
wdtest_printf("wdtest_once %lld ns\n", (long long)delay_ns);
/* Save the current callback count. */
cnt = param->callback_cnt;
/* Enter a critical section to prevent interruptions. */
flags = enter_critical_section();
/* Record the current system tick before setting the watchdog. */
wdset_tick = clock_systime_ticks();
wdtest_assert(wd_start(wdog, delay_tick, wdtest_callback,
(wdparm_t)param) == OK);
leave_critical_section(flags);
/* Wait until the callback is triggered exactly once. */
while (cnt + 1 != param->callback_cnt)
{
wdtest_delay(delay_ns);
}
/* Check if the delay is within the acceptable tolerance. */
diff = (sclock_t)(param->triggered_tick - wdset_tick);
wdtest_checkdelay(diff, delay_tick);
}
static void wdtest_rand(FAR struct wdog_s *wdog, FAR wdtest_param_t *param,
sclock_t rand_ns)
{
uint64_t cnt;
int idx;
sclock_t delay_ns;
clock_t wdset_tick;
sclock_t delay_tick;
sclock_t diff;
irqstate_t flags;
/* Perform multiple iterations with random delays. */
for (idx = 0; idx < WDOGTEST_RAND_ITER; idx++)
{
cnt = param->callback_cnt;
/* Generate a random delay within the specified range. */
delay_ns = rand() % rand_ns;
delay_tick = NSEC2TICK(delay_ns);
/* Enter critical section if the callback count is odd. */
if (cnt % 2)
{
flags = enter_critical_section();
}
wdset_tick = clock_systime_ticks();
wdtest_assert(wd_start(wdog, delay_tick, wdtest_callback,
(wdparm_t)param) == 0);
if (cnt % 2)
{
leave_critical_section(flags);
}
/* Decide to wait for the callback or cancel the watchdog. */
if (delay_ns % 2)
{
/* Wait for the callback. */
while (cnt + 1 != param->callback_cnt)
{
wdtest_delay(delay_ns);
}
/* Check the delay if the callback count is odd. */
if (cnt % 2)
{
diff = (sclock_t)(param->triggered_tick - wdset_tick);
wdtest_checkdelay(diff, delay_tick);
}
}
else
{
wd_cancel(wdog);
}
}
}
static void wdtest_callback_recursive(wdparm_t param)
{
FAR wdtest_param_t *wdtest_param = (FAR wdtest_param_t *)param;
sclock_t interval = wdtest_param->interval;
wdtest_param->callback_cnt += 1;
wdtest_param->triggered_tick = clock_systime_ticks();
wd_start(wdtest_param->wdog, interval,
wdtest_callback_recursive, param);
}
static void wdtest_recursive(FAR struct wdog_s *wdog,
FAR wdtest_param_t *param,
sclock_t delay_ns,
unsigned int times)
{
uint64_t cnt;
clock_t wdset_tick;
irqstate_t flags;
wdtest_printf("wdtest_recursive %lldns\n", (long long)delay_ns);
cnt = param->callback_cnt;
param->wdog = wdog;
param->interval = (sclock_t)NSEC2TICK((clock_t)delay_ns);
wdtest_assert(param->interval >= 0);
flags = enter_critical_section();
wdset_tick = clock_systime_ticks();
wdtest_assert(wd_start(param->wdog, param->interval,
wdtest_callback_recursive,
(wdparm_t)param) == OK);
leave_critical_section(flags);
wdtest_delay(times * delay_ns);
wd_cancel(param->wdog);
wdtest_printf("recursive wdog triggered %llu times, elapsed tick %lld\n",
(unsigned long long)(param->callback_cnt - cnt),
(long long)(param->triggered_tick - wdset_tick));
}
static void wdog_test_run(FAR wdtest_param_t *param)
{
uint64_t cnt;
sclock_t rest;
clock_t delay;
struct wdog_s test_wdog =
{
0
};
/* Wrong arguments of the wd_start */
wdtest_assert(wd_start(NULL, 0, NULL, (wdparm_t)NULL) != OK);
wdtest_assert(wd_start(NULL, 0, wdtest_callback, (wdparm_t)NULL) != OK);
wdtest_assert(wd_start(NULL, -1, NULL, (wdparm_t)NULL) != OK);
wdtest_assert(wd_start(NULL, -1, wdtest_callback, (wdparm_t)NULL) != OK);
wdtest_assert(wd_start(&test_wdog, 0, NULL, (wdparm_t)NULL) != OK);
wdtest_assert(wd_start(&test_wdog, -1, NULL, (wdparm_t)NULL) != OK);
wdtest_assert(wd_start(&test_wdog, -1, wdtest_callback, (wdparm_t)NULL)
!= OK);
/* Wrong arguments of the wd_cancel */
wdtest_assert(wd_cancel(NULL) != OK);
wdtest_assert(wd_cancel(&test_wdog) != OK);
/* Delay = 0 */
wdtest_once(&test_wdog, param, 0);
/* Delay > 0, small */
wdtest_once(&test_wdog, param, 1);
wdtest_once(&test_wdog, param, 10);
wdtest_once(&test_wdog, param, 100);
wdtest_once(&test_wdog, param, 1000);
wdtest_once(&test_wdog, param, 10000);
/* Delay > 0, middle 100us */
wdtest_once(&test_wdog, param, 100000);
wdtest_once(&test_wdog, param, 1000000);
/* Delay > 0, maximum */
cnt = param->callback_cnt;
/* Maximum */
delay = CLOCK_MAX >> 2;
wdtest_assert(wd_start(&test_wdog, delay,
wdtest_callback, (wdparm_t)param) == OK);
/* Sleep for 1s */
wdtest_delay(USEC_PER_SEC);
/* Testing wd_gettime */
wdtest_assert(wd_gettime(NULL) == 0);
wdtest_assert(wd_cancel(NULL) != 0);
/* Ensure watchdog not alarmed */
wdtest_assert(cnt == param->callback_cnt);
rest = wd_gettime(&test_wdog);
wdtest_assert(rest < delay);
wdtest_assert(wd_cancel(&test_wdog) == 0);
wdtest_printf("wd_start with maximum delay, cancel OK, rest %lld\n",
(long long)rest);
/* Recursive wdog delay from 1000us to 10000us */
wdtest_recursive(&test_wdog, param, 1000000, 100);
wdtest_recursive(&test_wdog, param, 10000000, 10);
/* Random delay ~12us */
wdtest_rand(&test_wdog, param, 12345);
/* Finally, cancel the wdog. */
wd_cancel(&test_wdog);
}
/* Multi threaded */
static FAR void *wdog_test_thread(FAR void *param)
{
wdog_test_run(param);
return NULL;
}
/****************************************************************************
* Public Functions
****************************************************************************/
void wdog_test(void)
{
unsigned int thread_id;
pthread_attr_t attr;
pthread_t pthreads[WDOGTEST_THREAD_NR];
wdtest_param_t params[WDOGTEST_THREAD_NR] =
{
0
};
printf("wdog_test start...\n");
wdtest_assert(pthread_attr_init(&attr) == 0);
/* Create wdog test thread */
for (thread_id = 0; thread_id < WDOGTEST_THREAD_NR; thread_id++)
{
wdtest_assert(pthread_create(&pthreads[thread_id], &attr,
wdog_test_thread, &params[thread_id])
== 0);
}
for (thread_id = 0; thread_id < WDOGTEST_THREAD_NR; thread_id++)
{
pthread_join(pthreads[thread_id], NULL);
}
wdtest_assert(pthread_attr_destroy(&attr) == 0);
printf("wdog_test end...\n");
}
#endif