107 lines
3.6 KiB
Diff
107 lines
3.6 KiB
Diff
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-3.2/kernel/hrtimer.c
|
|
===================================================================
|
|
--- linux-3.2.orig/kernel/hrtimer.c
|
|
+++ linux-3.2/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;
|
|
@@ -1046,8 +1033,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);
|
|
|