# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 974ed9f7364198b2f3be194847e3b0538f88d5d8
# Parent b246f429f683cce73bf7486c37bf6842983fa49f
Fix Xen timer interface to allow migration of timers
among CPUs (using new migrate_timer() call). Fix the
locking protocol in light of this addition.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
diff -r b246f429f683 -r 974ed9f73641 xen/common/timer.c
--- a/xen/common/timer.c Wed Feb 8 16:26:20 2006
+++ b/xen/common/timer.c Wed Feb 8 16:27:32 2006
@@ -161,46 +161,122 @@
cpu_raise_softirq(cpu, TIMER_SOFTIRQ);
}
+static inline void timer_lock(struct timer *timer)
+{
+ unsigned int cpu;
+
+ for ( ; ; )
+ {
+ cpu = timer->cpu;
+ spin_lock(&timers[cpu].lock);
+ if ( likely(timer->cpu == cpu) )
+ break;
+ spin_unlock(&timers[cpu].lock);
+ }
+}
+
+#define timer_lock_irq(t) \
+ do { local_irq_disable(); timer_lock(t); } while ( 0 )
+#define timer_lock_irqsave(t, flags) \
+ do { local_irq_save(flags); timer_lock(t); } while ( 0 )
+
+static inline void timer_unlock(struct timer *timer)
+{
+ spin_unlock(&timers[timer->cpu].lock);
+}
+
+#define timer_unlock_irq(t) \
+ do { timer_unlock(t); local_irq_enable(); } while ( 0 )
+#define timer_unlock_irqrestore(t, flags) \
+ do { timer_unlock(t); local_irq_restore(flags); } while ( 0 )
+
void set_timer(struct timer *timer, s_time_t expires)
{
- int cpu = timer->cpu;
unsigned long flags;
- spin_lock_irqsave(&timers[cpu].lock, flags);
+ timer_lock_irqsave(timer, flags);
+
if ( active_timer(timer) )
__stop_timer(timer);
+
timer->expires = expires;
+
if ( likely(!timer->killed) )
__add_timer(timer);
- spin_unlock_irqrestore(&timers[cpu].lock, flags);
+
+ timer_unlock_irqrestore(timer, flags);
}
void stop_timer(struct timer *timer)
{
- int cpu = timer->cpu;
unsigned long flags;
- spin_lock_irqsave(&timers[cpu].lock, flags);
+ timer_lock_irqsave(timer, flags);
+
if ( active_timer(timer) )
__stop_timer(timer);
- spin_unlock_irqrestore(&timers[cpu].lock, flags);
+
+ timer_unlock_irqrestore(timer, flags);
+}
+
+
+void migrate_timer(struct timer *timer, unsigned int new_cpu)
+{
+ int old_cpu;
+ unsigned long flags;
+
+ for ( ; ; )
+ {
+ if ( (old_cpu = timer->cpu) == new_cpu )
+ return;
+
+ if ( old_cpu < new_cpu )
+ {
+ spin_lock_irqsave(&timers[old_cpu].lock, flags);
+ spin_lock(&timers[new_cpu].lock);
+ }
+ else
+ {
+ spin_lock_irqsave(&timers[new_cpu].lock, flags);
+ spin_lock(&timers[old_cpu].lock);
+ }
+
+ if ( likely(timer->cpu == old_cpu) )
+ break;
+
+ spin_unlock(&timers[old_cpu].lock);
+ spin_unlock_irqrestore(&timers[new_cpu].lock, flags);
+ }
+
+ if ( active_timer(timer) )
+ __stop_timer(timer);
+
+ timer->cpu = new_cpu;
+
+ if ( likely(!timer->killed) )
+ __add_timer(timer);
+
+ spin_unlock(&timers[old_cpu].lock);
+ spin_unlock_irqrestore(&timers[new_cpu].lock, flags);
}
void kill_timer(struct timer *timer)
{
- int cpu = timer->cpu;
+ int cpu;
unsigned long flags;
- BUG_ON(timers[cpu].running == timer);
-
- spin_lock_irqsave(&timers[cpu].lock, flags);
+ BUG_ON(timers[smp_processor_id()].running == timer);
+
+ timer_lock_irqsave(timer, flags);
+
if ( active_timer(timer) )
__stop_timer(timer);
timer->killed = 1;
- spin_unlock_irqrestore(&timers[cpu].lock, flags);
+
+ timer_unlock_irqrestore(timer, flags);
for_each_online_cpu ( cpu )
while ( timers[cpu].running == timer )
diff -r b246f429f683 -r 974ed9f73641 xen/include/xen/timer.h
--- a/xen/include/xen/timer.h Wed Feb 8 16:26:20 2006
+++ b/xen/include/xen/timer.h Wed Feb 8 16:27:32 2006
@@ -66,6 +66,12 @@
extern void stop_timer(struct timer *timer);
/*
+ * Migrate a timer to a different CPU. The timer must have been previously
+ * initialised by init_timer(). The timer may be active.
+ */
+extern void migrate_timer(struct timer *timer, unsigned int new_cpu);
+
+/*
* Deactivate a timer and prevent it from being re-set (future calls to
* set_timer will silently fail). When this function returns it is guaranteed
* that the timer callback handler is not running on any CPU.
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|