From 07a4233d1d0af381e485f47a86e5a20dd7a32eab Mon Sep 17 00:00:00 2001 From: ligd Date: Wed, 5 Jun 2024 19:59:23 +0800 Subject: [PATCH] clock: refactor clock_gettime clock_settime Signed-off-by: ligd --- include/nuttx/clock.h | 23 +++ sched/clock/clock_gettime.c | 275 ++++++++++++++++-------------------- sched/clock/clock_settime.c | 152 +++++++++----------- 3 files changed, 210 insertions(+), 240 deletions(-) diff --git a/include/nuttx/clock.h b/include/nuttx/clock.h index b87a0b438a..f6fe114c47 100644 --- a/include/nuttx/clock.h +++ b/include/nuttx/clock.h @@ -732,6 +732,29 @@ void perf_convert(clock_t elapsed, FAR struct timespec *ts); unsigned long perf_getfreq(void); +/**************************************************************************** + * 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); + +/**************************************************************************** + * Name: nxclock_gettime + * + * Description: + * Get the current value of the specified time clock. + * + ****************************************************************************/ + +void 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 f2e05efcdc..351a2e970a 100644 --- a/sched/clock/clock_gettime.c +++ b/sched/clock/clock_gettime.c @@ -36,7 +36,6 @@ #include #include #include -#include #include "clock/clock.h" #include "sched/sched.h" @@ -44,172 +43,142 @@ # include "clock/clock_timekeeping.h" #endif +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef CONFIG_SCHED_CRITMONITOR +static clock_t clock_process_runtime(FAR struct tcb_s *tcb) +{ +# ifdef HAVE_GROUP_MEMBERS + FAR struct task_group_s *group; + FAR sq_entry_t *curr; + clock_t runtime = 0; + irqstate_t flags; + + group = tcb->group; + + flags = spin_lock_irqsave(NULL); + sq_for_every(&group->tg_members, curr) + { + tcb = container_of(curr, struct tcb_s, member); + + runtime += tcb->run_time; + } + + spin_unlock_irqrestore(NULL, flags); + return runtime; +# else /* HAVE_GROUP_MEMBERS */ + return tcb->run_time; +# endif /* HAVE_GROUP_MEMBERS */ +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: nxclock_gettime + * + * Description: + * Get the current value of the specified time clock. + * + ****************************************************************************/ + +void nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp) +{ + if (clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_BOOTTIME) + { + /* The the time elapsed since the timer was initialized at power on + * reset. + */ + + clock_systime_timespec(tp); + } + else if (clock_id == CLOCK_REALTIME) + { +#ifndef CONFIG_CLOCK_TIMEKEEPING + struct timespec ts; + irqstate_t flags; + + clock_systime_timespec(&ts); + + /* Add the base time to this. The base time is the time-of-day + * setting. When added to the elapsed time since the time-of-day + * was last set, this gives us the current time. + */ + + flags = spin_lock_irqsave(NULL); + clock_timespec_add(&g_basetime, &ts, tp); + spin_unlock_irqrestore(NULL, flags); +#else + clock_timekeeping_get_wall_time(tp); +#endif + } + else + { +#ifdef CONFIG_SCHED_CRITMONITOR + clockid_t clock_type = clock_id & CLOCK_MASK; + pid_t pid = clock_id >> CLOCK_SHIFT; + FAR struct tcb_s *tcb; + + if (pid == 0) + { + tcb = this_task(); + } + else + { + tcb = nxsched_get_tcb(pid); + } + + if (tcb) + { + if (clock_type == CLOCK_PROCESS_CPUTIME_ID) + { + up_perf_convert(clock_process_runtime(tcb), tp); + } + else if (clock_type == CLOCK_THREAD_CPUTIME_ID) + { + up_perf_convert(tcb->run_time, tp); + } + } +#endif + } +} + /**************************************************************************** * Name: clock_gettime * * Description: * Clock Functions based on POSIX APIs * + * CLOCK_MONOTONIC is an optional under POSIX: "If the Monotonic Clock + * option is supported, all implementations shall support a clock_id + * of CLOCK_MONOTONIC defined in . This clock represents the + * monotonic clock for the system. For this clock, the value returned + * by clock_gettime() represents the amount of time (in seconds and + * nanoseconds) since an unspecified point in the past (for example, + * system start-up time, or the Epoch). This point does not change + * after system start-up time. The value of the CLOCK_MONOTONIC clock + * cannot be set via clock_settime(). This function shall fail if it + * is invoked with a clock_id argument of CLOCK_MONOTONIC." + * + * CLOCK_REALTIME - POSIX demands this to be present. CLOCK_REALTIME + * represents the machine's best-guess as to the current wall-clock, + * time-of-day time. This means that CLOCK_REALTIME can jump forward and + * backward as the system time-of-day clock is changed. + * ****************************************************************************/ -int clock_gettime(clockid_t clock_id, struct timespec *tp) +int clock_gettime(clockid_t clock_id, FAR struct timespec *tp) { -#ifndef CONFIG_CLOCK_TIMEKEEPING - struct timespec ts; -#endif - int ret = OK; - - clockid_t clock_type = clock_id & CLOCK_MASK; -#ifdef CONFIG_SCHED_CRITMONITOR - pid_t pid = clock_id >> CLOCK_SHIFT; -#endif - - DEBUGASSERT(tp != NULL); - - /* CLOCK_MONOTONIC is an optional under POSIX: "If the Monotonic Clock - * option is supported, all implementations shall support a clock_id - * of CLOCK_MONOTONIC defined in . This clock represents the - * monotonic clock for the system. For this clock, the value returned - * by clock_gettime() represents the amount of time (in seconds and - * nanoseconds) since an unspecified point in the past (for example, - * system start-up time, or the Epoch). This point does not change - * after system start-up time. The value of the CLOCK_MONOTONIC clock - * cannot be set via clock_settime(). This function shall fail if it - * is invoked with a clock_id argument of CLOCK_MONOTONIC." - */ - - if (clock_type == CLOCK_MONOTONIC || clock_type == CLOCK_BOOTTIME) + if (tp == NULL || clock_id < 0 || clock_id > CLOCK_BOOTTIME) { - /* The the time elapsed since the timer was initialized at power on - * reset. - */ - - ret = clock_systime_timespec(tp); + set_errno(EINVAL); + return ERROR; } - /* CLOCK_REALTIME - POSIX demands this to be present. CLOCK_REALTIME - * represents the machine's best-guess as to the current wall-clock, - * time-of-day time. This means that CLOCK_REALTIME can jump forward and - * backward as the system time-of-day clock is changed. - */ - - else if (clock_type == CLOCK_REALTIME) - { - /* Get the elapsed time since the time-of-day was last set. - * clock_systime_timespec() provides the time since power was applied; - * the bias value corresponds to the time when the time-of-day was - * last set. - */ - -#if defined(CONFIG_CLOCK_TIMEKEEPING) - ret = clock_timekeeping_get_wall_time(tp); -#else - ret = clock_systime_timespec(&ts); - if (ret == OK) - { - irqstate_t flags; - - /* Add the base time to this. The base time is the time-of-day - * setting. When added to the elapsed time since the time-of-day - * was last set, this gives us the current time. - */ - - flags = spin_lock_irqsave(NULL); - clock_timespec_add(&g_basetime, &ts, tp); - spin_unlock_irqrestore(NULL, flags); - } -#endif /* CONFIG_CLOCK_TIMEKEEPING */ - } -#ifdef CONFIG_SCHED_CRITMONITOR - else if (clock_type == CLOCK_THREAD_CPUTIME_ID) - { - FAR struct tcb_s *tcb; - - if (pid == 0) - { - /* Fetch the THREAD_CPUTIME for current thread */ - - tcb = this_task(); - } - else - { - tcb = nxsched_get_tcb(pid); - } - - if (tcb != NULL) - { - perf_convert(tcb->run_time, tp); - } - else - { - ret = -EFAULT; - } - } - else if (clock_type == CLOCK_PROCESS_CPUTIME_ID) - { - unsigned long runtime; - FAR struct tcb_s *tcb; -# ifdef HAVE_GROUP_MEMBERS - FAR struct task_group_s *group; - FAR sq_entry_t *curr; - FAR sq_entry_t *next; - irqstate_t flags; -# endif - - if (pid == 0) - { - /* Fetch the PROCESS_CPUTIME for current process */ - - tcb = this_task(); - } - else - { - tcb = nxsched_get_tcb(pid); - } - - if (tcb != NULL) - { -# ifdef HAVE_GROUP_MEMBERS - group = tcb->group; - runtime = 0; - - flags = spin_lock_irqsave(NULL); - sq_for_every_safe(&group->tg_members, curr, next) - { - tcb = container_of(curr, struct tcb_s, member); - - runtime += tcb->run_time; - } - - spin_unlock_irqrestore(NULL, flags); -# else /* HAVE_GROUP_MEMBERS */ - runtime = tcb->run_time; -# endif /* HAVE_GROUP_MEMBERS */ - - perf_convert(runtime, tp); - } - else - { - ret = -EFAULT; - } - } -#endif - else - { - ret = -EINVAL; - } - - /* Check for errors and set the errno value if necessary */ - - if (ret < 0) - { - set_errno(-ret); - ret = ERROR; - } - - return ret; + nxclock_gettime(clock_id, tp); + return OK; } diff --git a/sched/clock/clock_settime.c b/sched/clock/clock_settime.c index 0a7d8fcdcf..e07b4fd941 100644 --- a/sched/clock/clock_settime.c +++ b/sched/clock/clock_settime.c @@ -44,105 +44,83 @@ * 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. + * + ****************************************************************************/ + +void nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp) +{ +#ifndef CONFIG_CLOCK_TIMEKEEPING + struct timespec bias; + irqstate_t flags; +# ifdef CONFIG_CLOCK_ADJTIME + const struct timeval zerodelta = { + 0, 0 + }; +# endif + + /* Interrupts are disabled here so that the in-memory time + * representation and the RTC setting will be as close as + * possible. + */ + + flags = enter_critical_section(); + + /* Get the elapsed time since power up (in milliseconds). This is a + * bias value that we need to use to correct the base time. + */ + + clock_systime_timespec(&bias); + clock_timespec_subtract(tp, &bias, &g_basetime); + + leave_critical_section(flags); + + /* Setup the RTC (lo- or high-res) */ + +# ifdef CONFIG_RTC + if (g_rtc_enabled) + { + up_rtc_settime(tp); + } +# endif + +# ifdef CONFIG_CLOCK_ADJTIME + /* Cancel any ongoing adjustment */ + + adjtime(&zerodelta, NULL); +# endif +#else + clock_timekeeping_set_wall_time(tp); +#endif +} + /**************************************************************************** * Name: clock_settime * * Description: * Clock Functions based on POSIX APIs * + * CLOCK_REALTIME - POSIX demands this to be present. This is the wall + * time clock. + * ****************************************************************************/ int clock_settime(clockid_t clock_id, FAR const struct timespec *tp) { -#ifndef CONFIG_CLOCK_TIMEKEEPING - struct timespec bias; - irqstate_t flags; -#endif - -#ifdef CONFIG_CLOCK_ADJTIME - const struct timeval zerodelta = { - 0, 0 - }; - -#endif - - int ret = OK; - - sinfo("clock_id=%d\n", clock_id); - DEBUGASSERT(tp != NULL); - - /* CLOCK_REALTIME - POSIX demands this to be present. This is the wall - * time clock. - */ - - if (clock_id == CLOCK_REALTIME && - tp->tv_nsec >= 0 && tp->tv_nsec < 1000000000) + if (clock_id != CLOCK_REALTIME || tp == NULL || + tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000) { -#ifndef CONFIG_CLOCK_TIMEKEEPING - /* Interrupts are disabled here so that the in-memory time - * representation and the RTC setting will be as close as - * possible. - */ - - flags = enter_critical_section(); - - /* Get the elapsed time since power up (in milliseconds). This is a - * bias value that we need to use to correct the base time. - */ - - clock_systime_timespec(&bias); - - /* Save the new base time. */ - - g_basetime.tv_sec = tp->tv_sec; - g_basetime.tv_nsec = tp->tv_nsec; - - /* Subtract that bias from the basetime so that when the system - * timer is again added to the base time, the result is the current - * time relative to basetime. - */ - - if (g_basetime.tv_nsec < bias.tv_nsec) - { - g_basetime.tv_nsec += NSEC_PER_SEC; - g_basetime.tv_sec--; - } - - /* Result could be negative seconds */ - - g_basetime.tv_nsec -= bias.tv_nsec; - g_basetime.tv_sec -= bias.tv_sec; - - /* Setup the RTC (lo- or high-res) */ - -#ifdef CONFIG_RTC - if (g_rtc_enabled) - { - up_rtc_settime(tp); - } -#endif - -#ifdef CONFIG_CLOCK_ADJTIME - /* Cancel any ongoing adjustment */ - - adjtime(&zerodelta, NULL); -#endif - - leave_critical_section(flags); - - sinfo("basetime=(%ld,%lu) bias=(%ld,%lu)\n", - (long)g_basetime.tv_sec, (unsigned long)g_basetime.tv_nsec, - (long)bias.tv_sec, (unsigned long)bias.tv_nsec); -#else - ret = clock_timekeeping_set_wall_time(tp); -#endif - } - else - { - serr("Returning ERROR\n"); set_errno(EINVAL); - ret = ERROR; + return ERROR; } - return ret; + nxclock_settime(clock_id, tp); + return OK; }