diff options
| author | Andi Kleen <ak@suse.de> | 2006-09-26 04:52:40 -0400 |
|---|---|---|
| committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:40 -0400 |
| commit | a15da49debaf7f09460a886b0ecd08588410715e (patch) | |
| tree | 685ed022695ff03cec167c6690815e08191a803c /arch | |
| parent | 1c9c0a6ca35e9325cea811d734d6ab7352be086b (diff) | |
[PATCH] Fix idle notifiers
Previously exit_idle would be called more often than enter_idle
Now instead of using complicated tests just keep track of it
using the per CPU variable as a flip flop. I moved the idle state into the
PDA to make the access more efficient.
Original bug report and an initial patch from Stephane Eranian,
but redone by AK.
Cc: Stephane Eranian <eranian@hpl.hp.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch')
| -rw-r--r-- | arch/x86_64/kernel/process.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index 885c318f76ab..458006ae19f3 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c | |||
| @@ -80,25 +80,25 @@ void idle_notifier_unregister(struct notifier_block *n) | |||
| 80 | } | 80 | } |
| 81 | EXPORT_SYMBOL(idle_notifier_unregister); | 81 | EXPORT_SYMBOL(idle_notifier_unregister); |
| 82 | 82 | ||
| 83 | enum idle_state { CPU_IDLE, CPU_NOT_IDLE }; | ||
| 84 | static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE; | ||
| 85 | |||
| 86 | void enter_idle(void) | 83 | void enter_idle(void) |
| 87 | { | 84 | { |
| 88 | __get_cpu_var(idle_state) = CPU_IDLE; | 85 | write_pda(isidle, 1); |
| 89 | atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); | 86 | atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); |
| 90 | } | 87 | } |
| 91 | 88 | ||
| 92 | static void __exit_idle(void) | 89 | static void __exit_idle(void) |
| 93 | { | 90 | { |
| 94 | __get_cpu_var(idle_state) = CPU_NOT_IDLE; | 91 | if (read_pda(isidle) == 0) |
| 92 | return; | ||
| 93 | write_pda(isidle, 0); | ||
| 95 | atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); | 94 | atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); |
| 96 | } | 95 | } |
| 97 | 96 | ||
| 98 | /* Called from interrupts to signify idle end */ | 97 | /* Called from interrupts to signify idle end */ |
| 99 | void exit_idle(void) | 98 | void exit_idle(void) |
| 100 | { | 99 | { |
| 101 | if (current->pid | read_pda(irqcount)) | 100 | /* idle loop has pid 0 */ |
| 101 | if (current->pid) | ||
| 102 | return; | 102 | return; |
| 103 | __exit_idle(); | 103 | __exit_idle(); |
| 104 | } | 104 | } |
| @@ -220,6 +220,9 @@ void cpu_idle (void) | |||
| 220 | play_dead(); | 220 | play_dead(); |
| 221 | enter_idle(); | 221 | enter_idle(); |
| 222 | idle(); | 222 | idle(); |
| 223 | /* In many cases the interrupt that ended idle | ||
| 224 | has already called exit_idle. But some idle | ||
| 225 | loops can be woken up without interrupt. */ | ||
| 223 | __exit_idle(); | 226 | __exit_idle(); |
| 224 | } | 227 | } |
| 225 | 228 | ||
