clock: refactor clock_gettime clock_settime

Signed-off-by: ligd <liguiding1@xiaomi.com>
This commit is contained in:
ligd 2024-06-05 19:59:23 +08:00 committed by Xiang Xiao
parent 6a2c03732f
commit 07a4233d1d
3 changed files with 210 additions and 240 deletions

View File

@ -732,6 +732,29 @@ void perf_convert(clock_t elapsed, FAR struct timespec *ts);
unsigned long perf_getfreq(void); 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 #undef EXTERN
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -36,7 +36,6 @@
#include <nuttx/arch.h> #include <nuttx/arch.h>
#include <nuttx/sched.h> #include <nuttx/sched.h>
#include <nuttx/spinlock.h> #include <nuttx/spinlock.h>
#include <nuttx/queue.h>
#include "clock/clock.h" #include "clock/clock.h"
#include "sched/sched.h" #include "sched/sched.h"
@ -44,75 +43,67 @@
# include "clock/clock_timekeeping.h" # include "clock/clock_timekeeping.h"
#endif #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 * Public Functions
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: clock_gettime * Name: nxclock_gettime
* *
* Description: * Description:
* Clock Functions based on POSIX APIs * Get the current value of the specified time clock.
* *
****************************************************************************/ ****************************************************************************/
int clock_gettime(clockid_t clock_id, struct timespec *tp) void nxclock_gettime(clockid_t clock_id, FAR struct timespec *tp)
{ {
#ifndef CONFIG_CLOCK_TIMEKEEPING if (clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_BOOTTIME)
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 <time.h>. 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)
{ {
/* The the time elapsed since the timer was initialized at power on /* The the time elapsed since the timer was initialized at power on
* reset. * reset.
*/ */
ret = clock_systime_timespec(tp); clock_systime_timespec(tp);
} }
else if (clock_id == CLOCK_REALTIME)
/* 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)
{ {
#ifndef CONFIG_CLOCK_TIMEKEEPING
struct timespec ts;
irqstate_t flags; irqstate_t flags;
clock_systime_timespec(&ts);
/* Add the base time to this. The base time is the time-of-day /* 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 * setting. When added to the elapsed time since the time-of-day
* was last set, this gives us the current time. * was last set, this gives us the current time.
@ -121,95 +112,73 @@ int clock_gettime(clockid_t clock_id, struct timespec *tp)
flags = spin_lock_irqsave(NULL); flags = spin_lock_irqsave(NULL);
clock_timespec_add(&g_basetime, &ts, tp); clock_timespec_add(&g_basetime, &ts, tp);
spin_unlock_irqrestore(NULL, flags); spin_unlock_irqrestore(NULL, flags);
#else
clock_timekeeping_get_wall_time(tp);
#endif
} }
#endif /* CONFIG_CLOCK_TIMEKEEPING */ else
} {
#ifdef CONFIG_SCHED_CRITMONITOR #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) else if (clock_type == CLOCK_THREAD_CPUTIME_ID)
{ {
FAR struct tcb_s *tcb; up_perf_convert(tcb->run_time, tp);
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 #endif
else
{
ret = -EINVAL;
} }
}
/* Check for errors and set the errno value if necessary */
/****************************************************************************
if (ret < 0) * Name: clock_gettime
{ *
set_errno(-ret); * Description:
ret = ERROR; * Clock Functions based on POSIX APIs
} *
* CLOCK_MONOTONIC is an optional under POSIX: "If the Monotonic Clock
return ret; * option is supported, all implementations shall support a clock_id
* of CLOCK_MONOTONIC defined in <time.h>. 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, FAR struct timespec *tp)
{
if (tp == NULL || clock_id < 0 || clock_id > CLOCK_BOOTTIME)
{
set_errno(EINVAL);
return ERROR;
}
nxclock_gettime(clock_id, tp);
return OK;
} }

View File

@ -45,40 +45,27 @@
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: clock_settime * Name: nxclock_settime
* *
* Description: * Description:
* Clock Functions based on POSIX APIs * 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) void nxclock_settime(clockid_t clock_id, FAR const struct timespec *tp)
{ {
#ifndef CONFIG_CLOCK_TIMEKEEPING #ifndef CONFIG_CLOCK_TIMEKEEPING
struct timespec bias; struct timespec bias;
irqstate_t flags; irqstate_t flags;
#endif # ifdef CONFIG_CLOCK_ADJTIME
#ifdef CONFIG_CLOCK_ADJTIME
const struct timeval zerodelta = { const struct timeval zerodelta = {
0, 0 0, 0
}; };
# endif
#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)
{
#ifndef CONFIG_CLOCK_TIMEKEEPING
/* Interrupts are disabled here so that the in-memory time /* Interrupts are disabled here so that the in-memory time
* representation and the RTC setting will be as close as * representation and the RTC setting will be as close as
* possible. * possible.
@ -91,58 +78,49 @@ int clock_settime(clockid_t clock_id, FAR const struct timespec *tp)
*/ */
clock_systime_timespec(&bias); clock_systime_timespec(&bias);
clock_timespec_subtract(tp, &bias, &g_basetime);
/* Save the new base time. */ leave_critical_section(flags);
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) */ /* Setup the RTC (lo- or high-res) */
#ifdef CONFIG_RTC # ifdef CONFIG_RTC
if (g_rtc_enabled) if (g_rtc_enabled)
{ {
up_rtc_settime(tp); up_rtc_settime(tp);
} }
#endif # endif
#ifdef CONFIG_CLOCK_ADJTIME # ifdef CONFIG_CLOCK_ADJTIME
/* Cancel any ongoing adjustment */ /* Cancel any ongoing adjustment */
adjtime(&zerodelta, NULL); adjtime(&zerodelta, NULL);
#endif # 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 #else
ret = clock_timekeeping_set_wall_time(tp); clock_timekeeping_set_wall_time(tp);
#endif #endif
} }
else
/****************************************************************************
* 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)
{
if (clock_id != CLOCK_REALTIME || tp == NULL ||
tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000)
{ {
serr("Returning ERROR\n");
set_errno(EINVAL); set_errno(EINVAL);
ret = ERROR; return ERROR;
} }
return ret; nxclock_settime(clock_id, tp);
return OK;
} }