Skip to content

Commit

Permalink
timekeeping: Add the new CLOCK_MONOTONIC_ACTIVE clock
Browse files Browse the repository at this point in the history
The planned change to unify the behaviour of the MONOTONIC and BOOTTIME
clocks vs. suspend removes the ability to retrieve the active
non-suspended time of a system.

Provide a new CLOCK_MONOTONIC_ACTIVE clock which returns the active
non-suspended time of the system via clock_gettime().

This preserves the old behaviour of CLOCK_MONOTONIC before the
BOOTTIME/MONOTONIC unification.

This new clock also allows applications to detect programmatically that
the MONOTONIC and BOOTTIME clocks are identical.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Kevin Easton <kevin@guarana.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mark Salyzyn <salyzyn@android.com>
Cc: Michael Kerrisk <mtk.manpages@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Prarit Bhargava <prarit@redhat.com>
Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/20180301165149.965235774@linutronix.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
KAGA-KOKO authored and Ingo Molnar committed Mar 13, 2018
1 parent 78b98e3 commit 7219932
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/linux/timekeeper_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ struct tk_read_base {
* @offs_real: Offset clock monotonic -> clock realtime
* @offs_boot: Offset clock monotonic -> clock boottime
* @offs_tai: Offset clock monotonic -> clock tai
* @time_suspended: Accumulated suspend time
* @tai_offset: The current UTC to TAI offset in seconds
* @clock_was_set_seq: The sequence number of clock was set events
* @cs_was_changed_seq: The sequence number of clocksource change events
Expand Down Expand Up @@ -94,6 +95,7 @@ struct timekeeper {
ktime_t offs_real;
ktime_t offs_boot;
ktime_t offs_tai;
ktime_t time_suspended;
s32 tai_offset;
unsigned int clock_was_set_seq;
u8 cs_was_changed_seq;
Expand Down
1 change: 1 addition & 0 deletions include/linux/timekeeping.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extern void getrawmonotonic64(struct timespec64 *ts);
extern void ktime_get_ts64(struct timespec64 *ts);
extern time64_t ktime_get_seconds(void);
extern time64_t ktime_get_real_seconds(void);
extern void ktime_get_active_ts64(struct timespec64 *ts);

extern int __getnstimeofday64(struct timespec64 *tv);
extern void getnstimeofday64(struct timespec64 *tv);
Expand Down
1 change: 1 addition & 0 deletions include/uapi/linux/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ struct itimerval {
*/
#define CLOCK_SGI_CYCLE 10
#define CLOCK_TAI 11
#define CLOCK_MONOTONIC_ACTIVE 12

#define MAX_CLOCKS 16
#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC)
Expand Down
2 changes: 2 additions & 0 deletions kernel/time/posix-stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ int do_clock_gettime(clockid_t which_clock, struct timespec64 *tp)
case CLOCK_BOOTTIME:
get_monotonic_boottime64(tp);
break;
case CLOCK_MONOTONIC_ACTIVE:
ktime_get_active_ts64(tp);
default:
return -EINVAL;
}
Expand Down
13 changes: 13 additions & 0 deletions kernel/time/posix-timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,13 @@ static int posix_get_tai(clockid_t which_clock, struct timespec64 *tp)
return 0;
}

static int posix_get_monotonic_active(clockid_t which_clock,
struct timespec64 *tp)
{
ktime_get_active_ts64(tp);
return 0;
}

static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp)
{
tp->tv_sec = 0;
Expand Down Expand Up @@ -1330,6 +1337,11 @@ static const struct k_clock clock_boottime = {
.timer_arm = common_hrtimer_arm,
};

static const struct k_clock clock_monotonic_active = {
.clock_getres = posix_get_hrtimer_res,
.clock_get = posix_get_monotonic_active,
};

static const struct k_clock * const posix_clocks[] = {
[CLOCK_REALTIME] = &clock_realtime,
[CLOCK_MONOTONIC] = &clock_monotonic,
Expand All @@ -1342,6 +1354,7 @@ static const struct k_clock * const posix_clocks[] = {
[CLOCK_REALTIME_ALARM] = &alarm_clock,
[CLOCK_BOOTTIME_ALARM] = &alarm_clock,
[CLOCK_TAI] = &clock_tai,
[CLOCK_MONOTONIC_ACTIVE] = &clock_monotonic_active,
};

static const struct k_clock *clockid_to_kclock(const clockid_t id)
Expand Down
36 changes: 36 additions & 0 deletions kernel/time/timekeeping.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm)
static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
{
tk->offs_boot = ktime_add(tk->offs_boot, delta);

/* Accumulate time spent in suspend */
tk->time_suspended += delta;
}

/*
Expand Down Expand Up @@ -886,6 +889,39 @@ void ktime_get_ts64(struct timespec64 *ts)
}
EXPORT_SYMBOL_GPL(ktime_get_ts64);

/**
* ktime_get_active_ts64 - Get the active non-suspended monotonic clock
* @ts: pointer to timespec variable
*
* The function calculates the monotonic clock from the realtime clock and
* the wall_to_monotonic offset, subtracts the accumulated suspend time and
* stores the result in normalized timespec64 format in the variable
* pointed to by @ts.
*/
void ktime_get_active_ts64(struct timespec64 *ts)
{
struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 tomono, tsusp;
u64 nsec, nssusp;
unsigned int seq;

WARN_ON(timekeeping_suspended);

do {
seq = read_seqcount_begin(&tk_core.seq);
ts->tv_sec = tk->xtime_sec;
nsec = timekeeping_get_ns(&tk->tkr_mono);
tomono = tk->wall_to_monotonic;
nssusp = tk->time_suspended;
} while (read_seqcount_retry(&tk_core.seq, seq));

ts->tv_sec += tomono.tv_sec;
ts->tv_nsec = 0;
timespec64_add_ns(ts, nsec + tomono.tv_nsec);
tsusp = ns_to_timespec64(nssusp);
*ts = timespec64_sub(*ts, tsusp);
}

/**
* ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC
*
Expand Down

0 comments on commit 7219932

Please sign in to comment.