Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.25.2 /kernel/hrtimer.c

Filename:/kernel/hrtimer.c
Lines Added:30
Lines Deleted:4
Also changed in: (Previous) 2.6.25-git20  2.6.25-git19  2.6.25.1  2.6.25-git18  2.6.25-git17  2.6.25-git16 
(Following) 2.6.25.3  2.6.25.4  2.6.25.5  2.6.25.6  2.6.25.7  2.6.25.8 

Location
[  2.6.25.2
  [  kernel
     o  hrtimer.c

Patch

diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 98bee01..c15a359 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -590,7 +590,6 @@ static inline int hrtimer_enqueue_reprogram(struct hrtimer *timer,
          list_add_tail(&timer->cb_entry,
                   &base->cpu_base->cb_pending);
          timer->state = HRTIMER_STATE_PENDING;
-         raise_softirq(HRTIMER_SOFTIRQ);
          return 1;
       default:
          BUG();
@@ -633,6 +632,11 @@ static int hrtimer_switch_to_hres(void)
    return 1;
 }
 
+static inline void hrtimer_raise_softirq(void)
+{
+   raise_softirq(HRTIMER_SOFTIRQ);
+}
+
 #else
 
 static inline int hrtimer_hres_active(void) { return 0; }
@@ -651,6 +655,7 @@ static inline int hrtimer_reprogram(struct hrtimer *timer,
 {
    return 0;
 }
+static inline void hrtimer_raise_softirq(void) { }
 
 #endif /* CONFIG_HIGH_RES_TIMERS */
 
@@ -850,7 +855,7 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
 {
    struct hrtimer_clock_base *base, *new_base;
    unsigned long flags;
-   int ret;
+   int ret, raise;
 
    base = lock_hrtimer_base(timer, &flags);
 
@@ -884,8 +889,18 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
    enqueue_hrtimer(timer, new_base,
          new_base->cpu_base == &__get_cpu_var(hrtimer_bases));
 
+   /*
+    * The timer may be expired and moved to the cb_pending
+    * list. We can not raise the softirq with base lock held due
+    * to a possible deadlock with runqueue lock.
+    */
+   raise = timer->state == HRTIMER_STATE_PENDING;
+
    unlock_hrtimer_base(timer, &flags);
 
+   if (raise)
+      hrtimer_raise_softirq();
+
    return ret;
 }
 EXPORT_SYMBOL_GPL(hrtimer_start);
@@ -1080,8 +1095,19 @@ static void run_hrtimer_pending(struct hrtimer_cpu_base *cpu_base)
           * If the timer was rearmed on another CPU, reprogram
           * the event device.
           */
-         if (timer->base->first == &timer->node)
-            hrtimer_reprogram(timer, timer->base);
+         struct hrtimer_clock_base *base = timer->base;
+
+         if (base->first == &timer->node &&
+             hrtimer_reprogram(timer, base)) {
+            /*
+             * Timer is expired. Thus move it from tree to
+             * pending list again.
+             */
+            __remove_hrtimer(timer, base,
+                   HRTIMER_STATE_PENDING, 0);
+            list_add_tail(&timer->cb_entry,
+                     &base->cpu_base->cb_pending);
+         }
       }
    }
    spin_unlock_irq(&cpu_base->lock);


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.