[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] timers: Track inactive timers and migrate them on cpu offline.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1275480791 -3600
# Node ID 5aabc6f94df5f275647d55caa24780eff0c81355
# Parent  a3bdee5a20daf590ae7a440dad4e3b104b99c620
timers: Track inactive timers and migrate them on cpu offline.

Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/irq.c      |   22 +++-----
 xen/common/domain.c     |    7 --
 xen/common/schedule.c   |   23 --------
 xen/common/timer.c      |  129 +++++++++++++++++++++++++++++++++---------------
 xen/include/xen/timer.h |   85 +++++++++++--------------------
 5 files changed, 131 insertions(+), 135 deletions(-)

diff -r a3bdee5a20da -r 5aabc6f94df5 xen/arch/x86/irq.c
--- a/xen/arch/x86/irq.c        Wed Jun 02 10:54:32 2010 +0100
+++ b/xen/arch/x86/irq.c        Wed Jun 02 13:13:11 2010 +0100
@@ -46,8 +46,6 @@ static DECLARE_BITMAP(used_vectors, NR_V
 
 struct irq_cfg __read_mostly *irq_cfg = NULL;
 
-static struct timer *__read_mostly irq_guest_eoi_timer;
-
 static DEFINE_SPINLOCK(vector_lock);
 
 DEFINE_PER_CPU(vector_irq_t, vector_irq);
@@ -275,18 +273,15 @@ int init_irq_data(void)
     irq_desc = xmalloc_array(struct irq_desc, nr_irqs);
     irq_cfg = xmalloc_array(struct irq_cfg, nr_irqs);
     irq_status = xmalloc_array(int, nr_irqs);
-    irq_guest_eoi_timer = xmalloc_array(struct timer, nr_irqs);
     irq_vector = xmalloc_array(u8, nr_irqs_gsi);
     
-    if (!irq_desc || !irq_cfg || !irq_status ||! irq_vector ||
-        !irq_guest_eoi_timer)
+    if ( !irq_desc || !irq_cfg || !irq_status ||! irq_vector )
         return -ENOMEM;
 
     memset(irq_desc, 0,  nr_irqs * sizeof(*irq_desc));
     memset(irq_cfg, 0,  nr_irqs * sizeof(*irq_cfg));
     memset(irq_status, 0,  nr_irqs * sizeof(*irq_status));
     memset(irq_vector, 0, nr_irqs_gsi * sizeof(*irq_vector));
-    memset(irq_guest_eoi_timer, 0, nr_irqs * sizeof(*irq_guest_eoi_timer));
     
     for (irq = 0; irq < nr_irqs; irq++) {
         desc = irq_to_desc(irq);
@@ -741,6 +736,7 @@ typedef struct {
 #define ACKTYPE_UNMASK 1     /* Unmask PIC hardware (from any CPU)   */
 #define ACKTYPE_EOI    2     /* EOI on the CPU that was interrupted  */
     cpumask_t cpu_eoi_map;   /* CPUs that need to EOI this interrupt */
+    struct timer eoi_timer;
     struct domain *guest[IRQ_MAX_GUESTS];
 } irq_guest_action_t;
 
@@ -850,7 +846,7 @@ static void __do_IRQ_guest(int irq)
 
     if ( already_pending == action->nr_guests )
     {
-        stop_timer(&irq_guest_eoi_timer[irq]);
+        stop_timer(&action->eoi_timer);
         desc->handler->disable(irq);
         desc->status |= IRQ_GUEST_EOI_PENDING;
         for ( i = 0; i < already_pending; ++i )
@@ -866,9 +862,8 @@ static void __do_IRQ_guest(int irq)
              * - skip the timer setup below.
              */
         }
-        init_timer(&irq_guest_eoi_timer[irq],
-                   irq_guest_eoi_timer_fn, desc, smp_processor_id());
-        set_timer(&irq_guest_eoi_timer[irq], NOW() + MILLISECS(1));
+        migrate_timer(&action->eoi_timer, smp_processor_id());
+        set_timer(&action->eoi_timer, NOW() + MILLISECS(1));
     }
 }
 
