diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2011-07-21 13:23:39 (GMT) |
---|---|---|
committer | Scott Wood <scottwood@freescale.com> | 2015-02-13 22:20:29 (GMT) |
commit | 6cb009abe8ec043594c04c33210f1a819d662b62 (patch) | |
tree | 78baa1fbdec6bff3c147c1672e4339ae8879df62 /kernel/timer.c | |
parent | e8c0d055c13346ef17af2f326694c81aa5b81cd1 (diff) | |
download | linux-fsl-qoriq-6cb009abe8ec043594c04c33210f1a819d662b62.tar.xz |
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 5d4657f..f04db01 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -723,6 +723,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) @@ -761,14 +791,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; |