Messages in this thread Patch in this message | | | From | Prarit Bhargava <> | Subject | [PATCH 1/2] kernel, timekeeping, add trylock option to ktime_get_with_offset() | Date | Wed, 6 Jan 2016 08:00:33 -0500 |
| |
This is a timekeeping staging patch for the printk() timestamp functionality that adds a trylock option for the timekeeping_lock() to ktime_get_with_offset(). When trylock is 1, calls to ktime_get_with_offset() will return return a ktime of 0 if the timekeeping_lock is locked.
This patch adds ktime_try_real(), ktime_try_boot(), and ktime_try_tai() as wrapper functions around ktime_get_with_offset() with trylock = 1, and modifies other callers to call ktime_get_with_offset() with trylock = 0.
Cc: John Stultz <john.stultz@linaro.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@kernel.org> Cc: Xunlei Pang <pang.xunlei@linaro.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Baolin Wang <baolin.wang@linaro.org> Cc: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Prarit Bhargava <prarit@redhat.com> --- include/linux/timekeeping.h | 50 +++++++++++++++++++++++++++++++++++++++---- kernel/time/timekeeping.c | 15 ++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-)
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index ec89d84..4f47352 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -166,7 +166,7 @@ enum tk_offsets { }; extern ktime_t ktime_get(void); -extern ktime_t ktime_get_with_offset(enum tk_offsets offs); +extern ktime_t ktime_get_with_offset(enum tk_offsets offs, int trylock); extern ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs); extern ktime_t ktime_get_raw(void); extern u32 ktime_get_resolution_ns(void); @@ -176,7 +176,16 @@ extern u32 ktime_get_resolution_ns(void); */ static inline ktime_t ktime_get_real(void) { - return ktime_get_with_offset(TK_OFFS_REAL); + return ktime_get_with_offset(TK_OFFS_REAL, 0); +} + +/** + * ktime_try_real - same as ktime_get_real, except return 0 if timekeeping is + * locked. + */ +static inline ktime_t ktime_try_real(void) +{ + return ktime_get_with_offset(TK_OFFS_REAL, 1); } /** @@ -187,7 +196,16 @@ static inline ktime_t ktime_get_real(void) */ static inline ktime_t ktime_get_boottime(void) { - return ktime_get_with_offset(TK_OFFS_BOOT); + return ktime_get_with_offset(TK_OFFS_BOOT, 0); +} + +/** + * ktime_try_boottime - same as ktime_get_bootime, except return 0 if + * timekeeping is locked. + */ +static inline ktime_t ktime_try_boottime(void) +{ + return ktime_get_with_offset(TK_OFFS_BOOT, 1); } /** @@ -195,7 +213,16 @@ static inline ktime_t ktime_get_boottime(void) */ static inline ktime_t ktime_get_clocktai(void) { - return ktime_get_with_offset(TK_OFFS_TAI); + return ktime_get_with_offset(TK_OFFS_TAI, 0); +} + +/** + * ktime_try_clocktai - same as ktime_get_clocktai, except return 0 if + * timekeeping is locked. + */ +static inline ktime_t ktime_try_clocktai(void) +{ + return ktime_get_with_offset(TK_OFFS_TAI, 1); } /** @@ -216,16 +243,31 @@ static inline u64 ktime_get_real_ns(void) return ktime_to_ns(ktime_get_real()); } +static inline u64 ktime_try_real_ns(void) +{ + return ktime_to_ns(ktime_try_real()); +} + static inline u64 ktime_get_boot_ns(void) { return ktime_to_ns(ktime_get_boottime()); } +static inline u64 ktime_try_boot_ns(void) +{ + return ktime_to_ns(ktime_try_boottime()); +} + static inline u64 ktime_get_tai_ns(void) { return ktime_to_ns(ktime_get_clocktai()); } +static inline u64 ktime_try_tai_ns(void) +{ + return ktime_to_ns(ktime_try_clocktai()); +} + static inline u64 ktime_get_raw_ns(void) { return ktime_to_ns(ktime_get_raw()); diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index d563c19..6e2cbeb 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -44,6 +44,8 @@ static struct { static DEFINE_RAW_SPINLOCK(timekeeper_lock); static struct timekeeper shadow_timekeeper; +/* printk may call ktime_get_with_offset() before timekeeping is initialized. */ +static int timekeeping_initialized; /** * struct tk_fast - NMI safe timekeeper * @seq: Sequence counter for protecting updates. The lowest bit @@ -705,15 +707,22 @@ static ktime_t *offsets[TK_OFFS_MAX] = { [TK_OFFS_TAI] = &tk_core.timekeeper.offs_tai, }; -ktime_t ktime_get_with_offset(enum tk_offsets offs) +ktime_t ktime_get_with_offset(enum tk_offsets offs, int trylock) { struct timekeeper *tk = &tk_core.timekeeper; unsigned int seq; ktime_t base, *offset = offsets[offs]; s64 nsecs; + unsigned long flags = 0; + + if (unlikely(!timekeeping_initialized)) + return ktime_set(0, 0); WARN_ON(timekeeping_suspended); + if (trylock && !raw_spin_trylock_irqsave(&timekeeper_lock, flags)) + return ktime_set(KTIME_MAX, 0); + do { seq = read_seqcount_begin(&tk_core.seq); base = ktime_add(tk->tkr_mono.base, *offset); @@ -721,6 +730,9 @@ ktime_t ktime_get_with_offset(enum tk_offsets offs) } while (read_seqcount_retry(&tk_core.seq, seq)); + if (trylock) + raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + return ktime_add_ns(base, nsecs); } @@ -1255,6 +1267,7 @@ void __init timekeeping_init(void) write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + timekeeping_initialized = 1; } /* time in seconds when suspend began for persistent clock */ -- 1.7.9.3
| |