diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-04-11 15:37:48 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-04-11 15:37:48 +0100 |
commit | 989a44571e0ad793e17e192e7e5247e6fb8760ad (patch) | |
tree | 61a2315cc147e705e7135d48da0501f45b910dcd /xen/common/softirq.c | |
parent | 812471f0d1fb3b455297c3f8130e291eade85abf (diff) | |
download | xen-989a44571e0ad793e17e192e7e5247e6fb8760ad.tar.gz xen-989a44571e0ad793e17e192e7e5247e6fb8760ad.tar.bz2 xen-989a44571e0ad793e17e192e7e5247e6fb8760ad.zip |
Support tasklets in Xen as a more dynamic alternative to softirqs.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/common/softirq.c')
-rw-r--r-- | xen/common/softirq.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/xen/common/softirq.c b/xen/common/softirq.c index b6c2b18886..c3618eb7ca 100644 --- a/xen/common/softirq.c +++ b/xen/common/softirq.c @@ -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 |