aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2017-06-12 13:39:49 -0400
committerThomas Gleixner <tglx@linutronix.de>2017-06-12 15:07:41 -0400
commit67edab48caeb75d412706f4b9d3107afd1e07623 (patch)
tree78e85dfdcbcdc724bc8017e3689275176f674fd8
parent5c7a3a3d20a4e175304c0e23809e3d70be8fed8a (diff)
posix-timers: Handle relative posix-timers correctly
The recent rework of the posix timer internals broke the magic posix mechanism, which requires that relative timers are not affected by modifications of the underlying clock. That means relative CLOCK_REALTIME timers cannot use CLOCK_REALTIME, because that can be set and adjusted. The underlying hrtimer switches the clock for these timers to CLOCK_MONOTONIC. That still works, but reading the remaining time of such a timer has been broken in the rework. The old code used the hrtimer internals directly and avoided the posix clock callbacks. Now common_timer_get() uses the underlying kclock->timer_get() callback, which is still CLOCK_REALTIME based. So the remaining time of such a timer is calculated against the wrong time base. Handle it by switching the k_itimer->kclock pointer according to the resulting hrtimer mode. k_itimer->it_clock still contains CLOCK_REALTIME because the timer might be set with ABSTIME later and then it needs to switch back to the realtime posix clock implementation. Fixes: eae1c4ae275f ("posix-timers: Make use of cancel/arm callbacks") Reported-by: Andrei Vagin <avagin@virtuozzo.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: John Stultz <john.stultz@linaro.org> Cc: Cyrill Gorcunov <gorcunov@openvz.org> Link: http://lkml.kernel.org/r/20170609201156.GB21491@outlook.office365.com
-rw-r--r--kernel/time/posix-timers.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 88517dcfe0ca..58c0f60b132f 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -72,6 +72,7 @@ static DEFINE_SPINLOCK(hash_lock);
72 72
73static const struct k_clock * const posix_clocks[]; 73static const struct k_clock * const posix_clocks[];
74static const struct k_clock *clockid_to_kclock(const clockid_t id); 74static const struct k_clock *clockid_to_kclock(const clockid_t id);
75static const struct k_clock clock_realtime, clock_monotonic;
75 76
76/* 77/*
77 * we assume that the new SIGEV_THREAD_ID shares no bits with the other 78 * we assume that the new SIGEV_THREAD_ID shares no bits with the other
@@ -750,6 +751,18 @@ static void common_hrtimer_arm(struct k_itimer *timr, ktime_t expires,
750 enum hrtimer_mode mode; 751 enum hrtimer_mode mode;
751 752
752 mode = absolute ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; 753 mode = absolute ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL;
754 /*
755 * Posix magic: Relative CLOCK_REALTIME timers are not affected by
756 * clock modifications, so they become CLOCK_MONOTONIC based under the
757 * hood. See hrtimer_init(). Update timr->kclock, so the generic
758 * functions which use timr->kclock->clock_get() work.
759 *
760 * Note: it_clock stays unmodified, because the next timer_set() might
761 * use ABSTIME, so it needs to switch back.
762 */
763 if (timr->it_clock == CLOCK_REALTIME)
764 timr->kclock = absolute ? &clock_realtime : &clock_monotonic;
765
753 hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); 766 hrtimer_init(&timr->it.real.timer, timr->it_clock, mode);
754 timr->it.real.timer.function = posix_timer_fn; 767 timr->it.real.timer.function = posix_timer_fn;
755 768