| Subject: hrtimer: Don't call the timer handler from hrtimer_start |
| From: Peter Zijlstra <a.p.zijlstra@chello.nl> |
| Date: Fri Aug 12 17:39:54 CEST 2011 |
| |
| [<ffffffff812de4a9>] __delay+0xf/0x11 |
| [<ffffffff812e36e9>] do_raw_spin_lock+0xd2/0x13c |
| [<ffffffff815028ee>] _raw_spin_lock+0x60/0x73 rt_b->rt_runtime_lock |
| [<ffffffff81068f68>] ? sched_rt_period_timer+0xad/0x281 |
| [<ffffffff81068f68>] sched_rt_period_timer+0xad/0x281 |
| [<ffffffff8109e5e1>] __run_hrtimer+0x1e4/0x347 |
| [<ffffffff81068ebb>] ? enqueue_rt_entity+0x36/0x36 |
| [<ffffffff8109f2b1>] __hrtimer_start_range_ns+0x2b5/0x40a base->cpu_base->lock (lock_hrtimer_base) |
| [<ffffffff81068b6f>] __enqueue_rt_entity+0x26f/0x2aa rt_b->rt_runtime_lock (start_rt_bandwidth) |
| [<ffffffff81068ead>] enqueue_rt_entity+0x28/0x36 |
| [<ffffffff81069355>] enqueue_task_rt+0x3d/0xb0 |
| [<ffffffff810679d6>] enqueue_task+0x5d/0x64 |
| [<ffffffff810714fc>] task_setprio+0x210/0x29c rq->lock |
| [<ffffffff810b56cb>] __rt_mutex_adjust_prio+0x25/0x2a p->pi_lock |
| [<ffffffff810b5d2c>] task_blocks_on_rt_mutex+0x196/0x20f |
| |
| Instead make __hrtimer_start_range_ns() return -ETIME when the timer |
| is in the past. Since body actually uses the hrtimer_start*() return |
| value its pretty safe to wreck it. |
| |
| Also, it will only ever return -ETIME for timer->irqsafe || !wakeup |
| timers. |
| |
| Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> |
| --- |
| kernel/hrtimer.c | 48 +++++++++++++++++++++++------------------------- |
| 1 file changed, 23 insertions(+), 25 deletions(-) |
| |
| Index: linux-stable/kernel/hrtimer.c |
| =================================================================== |
| --- linux-stable.orig/kernel/hrtimer.c |
| +++ linux-stable/kernel/hrtimer.c |
| @@ -646,37 +646,24 @@ static inline int hrtimer_enqueue_reprog |
| struct hrtimer_clock_base *base, |
| int wakeup) |
| { |
| -#ifdef CONFIG_PREEMPT_RT_BASE |
| -again: |
| if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) { |
| + if (!wakeup) |
| + return -ETIME; |
| + |
| +#ifdef CONFIG_PREEMPT_RT_BASE |
| /* |
| * Move softirq based timers away from the rbtree in |
| * case it expired already. Otherwise we would have a |
| * stale base->first entry until the softirq runs. |
| */ |
| - if (!hrtimer_rt_defer(timer)) { |
| - ktime_t now = ktime_get(); |
| - |
| - __run_hrtimer(timer, &now); |
| - /* |
| - * __run_hrtimer might have requeued timer and |
| - * it could be base->first again. |
| - */ |
| - if (&timer->node == base->active.next) |
| - goto again; |
| - return 1; |
| - } |
| -#else |
| - if (base->cpu_base->hres_active && hrtimer_reprogram(timer, base)) { |
| + if (!hrtimer_rt_defer(timer)) |
| + return -ETIME; |
| #endif |
| - if (wakeup) { |
| - raw_spin_unlock(&base->cpu_base->lock); |
| - raise_softirq_irqoff(HRTIMER_SOFTIRQ); |
| - raw_spin_lock(&base->cpu_base->lock); |
| - } else |
| - __raise_softirq_irqoff(HRTIMER_SOFTIRQ); |
| + raw_spin_unlock(&base->cpu_base->lock); |
| + raise_softirq_irqoff(HRTIMER_SOFTIRQ); |
| + raw_spin_lock(&base->cpu_base->lock); |
| |
| - return 1; |
| + return 0; |
| } |
| |
| return 0; |
| @@ -1067,8 +1054,19 @@ int __hrtimer_start_range_ns(struct hrti |
| * |
| * XXX send_remote_softirq() ? |
| */ |
| - if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) |
| - hrtimer_enqueue_reprogram(timer, new_base, wakeup); |
| + if (leftmost && new_base->cpu_base == &__get_cpu_var(hrtimer_bases)) { |
| + ret = hrtimer_enqueue_reprogram(timer, new_base, wakeup); |
| + if (ret) { |
| + /* |
| + * In case we failed to reprogram the timer (mostly |
| + * because out current timer is already elapsed), |
| + * remove it again and report a failure. This avoids |
| + * stale base->first entries. |
| + */ |
| + __remove_hrtimer(timer, new_base, |
| + timer->state & HRTIMER_STATE_CALLBACK, 0); |
| + } |
| + } |
| |
| unlock_hrtimer_base(timer, &flags); |
| |