diff options
Diffstat (limited to 'features/rt/tasklets-Replace-spin-wait-in-tasklet_kill.patch')
-rw-r--r-- | features/rt/tasklets-Replace-spin-wait-in-tasklet_kill.patch | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/features/rt/tasklets-Replace-spin-wait-in-tasklet_kill.patch b/features/rt/tasklets-Replace-spin-wait-in-tasklet_kill.patch new file mode 100644 index 00000000..1beafa8d --- /dev/null +++ b/features/rt/tasklets-Replace-spin-wait-in-tasklet_kill.patch @@ -0,0 +1,73 @@ +From e7314e8cbafc258fde5e864eafd6661a847790ec Mon Sep 17 00:00:00 2001 +From: Peter Zijlstra <peterz@infradead.org> +Date: Tue, 9 Mar 2021 09:42:09 +0100 +Subject: [PATCH 046/191] tasklets: Replace spin wait in tasklet_kill() + +tasklet_kill() spin waits for TASKLET_STATE_SCHED to be cleared invoking +yield() from inside the loop. yield() is an ill defined mechanism and the +result might still be wasting CPU cycles in a tight loop which is +especially painful in a guest when the CPU running the tasklet is scheduled +out. + +tasklet_kill() is used in teardown paths and not performance critical at +all. Replace the spin wait with wait_var_event(). + +Signed-off-by: Peter Zijlstra <peterz@infradead.org> +Signed-off-by: Thomas Gleixner <tglx@linutronix.de> +Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +--- + kernel/softirq.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/kernel/softirq.c b/kernel/softirq.c +index 7cd63df59e1c..1d910294faf7 100644 +--- a/kernel/softirq.c ++++ b/kernel/softirq.c +@@ -532,6 +532,16 @@ void __tasklet_hi_schedule(struct tasklet_struct *t) + } + EXPORT_SYMBOL(__tasklet_hi_schedule); + ++static inline bool tasklet_clear_sched(struct tasklet_struct *t) ++{ ++ if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) { ++ wake_up_var(&t->state); ++ return true; ++ } ++ ++ return false; ++} ++ + static void tasklet_action_common(struct softirq_action *a, + struct tasklet_head *tl_head, + unsigned int softirq_nr) +@@ -551,8 +561,7 @@ static void tasklet_action_common(struct softirq_action *a, + + if (tasklet_trylock(t)) { + if (!atomic_read(&t->count)) { +- if (!test_and_clear_bit(TASKLET_STATE_SCHED, +- &t->state)) ++ if (!tasklet_clear_sched(t)) + BUG(); + if (t->use_callback) + t->callback(t); +@@ -612,13 +621,11 @@ void tasklet_kill(struct tasklet_struct *t) + if (in_interrupt()) + pr_notice("Attempt to kill tasklet from interrupt\n"); + +- while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { +- do { +- yield(); +- } while (test_bit(TASKLET_STATE_SCHED, &t->state)); +- } ++ while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) ++ wait_var_event(&t->state, !test_bit(TASKLET_STATE_SCHED, &t->state)); ++ + tasklet_unlock_wait(t); +- clear_bit(TASKLET_STATE_SCHED, &t->state); ++ tasklet_clear_sched(t); + } + EXPORT_SYMBOL(tasklet_kill); + +-- +2.19.1 + |