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.stu...@linaro.org>
Cc: Thomas Gleixner <t...@linutronix.de>
Cc: Ingo Molnar <mi...@kernel.org>
Cc: Xunlei Pang <pang.xun...@linaro.org>
Cc: Peter Zijlstra <pet...@infradead.org>
Cc: Baolin Wang <baolin.w...@linaro.org>
Cc: Arnd Bergmann <a...@arndb.de>
Signed-off-by: Prarit Bhargava <pra...@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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to