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>
This commit is contained in:
Thomas Gleixner 2011-07-21 15:23:39 +02:00 committed by Alibek Omarov
parent df33ba0f2a
commit 33003232ee
1 changed files with 32 additions and 8 deletions

View File

@ -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;