Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-block.git] / kernel / time / alarmtimer.c
index b7d75a9e8ccf17c7b616b649e8d76bd5522561b4..271ce6c12907860bc2db9ae94fab4e70dbedbbfb 100644 (file)
@@ -432,7 +432,7 @@ int alarm_cancel(struct alarm *alarm)
                int ret = alarm_try_to_cancel(alarm);
                if (ret >= 0)
                        return ret;
-               cpu_relax();
+               hrtimer_cancel_wait_running(&alarm->timer);
        }
 }
 EXPORT_SYMBOL_GPL(alarm_cancel);
@@ -605,6 +605,19 @@ static int alarm_timer_try_to_cancel(struct k_itimer *timr)
        return alarm_try_to_cancel(&timr->it.alarm.alarmtimer);
 }
 
+/**
+ * alarm_timer_wait_running - Posix timer callback to wait for a timer
+ * @timr:      Pointer to the posixtimer data struct
+ *
+ * Called from the core code when timer cancel detected that the callback
+ * is running. @timr is unlocked and rcu read lock is held to prevent it
+ * from being freed.
+ */
+static void alarm_timer_wait_running(struct k_itimer *timr)
+{
+       hrtimer_cancel_wait_running(&timr->it.alarm.alarmtimer.timer);
+}
+
 /**
  * alarm_timer_arm - Posix timer callback to arm a timer
  * @timr:      Pointer to the posixtimer data struct
@@ -834,6 +847,7 @@ const struct k_clock alarm_clock = {
        .timer_forward          = alarm_timer_forward,
        .timer_remaining        = alarm_timer_remaining,
        .timer_try_to_cancel    = alarm_timer_try_to_cancel,
+       .timer_wait_running     = alarm_timer_wait_running,
        .nsleep                 = alarm_timer_nsleep,
 };
 #endif /* CONFIG_POSIX_TIMERS */