aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/softirq.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-04-15 15:03:40 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-04-15 15:03:40 +0100
commitc6b465270554f67e8fd3074f7ddb9fc531958613 (patch)
tree2a1d183eff191aa76fa15003faf150b85722b3a1 /xen/common/softirq.c
parenta20735e84bc1d319f523cb179d0bfba764891038 (diff)
downloadxen-c6b465270554f67e8fd3074f7ddb9fc531958613.tar.gz
xen-c6b465270554f67e8fd3074f7ddb9fc531958613.tar.bz2
xen-c6b465270554f67e8fd3074f7ddb9fc531958613.zip
Tasklet bug fixes.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/common/softirq.c')
-rw-r--r--xen/common/softirq.c61
1 files changed, 39 insertions, 22 deletions
diff --git a/xen/common/softirq.c b/xen/common/softirq.c
index 1888d17112..be4728f2e0 100644
--- a/xen/common/softirq.c
+++ b/xen/common/softirq.c
@@ -61,15 +61,18 @@ void tasklet_schedule(struct tasklet *t)
spin_lock_irqsave(&tasklet_lock, flags);
- if ( !t->is_scheduled )
+ if ( !t->is_dead )
{
- list_add(&t->list, &tasklet_list);
+ if ( !t->is_scheduled && !t->is_running )
+ {
+ BUG_ON(!list_empty(&t->list));
+ list_add_tail(&t->list, &tasklet_list);
+ }
t->is_scheduled = 1;
+ raise_softirq(TASKLET_SOFTIRQ);
}
spin_unlock_irqrestore(&tasklet_lock, flags);
-
- raise_softirq(TASKLET_SOFTIRQ);
}
static void tasklet_action(void)
@@ -78,24 +81,38 @@ static void tasklet_action(void)
spin_lock_irq(&tasklet_lock);
- while ( !list_empty(&tasklet_list) )
+ if ( list_empty(&tasklet_list) )
{
- t = list_entry(tasklet_list.next, struct tasklet, list);
- list_del(&t->list);
+ spin_unlock_irq(&tasklet_lock);
+ return;
+ }
+
+ t = list_entry(tasklet_list.next, struct tasklet, list);
+ list_del_init(&t->list);
- BUG_ON(!t->is_scheduled);
- t->is_scheduled = 0;
+ BUG_ON(t->is_dead || t->is_running || !t->is_scheduled);
+ t->is_scheduled = 0;
+ t->is_running = 1;
- BUG_ON(t->is_running);
- t->is_running = 1;
+ spin_unlock_irq(&tasklet_lock);
+ t->func(t->data);
+ spin_lock_irq(&tasklet_lock);
- spin_unlock_irq(&tasklet_lock);
- t->func(t->data);
- spin_lock_irq(&tasklet_lock);
+ t->is_running = 0;
- t->is_running = 0;
+ if ( t->is_scheduled )
+ {
+ BUG_ON(t->is_dead || !list_empty(&t->list));
+ list_add_tail(&t->list, &tasklet_list);
}
+ /*
+ * If there is more work to do then reschedule. We don't grab more work
+ * immediately as we want to allow other softirq work to happen first.
+ */
+ if ( !list_empty(&tasklet_list) )
+ raise_softirq(TASKLET_SOFTIRQ);
+
spin_unlock_irq(&tasklet_lock);
}
@@ -105,12 +122,14 @@ void tasklet_kill(struct tasklet *t)
spin_lock_irqsave(&tasklet_lock, flags);
- /* De-schedule the tasklet and prevent it from re-scheduling itself. */
if ( !list_empty(&t->list) )
- list_del(&t->list);
- t->is_scheduled = 1;
+ {
+ BUG_ON(t->is_dead || t->is_running || !t->is_scheduled);
+ list_del_init(&t->list);
+ }
+ t->is_scheduled = 0;
+ t->is_dead = 1;
- /* Wait for tasklet to complete. */
while ( t->is_running )
{
spin_unlock_irqrestore(&tasklet_lock, flags);
@@ -118,9 +137,6 @@ void tasklet_kill(struct tasklet *t)
spin_lock_irqsave(&tasklet_lock, flags);
}
- /* Clean up and we're done. */
- t->is_scheduled = 0;
-
spin_unlock_irqrestore(&tasklet_lock, flags);
}
@@ -128,6 +144,7 @@ void tasklet_init(
struct tasklet *t, void (*func)(unsigned long), unsigned long data)
{
memset(t, 0, sizeof(*t));
+ INIT_LIST_HEAD(&t->list);
t->func = func;
t->data = data;
}