nuttx-apps/testing/drivers/drivertest/drivertest_posix_timer.c
Xiang Xiao f9f59bd0f8 !apps: drop redundant casts on tv_sec/tv_nsec and fix printf formats
Now that time_t is unconditionally 64-bit (signed int64_t) and the
struct timespec fields tv_sec / tv_nsec are wide enough on their own,
the explicit (uint64_t)/(int64_t)/(int) casts that used to guard the
multiplications and subtractions in *_us / *_ms / *_ns helpers are no
longer needed.  Drop them to keep the timekeeping math readable.

In the same spirit, this commit also normalises the printf-style format
specifiers and casts used to print tv_sec / tv_nsec / tv_usec values.
The prior code was a mix of "%d"/"%u"/"%ld"/"%lu"/"%lld" with matching
(int)/(unsigned long)/(long long) casts; some formats truncated time_t
on 32-bit hosts, others mismatched signedness or width.  Replace all
such cases with the portable POSIX-recommended forms:

  - tv_sec  (time_t,       signed, impl-defined width) -> %jd  + (intmax_t)
  - tv_nsec (long,         signed)                     -> %ld  (no cast)
  - tv_usec (suseconds_t / long)                       -> %ld  (no cast)

Also drop two stale `(FAR const time_t *)&ts.tv_sec` casts that are
unnecessary now that ts.tv_sec is plain time_t.

Arithmetic-cleanup files (existing scope):

  - benchmarks/cyclictest/cyclictest.c:        timediff_us()
  - benchmarks/sd_bench/sd_bench_main.c:       get_time_delta_us()
  - examples/oneshot/oneshot_main.c:           maxus computation
  - examples/watchdog/watchdog_main.c:         current_time_ms (x2)
  - industry/nxmodbus/nxmb_internal.h:         nxmb_util_clock_ms()
  - netutils/ntpclient/ntpclient.c:            timespec2ntp()
  - netutils/ptpd/ptpd.c:                      ptp_adjtime()
  - system/dd/dd_main.c:                       elapsed accounting
  - testing/drivers/drivertest/drivertest_posix_timer.c:
                                               get_timestamp()
  - testing/drivers/sd_stress/sd_stress_main.c:get_time_delta()
  - testing/sched/getprime/getprime_main.c:    elapsed accounting
  - testing/sched/pthread_mutex_perf/pthread_mutex_perf.c:
                                               timespec_avg()

Printf-format-fix files (new in this revision):

  - examples/adjtime/adjtime_main.c
  - examples/charger/charger_main.c
  - examples/netpkt/netpkt_ethercat.c
  - fsutils/mkfatfs/mkfatfs.c
  - graphics/tiff/tiff_initialize.c
  - netutils/ptpd/ptpd.c
  - nshlib/nsh_timcmds.c
  - system/coredump/coredump.c
  - system/ptpd/ptpd_main.c
  - testing/drivers/drivertest/drivertest_oneshot.c
  - testing/mm/kasantest/kasantest.c
  - testing/ostest/semtimed.c
  - testing/sched/pthread_mutex_perf/pthread_mutex_perf.c
  - testing/sched/timerjitter/timerjitter.c
  - testing/testsuites/kernel/time/cases/clock_test_clock01.c
  - testing/testsuites/kernel/time/cases/clock_test_smoke.c

No behavioural change.

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2026-05-22 13:38:25 +08:00

245 lines
7.8 KiB
C

