diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2011-07-21 15:23:39 +0200 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2012-04-10 14:34:05 -0400 |
commit | d70d7abb21967e6c1633dbb0e4270668783597d1 (patch) | |
tree | 625b49c65f3d17190e1c269c469a730bce37000e /kernel/timer.c | |
parent | 0ce44666c0b5aede69312410d6b13138096f9921 (diff) | |
download | linux-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.c | 40 |
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; |