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);
/****************************************************************************
* 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
}

View File

@ -36,7 +36,6 @@
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/spinlock.h>
#include <nuttx/queue.h>
#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 <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, 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 <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)
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;
}

View File

@ -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;
}