From 1c643b5cc33779a65baa75be814607d549cf224c Mon Sep 17 00:00:00 2001 From: dongjiuzhu1 Date: Thu, 20 Mar 2025 18:20:26 +0800 Subject: [PATCH] sched/clock: support using CLOCKFD to call clock_gettime/settime This patch implements POSIX-compliant CLOCKFD support, enabling user applications to access dynamic PTP clocks through file descriptors combined with clock_gettime() and clock_settime() system calls. Key changes include: 1. CLOCKFD macro support: - Added CLOCKFD() macro in include/nuttx/clock.h - Allows encoding file descriptor into clockid_t: CLOCKFD(fd) - Enables accessing PTP clocks via: clock_gettime(CLOCKFD(fd), &ts) 2. clock_gettime() enhancements: - Modified sched/clock/clock_gettime.c to detect CLOCKFD clockids - Extracts file descriptor from clockid using CLOCKFD_TO_FD() - Validates file descriptor and calls file_ioctl() with PTP_CLOCK_GETTIME - Falls back to standard clock handling for non-CLOCKFD clockids 3. clock_settime() enhancements: - Modified sched/clock/clock_settime.c to support CLOCKFD clockids - Extracts file descriptor and validates accessibility - Issues PTP_CLOCK_SETTIME ioctl to underlying PTP clock device - Maintains backward compatibility with standard POSIX clocks 4. File descriptor validation: - Checks file descriptor validity using fs_getfilep() - Ensures proper reference counting with fs_putfilep() - Returns appropriate error codes (EINVAL, EBADF) on failures 5. Integration with PTP clock framework: - Seamlessly integrates with PTP clock driver's ioctl interface - Enables standard POSIX clock API usage for dynamic PTP clocks - No changes required to existing applications using standard clocks Usage example: int fd = open("/dev/ptp0", O_RDONLY); struct timespec ts; clock_gettime(CLOCKFD(fd), &ts); /* Get PTP clock time */ clock_settime(CLOCKFD(fd), &ts); /* Set PTP clock time */ close(fd); This implementation follows the Linux kernel's PTP clock model, providing a familiar interface for developers working with PTP hardware. Signed-off-by: dongjiuzhu1 --- include/nuttx/clock.h | 4 +- sched/clock/clock_gettime.c | 46 +++++++++++++++++++--- sched/clock/clock_settime.c | 76 ++++++++++++++++++++++++++++--------- 3 files changed, 101 insertions(+), 25 deletions(-) diff --git a/include/nuttx/clock.h b/include/nuttx/clock.h index 60d2941e071..05b568af6a4 100644 --- a/include/nuttx/clock.h +++ b/include/nuttx/clock.h @@ -827,7 +827,7 @@ unsigned long perf_getfreq(void); * ****************************************************************************/ -void nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp); +int nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp); /**************************************************************************** * Name: nxclock_gettime @@ -837,7 +837,7 @@ void nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp); * ****************************************************************************/ -void nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp); +int nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp); #undef EXTERN #ifdef __cplusplus diff --git a/sched/clock/clock_gettime.c b/sched/clock/clock_gettime.c index 89ebde17665..3dcf862e1c3 100644 --- a/sched/clock/clock_gettime.c +++ b/sched/clock/clock_gettime.c @@ -32,10 +32,12 @@ #include #include +#include #include #include #include #include +#include #include "clock/clock.h" #include "sched/sched.h" @@ -86,9 +88,16 @@ static clock_t clock_process_runtime(FAR struct tcb_s *tcb) * ****************************************************************************/ -void nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp) +int nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp) { - if (clock_id == CLOCK_MONOTONIC) + int ret = 0; + + if (tp == NULL) + { + return -EINVAL; + } + + if (clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_BOOTTIME) { /* The the time elapsed since the timer was initialized at power on * reset, excluding the time that the system is suspended. @@ -124,6 +133,21 @@ void nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp) clock_timekeeping_get_wall_time(tp); #endif } +#ifdef CONFIG_PTP_CLOCK + else if ((clock_id & CLOCK_MASK) == CLOCK_FD) + { + FAR struct file *filep; + + ret = ptp_clockid_to_filep(clock_id, &filep); + if (ret < 0) + { + return ret; + } + + ret = file_ioctl(filep, PTP_CLOCK_GETTIME, tp); + fs_putfilep(filep); + } +#endif else { #if CONFIG_SCHED_CRITMONITOR_MAXTIME_THREAD >= 0 @@ -150,9 +174,19 @@ void nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp) { up_perf_convert(tcb->run_time, tp); } + else + { + ret = -EINVAL; + } + } + else + { + return -EINVAL; } #endif } + + return ret; } /**************************************************************************** @@ -181,12 +215,14 @@ void nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp) int clock_gettime(clockid_t clock_id, FAR struct timespec *tp) { - if (tp == NULL || clock_id < 0 || clock_id > CLOCK_BOOTTIME) + int ret; + + ret = nxclock_gettime(clock_id, tp); + if (ret < 0) { - set_errno(EINVAL); + set_errno(-ret); return ERROR; } - nxclock_gettime(clock_id, tp); return OK; } diff --git a/sched/clock/clock_settime.c b/sched/clock/clock_settime.c index 41017e69647..a448e809ea1 100644 --- a/sched/clock/clock_settime.c +++ b/sched/clock/clock_settime.c @@ -30,11 +30,13 @@ #include #include #include +#include #include +#include #include #include -#include +#include #include "clock/clock.h" #ifdef CONFIG_CLOCK_TIMEKEEPING @@ -42,21 +44,10 @@ #endif /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: nxclock_settime - * - * Description: - * Clock Functions based on POSIX APIs - * - * CLOCK_REALTIME - POSIX demands this to be present. This is the wall - * time clock. - * - ****************************************************************************/ - -void nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp) +static void nxclock_set_realtime(FAR const struct timespec *tp) { #ifndef CONFIG_CLOCK_TIMEKEEPING struct timespec bias; @@ -103,6 +94,54 @@ void nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp) #endif } +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nxclock_settime + * + * Description: + * Clock Functions based on POSIX APIs + * + * CLOCK_REALTIME - POSIX demands this to be present. This is the wall + * time clock. + * + ****************************************************************************/ + +int nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp) +{ + int ret = -EINVAL; + + if (tp == NULL || tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000) + { + return ret; + } + + if (clock_id == CLOCK_REALTIME) + { + nxclock_set_realtime(tp); + return 0; + } +#ifdef CONFIG_PTP_CLOCK + else if ((clock_id & CLOCK_MASK) == CLOCK_FD) + { + FAR struct file *filep; + + ret = ptp_clockid_to_filep(clock_id, &filep); + if (ret < 0) + { + return ret; + } + + ret = file_ioctl(filep, PTP_CLOCK_SETTIME, tp); + fs_putfilep(filep); + } +#endif + + return ret; +} + /**************************************************************************** * Name: clock_settime * @@ -116,13 +155,14 @@ void nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp) int clock_settime(clockid_t clock_id, FAR const struct timespec *tp) { - if (clock_id != CLOCK_REALTIME || tp == NULL || - tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000) + int ret; + + ret = nxclock_settime(clock_id, tp); + if (ret < 0) { - set_errno(EINVAL); + set_errno(-ret); return ERROR; } - nxclock_settime(clock_id, tp); return OK; }