@@ -979,7 +974,7 @@ static void __pirq_guest_eoi(struct doma
     if ( action->ack_type == ACKTYPE_NONE )
     {
         ASSERT(!test_bit(pirq, d->pirq_mask));
-        stop_timer(&irq_guest_eoi_timer[irq]);
+        stop_timer(&action->eoi_timer);
         _irq_guest_eoi(desc);
     }
 
@@ -1163,6 +1158,7 @@ int pirq_guest_bind(struct vcpu *v, int 
         action->shareable   = will_share;
         action->ack_type    = pirq_acktype(v->domain, pirq);
         cpus_clear(action->cpu_eoi_map);
+        init_timer(&action->eoi_timer, irq_guest_eoi_timer_fn, desc, 0);
 
         desc->depth = 0;
         desc->status |= IRQ_GUEST;
@@ -1267,7 +1263,7 @@ static irq_guest_action_t *__pirq_guest_
         }
         break;
     case ACKTYPE_NONE:
-        stop_timer(&irq_guest_eoi_timer[irq]);
+        stop_timer(&action->eoi_timer);
         _irq_guest_eoi(desc);
         break;
     }
@@ -1309,7 +1305,7 @@ static irq_guest_action_t *__pirq_guest_
     desc->action = NULL;
     desc->status &= ~IRQ_GUEST;
     desc->status &= ~IRQ_INPROGRESS;
-    kill_timer(&irq_guest_eoi_timer[irq]);
+    kill_timer(&action->eoi_timer);
     desc->handler->shutdown(irq);
 
     /* Caller frees the old guest descriptor block. */
diff -r a3bdee5a20da -r 5aabc6f94df5 xen/common/domain.c
--- a/xen/common/domain.c       Wed Jun 02 10:54:32 2010 +0100
+++ b/xen/common/domain.c       Wed Jun 02 13:13:11 2010 +0100
@@ -847,12 +847,7 @@ long do_vcpu_op(int cmd, int vcpuid, XEN
              (set.timeout_abs_ns < NOW()) )
             return -ETIME;
 
-        if ( v->singleshot_timer.cpu != smp_processor_id() )
-        {
-            stop_timer(&v->singleshot_timer);
-            v->singleshot_timer.cpu = smp_processor_id();
-        }
-
+        migrate_timer(&v->singleshot_timer, smp_processor_id());
         set_timer(&v->singleshot_timer, set.timeout_abs_ns);
 
         break;
diff -r a3bdee5a20da -r 5aabc6f94df5 xen/common/schedule.c
--- a/xen/common/schedule.c     Wed Jun 02 10:54:32 2010 +0100
+++ b/xen/common/schedule.c     Wed Jun 02 13:13:11 2010 +0100
@@ -475,18 +475,6 @@ int cpu_disable_scheduler(unsigned int c
                 cpus_setall(v->cpu_affinity);
             }
 
-            /*
-             * Migrate single-shot timers to CPU0. A new cpu will automatically
-             * be chosen when the timer is next re-set.
-             */
-            if ( v->singleshot_timer.cpu == cpu )
-            {
-                int cpu_mig = first_cpu(c->cpu_valid);
-                if ( cpu_mig == cpu )
-                    cpu_mig = next_cpu(cpu_mig, c->cpu_valid);
-                migrate_timer(&v->singleshot_timer, cpu_mig);
-            }
-
             if ( v->processor == cpu )
             {
                 set_bit(_VPF_migrating, &v->pause_flags);
@@ -804,12 +792,7 @@ long do_set_timer_op(s_time_t timeout)
     }
     else
     {
-        if ( v->singleshot_timer.cpu != smp_processor_id() )
-        {
-            stop_timer(&v->singleshot_timer);
-            v->singleshot_timer.cpu = smp_processor_id();
-        }
-
+        migrate_timer(&v->singleshot_timer, smp_processor_id());
         set_timer(&v->singleshot_timer, timeout);
     }
 