/****************************************************************************
* apps/testing/drivers/drivertest/drivertest_posix_timer.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 <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <cmocka.h>
#include <syslog.h>
#include <getopt.h>
#include <time.h>
#include <nuttx/timers/timer.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define RTC_DEFAULT_DEVIATION 100
#define DEFAULT_TIME_OUT 2
#define SLEEPSECONDS 10
#define OPTARG_TO_VALUE(value, type, base) \
do \
{ \
FAR char *ptr; \
value = (type)strtoul(optarg, &ptr, base); \
if (*ptr != '\0') \
{ \
printf("Parameter error: -%c %s\n", ch, optarg); \
show_usage(argv[0], EXIT_FAILURE); \
} \
} while (0)
/****************************************************************************
* Private Types
****************************************************************************/
struct posix_timer_state_s
{
struct itimerspec it;
uint64_t tim;
uint32_t trigger_count;
uint32_t deviation;
};
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: show_usage
****************************************************************************/
static void show_usage(FAR const char *progname, int exitcode)
{
printf("Usage: %s\n"
" -s <timeout seconds>\n"
" -a <timeout deviation>\n",
progname);
exit(exitcode);
}
/****************************************************************************
* Name: parse_commandline
****************************************************************************/
static void parse_commandline(
FAR struct posix_timer_state_s *posix_timer_state,
int argc, FAR char **argv)
{
int ch;
int converted;
while ((ch = getopt(argc, argv, "s:a:")) != ERROR)
{
switch (ch)
{
case 's':
OPTARG_TO_VALUE(converted, uint32_t, 10);
if (converted < 1 || converted > INT_MAX)
{
printf("signal out of range: %d\n", converted);
show_usage(argv[0], EXIT_FAILURE);
}
posix_timer_state->it.it_value.tv_sec = (uint32_t)converted;
posix_timer_state->it.it_interval.tv_sec = (uint32_t)converted;
break;
case 'a':
OPTARG_TO_VALUE(converted, uint32_t, 10);
if (converted < 0 || converted > INT_MAX)
{
printf("deviation out of range: %d\n", converted);
show_usage(argv[0], EXIT_FAILURE);
}
posix_timer_state->deviation = (uint32_t)converted;
break;
case '?':
printf("Unsupported option: %s\n", optarg);
show_usage(argv[0], EXIT_FAILURE);
break;
}
}
}
/****************************************************************************
* Name: get_timestamp
****************************************************************************/
static uint64_t get_timestamp(void)
{
struct timespec ts;
uint64_t ms;
clock_gettime(CLOCK_MONOTONIC, &ts);
ms = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
return ms;
}
/****************************************************************************
* Name: posix_timer_callback
****************************************************************************/
static void posix_timer_callback(union sigval arg)
{
FAR struct posix_timer_state_s *sigev_para =
(FAR struct posix_timer_state_s *)arg.sival_ptr;
uint64_t expected = (*sigev_para).tim +
DEFAULT_TIME_OUT * (*sigev_para).trigger_count;
int range = get_timestamp() - expected;
syslog(0, "range: %d ms\n", range);
assert(range >= sigev_para->it.it_interval.tv_sec * 1000 -
sigev_para->deviation);
syslog(LOG_DEBUG, "callback trigger!!!\n");
(*sigev_para).trigger_count++;
}
/****************************************************************************
* Name: drivertest_posix_timer
****************************************************************************/
static void drivertest_posix_timer(FAR void **state)
{
int ret;
timer_t timerid;
struct sigevent event;
FAR struct posix_timer_state_s *posix_timer_state;
struct itimerspec it;
memset(&it, 0, sizeof(it));
posix_timer_state = (FAR struct posix_timer_state_s *)*state;
event.sigev_notify = SIGEV_THREAD;
event.sigev_notify_function = posix_timer_callback;
event.sigev_notify_attributes = NULL;
event.sigev_value.sival_ptr = posix_timer_state;
/* Create the timer */
ret = timer_create(CLOCK_MONOTONIC, &event, &timerid);
assert_return_code(ret, OK);
/* Start the timer */
posix_timer_state->tim = get_timestamp();
ret = timer_settime(timerid, 0, &(posix_timer_state->it), NULL);
assert_return_code(ret, OK);
/* Get the timer status */
ret = timer_gettime(timerid, &it);
assert_return_code(ret, OK);
assert_in_range(it.it_value.tv_sec, 0,
posix_timer_state->it.it_value.tv_sec);
assert_return_code(it.it_interval.tv_sec,
posix_timer_state->it.it_interval.tv_sec);
sleep(SLEEPSECONDS);
/* Delete the timer */
ret = timer_delete(timerid);
assert_return_code(ret, OK);
}
int main(int argc, FAR char *argv[])
{
struct posix_timer_state_s posix_timer_state =
{
.it.it_value.tv_sec = DEFAULT_TIME_OUT,
.it.it_value.tv_nsec = 0,
.it.it_interval.tv_sec = DEFAULT_TIME_OUT,
.it.it_interval.tv_nsec = 0,
.trigger_count = 0,
.deviation = RTC_DEFAULT_DEVIATION
};
const struct CMUnitTest tests[] =
{
cmocka_unit_test_prestate_setup_teardown(drivertest_posix_timer, NULL,
NULL, &posix_timer_state)
};
parse_commandline(&posix_timer_state, argc, argv);
return cmocka_run_group_tests(tests, NULL, NULL);
}