summaryrefslogtreecommitdiff
path: root/kernel/timer.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-07-21 15:23:39 +0200
committerSteven Rostedt <rostedt@goodmis.org>2012-04-10 14:34:05 -0400
commitd70d7abb21967e6c1633dbb0e4270668783597d1 (patch)
tree625b49c65f3d17190e1c269c469a730bce37000e /kernel/timer.c
parent0ce44666c0b5aede69312410d6b13138096f9921 (diff)
downloadlinux-rt-d70d7abb21967e6c1633dbb0e4270668783597d1.tar.gz
timers: Avoid the switch timers base set to NULL trick on RT
On RT that code is preemptible, so we cannot assign NULL to timers base as a preempter would spin forever in lock_timer_base(). Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/timer.c')
-rw-r--r--kernel/timer.c40
1 files changed, 32 insertions, 8 deletions
diff --git a/kernel/timer.c b/kernel/timer.c
index d1bc5a9c532a..8a9ca7d1a23c 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -654,6 +654,36 @@ static struct tvec_base *lock_timer_base(struct timer_list *timer,
}
}
+#ifndef CONFIG_PREEMPT_RT_FULL
+static inline struct tvec_base *switch_timer_base(struct timer_list *timer,
+ struct tvec_base *old,
+ struct tvec_base *new)
+{
+ /* See the comment in lock_timer_base() */
+ timer_set_base(timer, NULL);
+ spin_unlock(&old->lock);
+ spin_lock(&new->lock);
+ timer_set_base(timer, new);
+ return new;
+}
+#else
+static inline struct tvec_base *switch_timer_base(struct timer_list *timer,
+ struct tvec_base *old,
+ struct tvec_base *new)
+{
+ /*
+ * We cannot do the above because we might be preempted and
+ * then the preempter would see NULL and loop forever.
+ */
+ if (spin_trylock(&new->lock)) {
+ timer_set_base(timer, new);
+ spin_unlock(&old->lock);
+ return new;
+ }
+ return old;
+}
+#endif
+
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires,
bool pending_only, int pinned)
@@ -699,14 +729,8 @@ __mod_timer(struct timer_list *timer, unsigned long expires,
* handler yet has not finished. This also guarantees that
* the timer is serialized wrt itself.
*/
- if (likely(base->running_timer != timer)) {
- /* See the comment in lock_timer_base() */
- timer_set_base(timer, NULL);
- spin_unlock(&base->lock);
- base = new_base;
- spin_lock(&base->lock);
- timer_set_base(timer, base);
- }
+ if (likely(base->running_timer != timer))
+ base = switch_timer_base(timer, base, new_base);
}
timer->expires = expires;