@@ -890,8 +873,6 @@ static void vcpu_periodic_timer_work(str
     s_time_t now = NOW();
     uint64_t periodic_next_event;
 
-    ASSERT(!active_timer(&v->periodic_timer));
-
     if ( v->periodic_period == 0 )
         return;
 
@@ -904,7 +885,7 @@ static void vcpu_periodic_timer_work(str
         periodic_next_event = now + v->periodic_period;
     }
 
-    v->periodic_timer.cpu = smp_processor_id();
+    migrate_timer(&v->periodic_timer, smp_processor_id());
     set_timer(&v->periodic_timer, periodic_next_event);
 }
 
diff -r a3bdee5a20da -r 5aabc6f94df5 xen/common/timer.c
--- a/xen/common/timer.c        Wed Jun 02 10:54:32 2010 +0100
+++ b/xen/common/timer.c        Wed Jun 02 13:13:11 2010 +0100
@@ -35,6 +35,7 @@ struct timers {
     struct timer **heap;
     struct timer  *list;
     struct timer  *running;
+    struct list_head inactive;
 } __cacheline_aligned;
 
 static DEFINE_PER_CPU(struct timers, timers);
@@ -169,8 +170,9 @@ static int add_to_list(struct timer **pp
  * TIMER OPERATIONS.
  */
 
-static int remove_entry(struct timers *timers, struct timer *t)
-{
+static int remove_entry(struct timer *t)
+{
+    struct timers *timers = &per_cpu(timers, t->cpu);
     int rc;
 
     switch ( t->status )
@@ -186,15 +188,16 @@ static int remove_entry(struct timers *t
         BUG();
     }
 
-    t->status = TIMER_STATUS_inactive;
+    t->status = TIMER_STATUS_invalid;
     return rc;
 }
 
-static int add_entry(struct timers *timers, struct timer *t)
-{
+static int add_entry(struct timer *t)
+{
+    struct timers *timers = &per_cpu(timers, t->cpu);
     int rc;
 
-    ASSERT(t->status == TIMER_STATUS_inactive);
+    ASSERT(t->status == TIMER_STATUS_invalid);
 
     /* Try to add to heap. t->heap_offset indicates whether we succeed. */
     t->heap_offset = 0;
@@ -209,18 +212,23 @@ static int add_entry(struct timers *time
     return add_to_list(&timers->list, t);
 }
 
-static inline void __add_timer(struct timer *timer)
-{
-    int cpu = timer->cpu;
-    if ( add_entry(&per_cpu(timers, cpu), timer) )
-        cpu_raise_softirq(cpu, TIMER_SOFTIRQ);
-}
-
-static inline void __stop_timer(struct timer *timer)
-{
-    int cpu = timer->cpu;
-    if ( remove_entry(&per_cpu(timers, cpu), timer) )
-        cpu_raise_softirq(cpu, TIMER_SOFTIRQ);
+static inline void activate_timer(struct timer *timer)
+{
+    ASSERT(timer->status == TIMER_STATUS_inactive);
+    timer->status = TIMER_STATUS_invalid;
+    list_del(&timer->inactive);
+
+    if ( add_entry(timer) )
+        cpu_raise_softirq(timer->cpu, TIMER_SOFTIRQ);
+}
+
+static inline void deactivate_timer(struct timer *timer)
+{
+    if ( remove_entry(timer) )
+        cpu_raise_softirq(timer->cpu, TIMER_SOFTIRQ);
+
+    timer->status = TIMER_STATUS_inactive;
+    list_add(&timer->inactive, &per_cpu(timers, timer->cpu).inactive);
 }
 
 static inline void timer_lock(struct timer *timer)
@@ -253,6 +261,32 @@ static inline void timer_unlock(struct t
     do { timer_unlock(t); local_irq_restore(flags); } while ( 0 )
 
 
+static bool_t active_timer(struct timer *timer)
+{
+    ASSERT(timer->status >= TIMER_STATUS_inactive);
+    ASSERT(timer->status <= TIMER_STATUS_in_list);
+    return (timer->status >= TIMER_STATUS_in_heap);
+}
+
+
+void init_timer(
+    struct timer *timer,
+    void        (*function)(void *),
+    void         *data,
+    unsigned int  cpu)
+{
+    unsigned long flags;
+    memset(timer, 0, sizeof(*timer));
+    timer->function = function;
+    timer->data = data;
+    timer->cpu = cpu;
+    timer->status = TIMER_STATUS_inactive;
+    timer_lock_irqsave(timer, flags);
+    list_add(&timer->inactive, &per_cpu(timers, cpu).inactive);
+    timer_unlock_irqrestore(timer, flags);
+}
+
+
 void set_timer(struct timer *timer, s_time_t expires)
 {
     unsigned long flags;
@@ -260,13 +294,13 @@ void set_timer(struct timer *timer, s_ti
     timer_lock_irqsave(timer, flags);
 
     if ( active_timer(timer) )
-        __stop_timer(timer);
+        deactivate_timer(timer);
 
     timer->expires = expires;
     timer->expires_end = expires + timer_slop;
 
     if ( likely(timer->status != TIMER_STATUS_killed) )
-        __add_timer(timer);
+        activate_timer(timer);
 
     timer_unlock_irqrestore(timer, flags);
 }
@@ -279,7 +313,7 @@ void stop_timer(struct timer *timer)
     timer_lock_irqsave(timer, flags);
 
     if ( active_timer(timer) )
-        __stop_timer(timer);
+        deactivate_timer(timer);
 
     timer_unlock_irqrestore(timer, flags);
 }
@@ -287,7 +321,8 @@ void stop_timer(struct timer *timer)
 
 void migrate_timer(struct timer *timer, unsigned int new_cpu)
 {
-    int           old_cpu;
+    int old_cpu;
+    bool_t active;
     unsigned long flags;
 
     for ( ; ; )
@@ -313,16 +348,16 @@ void migrate_timer(struct timer *timer, 
         spin_unlock_irqrestore(&per_cpu(timers, new_cpu).lock, flags);
     }
 
-    if ( active_timer(timer) )
-    {
-        __stop_timer(timer);
-        timer->cpu = new_cpu;
-        __add_timer(timer);
-    }
-    else
-    {
-        timer->cpu = new_cpu;
-    }
+    active = active_timer(timer);
+    if ( active )
+        deactivate_timer(timer);
+
+    list_del(&timer->inactive);
+    timer->cpu = new_cpu;
+    list_add(&timer->inactive, &per_cpu(timers, new_cpu).inactive);
+
+    if ( active )
+        activate_timer(timer);
 
     spin_unlock(&per_cpu(timers, old_cpu).lock);
     spin_unlock_irqrestore(&per_cpu(timers, new_cpu).lock, flags);
@@ -339,7 +374,9 @@ void kill_timer(struct timer *timer)
     timer_lock_irqsave(timer, flags);
 
     if ( active_timer(timer) )
-        __stop_timer(timer);
+        deactivate_timer(timer);
+
+    list_del(&timer->inactive);
     timer->status = TIMER_STATUS_killed;
 
     timer_unlock_irqrestore(timer, flags);
@@ -354,6 +391,9 @@ static void execute_timer(struct timers 
 {
     void (*fn)(void *) = t->function;
     void *data = t->data;
+
+    t->status = TIMER_STATUS_inactive;
+    list_add(&t->inactive, &ts->inactive);
 
     ts->running = t;
     spin_unlock_irq(&ts->lock);
@@ -401,7 +441,6 @@ static void timer_softirq_action(void)
             ((t = heap[1])->expires < now) )
     {
         remove_from_heap(heap, t);
-        t->status = TIMER_STATUS_inactive;
         execute_timer(ts, t);
     }
 
@@ -409,7 +448,6 @@ static void timer_softirq_action(void)
     while ( ((t = ts->list) != NULL) && (t->expires < now) )
     {
         ts->list = t->list_next;
-        t->status = TIMER_STATUS_inactive;
         execute_timer(ts, t);
     }
 
@@ -419,8 +457,8 @@ static void timer_softirq_action(void)
     while ( unlikely((t = next) != NULL) )
     {
         next = t->list_next;
-        t->status = TIMER_STATUS_inactive;
-        add_entry(ts, t);
+        t->status = TIMER_STATUS_invalid;
+        add_entry(t);
     }
 
     ts->overflow = (ts->list != NULL);
@@ -446,7 +484,7 @@ static void timer_softirq_action(void)
         while ( (GET_HEAP_SIZE(heap) != 0) &&
                 ((t = heap[1])->expires <= end) )
         {
-            remove_entry(ts, t);
+            remove_entry(t);
 
             t->status = TIMER_STATUS_in_list;
             t->list_next = NULL;
@@ -529,13 +567,23 @@ static void migrate_timers_from_cpu(unsi
 
     while ( (t = GET_HEAP_SIZE(ts->heap) ? ts->heap[1] : ts->list) != NULL )
     {
-        remove_entry(ts, t);
+        remove_entry(t);
         t->cpu = 0;
-        __add_timer(t);
+        add_entry(t);
+    }
+
+    while ( !list_empty(&ts->inactive) )
+    {
+        t = list_entry(ts->inactive.next, struct timer, inactive);
+        list_del(&t->inactive);
+        t->cpu = 0;
+        list_add(&t->inactive, &per_cpu(timers, 0).inactive);
     }
 
     spin_unlock(&ts->lock);
     spin_unlock_irq(&per_cpu(timers, 0).lock);
+
+    cpu_raise_softirq(0, TIMER_SOFTIRQ);
 }
 
 static struct timer *dummy_heap;
@@ -549,6 +597,7 @@ static int cpu_callback(
     switch ( action )
     {
     case CPU_UP_PREPARE:
+        INIT_LIST_HEAD(&ts->inactive);
         spin_lock_init(&ts->lock);
         ts->heap = &dummy_heap;
         break;
diff -r a3bdee5a20da -r 5aabc6f94df5 xen/include/xen/timer.h
--- a/xen/include/xen/timer.h   Wed Jun 02 10:54:32 2010 +0100
+++ b/xen/include/xen/timer.h   Wed Jun 02 13:13:11 2010 +0100
@@ -11,6 +11,7 @@
 #include <xen/spinlock.h>
 #include <xen/time.h>
 #include <xen/string.h>
+#include <xen/list.h>
 
 struct timer {
     /* System time expiry value (nanoseconds since boot). */
@@ -19,10 +20,12 @@ struct timer {
 
     /* Position in active-timer data structure. */
     union {
-        /* Timer-heap offset. */
+        /* Timer-heap offset (TIMER_STATUS_in_heap). */
         unsigned int heap_offset;
-        /* Linked list. */
+        /* Linked list (TIMER_STATUS_in_list). */
         struct timer *list_next;
+        /* Linked list of inactive timers (TIMER_STATUS_inactive). */
+        struct list_head inactive;
     };
 
     /* On expiry, '(*function)(data)' will be executed in softirq context. */
@@ -33,10 +36,11 @@ struct timer {
     uint16_t cpu;
 
     /* Timer status. */
-#define TIMER_STATUS_inactive 0 /* Not in use; can be activated.    */
-#define TIMER_STATUS_killed   1 /* Not in use; canot be activated.  */
-#define TIMER_STATUS_in_heap  2 /* In use; on timer heap.           */
-#define TIMER_STATUS_in_list  3 /* In use; on overflow linked list. */
+#define TIMER_STATUS_invalid  0 /* Should never see this.           */
+#define TIMER_STATUS_inactive 1 /* Not in use; can be activated.    */
+#define TIMER_STATUS_killed   2 /* Not in use; cannot be activated. */
+#define TIMER_STATUS_in_heap  3 /* In use; on timer heap.           */
+#define TIMER_STATUS_in_list  4 /* In use; on overflow linked list. */
     uint8_t status;
 };
 
@@ -45,67 +49,38 @@ struct timer {
  */
 
 /*
- * Returns TRUE if the given timer is on a timer list.
- * The timer must *previously* have been initialised by init_timer(), or its
- * structure initialised to all-zeroes.
+ * Initialise a timer structure with an initial callback CPU, callback
+ * function and callback data pointer. This function must only be called on
+ * a brand new timer, or a killed timer. It must *never* execute concurrently
+ * with any other operation on the same timer.
  */
-static inline int active_timer(struct timer *timer)
-{
-    return (timer->status >= TIMER_STATUS_in_heap);
-}
+void init_timer(
+    struct timer *timer,
+    void        (*function)(void *),
+    void         *data,
+    unsigned int  cpu);
 
-/*
- * Initialise a timer structure with an initial callback CPU, callback
- * function and callback data pointer. This function may be called at any
- * time (and multiple times) on an inactive timer. It must *never* execute
- * concurrently with any other operation on the same timer.
- */
-static inline void init_timer(
-    struct timer *timer,
-    void           (*function)(void *),
-    void            *data,
-    unsigned int     cpu)
-{
-    memset(timer, 0, sizeof(*timer));
-    timer->function = function;
-    timer->data     = data;
-    timer->cpu      = cpu;
-}
-
-/*
- * Set the expiry time and activate a timer. The timer must *previously* have
- * been initialised by init_timer() (so that callback details are known).
- */
-extern void set_timer(struct timer *timer, s_time_t expires);
+/* Set the expiry time and activate a timer. */
+void set_timer(struct timer *timer, s_time_t expires);
 
 /*
  * Deactivate a timer This function has no effect if the timer is not currently
  * active.
- * The timer must *previously* have been initialised by init_timer(), or its
- * structure initialised to all zeroes.
  */
-extern void stop_timer(struct timer *timer);
+void stop_timer(struct timer *timer);
 
-/*
- * Migrate a timer to a different CPU. The timer may be currently active.
- * The timer must *previously* have been initialised by init_timer(), or its
- * structure initialised to all zeroes.
- */
-extern void migrate_timer(struct timer *timer, unsigned int new_cpu);
+/* Migrate a timer to a different CPU. The timer may be currently active. */
+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.
- * The timer must *previously* have been initialised by init_timer(), or its
- * structure initialised to all zeroes.
  */
-extern void kill_timer(struct timer *timer);
+void kill_timer(struct timer *timer);
 
-/*
- * Bootstrap initialisation. Must be called before any other timer function.
- */
-extern void timer_init(void);
+/* Bootstrap initialisation. Must be called before any other timer function. */
+void timer_init(void);
 
 /*
  * Next timer deadline for each CPU.
@@ -115,10 +90,10 @@ DECLARE_PER_CPU(s_time_t, timer_deadline
 DECLARE_PER_CPU(s_time_t, timer_deadline_end);
 
 /* Arch-defined function to reprogram timer hardware for new deadline. */
-extern int reprogram_timer(s_time_t timeout);
+int reprogram_timer(s_time_t timeout);
 
-/* calculate the aligned first tick time for a given periodic timer */ 
-extern s_time_t align_timer(s_time_t firsttick, uint64_t period);
+/* Calculate the aligned first tick time for a given periodic timer. */
+s_time_t align_timer(s_time_t firsttick, uint64_t period);
 
 #endif /* _TIMER_H_ */
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.