]> xenbits.xensource.com Git - xen.git/commitdiff
Support tasklets in Xen as a more dynamic alternative to softirqs.
authorKeir Fraser <keir.fraser@citrix.com>
Fri, 11 Apr 2008 14:37:48 +0000 (15:37 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Fri, 11 Apr 2008 14:37:48 +0000 (15:37 +0100)
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
xen/arch/ia64/xen/xensetup.c
xen/arch/x86/setup.c
xen/common/softirq.c
xen/include/xen/softirq.h

index c3aa6bfb46660b1771d1d1f2283f35bc1e1c7045..d6aa79c246bbd72be250fcc50069e785cd9a5ad7 100644 (file)
@@ -576,6 +576,8 @@ skip_move:
 
     end_boot_allocator();
 
+    softirq_init();
+
     late_setup_arch(&cmdline);
 
     scheduler_init();
index 383a868225835953d52d17df39c4d59eb9123780..9b025b51b1f11475d75d5fb5667e68f31078177e 100644 (file)
@@ -861,6 +861,8 @@ void __init __start_xen(unsigned long mbi_p)
 
     early_boot = 0;
 
+    softirq_init();
+
     early_cpu_init();
 
     paging_init();
index b6c2b18886f9d165b389ba740c0b82e4d4c4c1c9..c3618eb7caade0d7d526b7e1f0945a3557a110d7 100644 (file)
@@ -52,6 +52,80 @@ void open_softirq(int nr, softirq_handler handler)
     softirq_handlers[nr] = handler;
 }
 
+static DEFINE_PER_CPU(struct tasklet *, tasklet_list);
+
+void tasklet_schedule(struct tasklet *t)
+{
+    unsigned long flags;
+
+    if ( test_and_set_bool(t->is_scheduled) )
+        return;
+
+    local_irq_save(flags);
+    t->next = this_cpu(tasklet_list);
+    this_cpu(tasklet_list) = t;
+    local_irq_restore(flags);
+
+    raise_softirq(TASKLET_SOFTIRQ);
+}
+
+static void tasklet_action(void)
+{
+    struct tasklet *list, *t;
+
+    local_irq_disable();
+    list = this_cpu(tasklet_list);
+    this_cpu(tasklet_list) = NULL;
+    local_irq_enable();
+
+    while ( (t = list) != NULL )
+    {
+        list = list->next;
+
+        BUG_ON(t->is_running);
+        t->is_running = 1;
+        smp_wmb();
+
+        BUG_ON(!t->is_scheduled);
+        t->is_scheduled = 0;
+
+        smp_mb();
+        t->func(t->data);
+        smp_mb();
+
+        t->is_running = 0;
+    }
+}
+
+void tasklet_kill(struct tasklet *t)
+{
+    /* Prevent tasklet from re-scheduling itself. */
+    while ( t->is_scheduled || test_and_set_bool(t->is_scheduled) )
+        cpu_relax();
+    smp_mb();
+
+    /* Wait for tasklet to complete. */
+    while ( t->is_running )
+        cpu_relax();
+    smp_mb();
+
+    /* Clean up and we're done. */
+    t->is_scheduled = 0;
+}
+
+void tasklet_init(
+    struct tasklet *t, void (*func)(unsigned long), unsigned long data)
+{
+    memset(t, 0, sizeof(*t));
+    t->func = func;
+    t->data = data;
+}
+
+void __init softirq_init(void)
+{
+    open_softirq(TASKLET_SOFTIRQ, tasklet_action);
+}
+
 /*
  * Local variables:
  * mode: C
index 7734b3374d166a436ebb3a9951040f3290389d2a..440bfa6c6cb03f8442c0ee1a73879e137c567841 100644 (file)
@@ -1,24 +1,20 @@
-#ifndef __XEN_SOFTIRQ_H__
+#if !defined(__XEN_SOFTIRQ_H__) && !defined(__ASSEMBLY__)
 #define __XEN_SOFTIRQ_H__
 
-/* Common softirqs come first in the following list. */
-#define TIMER_SOFTIRQ                     0
-#define SCHEDULE_SOFTIRQ                  1
-#define NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ 2
-#define KEYPRESS_SOFTIRQ                  3
-#define NMI_SOFTIRQ                       4
-#define PAGE_SCRUB_SOFTIRQ                5
-#define TRACE_SOFTIRQ                     6
-#define RCU_SOFTIRQ                       7
-#define STOPMACHINE_SOFTIRQ               8
-
-#define NR_COMMON_SOFTIRQS                9
-
-#include <asm/softirq.h>
-
-#define NR_SOFTIRQS (NR_COMMON_SOFTIRQS + NR_ARCH_SOFTIRQS)
-
-#ifndef __ASSEMBLY__
+/* Low-latency softirqs come first in the following list. */
+enum {
+    TIMER_SOFTIRQ = 0,
+    SCHEDULE_SOFTIRQ,
+    NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ,
+    KEYPRESS_SOFTIRQ,
+    NMI_SOFTIRQ,
+    PAGE_SCRUB_SOFTIRQ,
+    TRACE_SOFTIRQ,
+    RCU_SOFTIRQ,
+    STOPMACHINE_SOFTIRQ,
+    TASKLET_SOFTIRQ,
+    NR_COMMON_SOFTIRQS
+};
 
 #include <xen/config.h>
 #include <xen/lib.h>
 #include <asm/bitops.h>
 #include <asm/current.h>
 #include <asm/hardirq.h>
+#include <asm/softirq.h>
+
+#define NR_SOFTIRQS (NR_COMMON_SOFTIRQS + NR_ARCH_SOFTIRQS)
 
 typedef void (*softirq_handler)(void);
 
 asmlinkage void do_softirq(void);
-extern void open_softirq(int nr, softirq_handler handler);
+void open_softirq(int nr, softirq_handler handler);
+void softirq_init(void);
 
 static inline void cpumask_raise_softirq(cpumask_t mask, unsigned int nr)
 {
@@ -56,6 +56,25 @@ static inline void raise_softirq(unsigned int nr)
     set_bit(nr, &softirq_pending(smp_processor_id()));
 }
 
-#endif /* __ASSEMBLY__ */
+/*
+ * TASKLETS -- dynamically-allocatable tasks run in softirq context
+ * on at most one CPU at a time.
+ */
+struct tasklet
+{
+    struct tasklet *next;
+    bool_t is_scheduled;
+    bool_t is_running;
+    void (*func)(unsigned long);
+    unsigned long data;
+};
+
+#define DECLARE_TASKLET(name, func, data) \
+    struct tasklet name = { NULL, 0, 0, func, data }
+
+void tasklet_schedule(struct tasklet *t);
+void tasklet_kill(struct tasklet *t);
+void tasklet_init(
+    struct tasklet *t, void (*func)(unsigned long), unsigned long data);
 
 #endif /* __XEN_SOFTIRQ_H__ */