Commit a15da49d authored by Andi Kleen's avatar Andi Kleen Committed by Andi Kleen

[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: default avatarAndi Kleen <ak@suse.de>
parent 1c9c0a6c
...@@ -80,25 +80,25 @@ void idle_notifier_unregister(struct notifier_block *n) ...@@ -80,25 +80,25 @@ void idle_notifier_unregister(struct notifier_block *n)
} }
EXPORT_SYMBOL(idle_notifier_unregister); EXPORT_SYMBOL(idle_notifier_unregister);
enum idle_state { CPU_IDLE, CPU_NOT_IDLE };
static DEFINE_PER_CPU(enum idle_state, idle_state) = CPU_NOT_IDLE;
void enter_idle(void) void enter_idle(void)
{ {
__get_cpu_var(idle_state) = CPU_IDLE; write_pda(isidle, 1);
atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL);
} }
static void __exit_idle(void) static void __exit_idle(void)
{ {
__get_cpu_var(idle_state) = CPU_NOT_IDLE; if (read_pda(isidle) == 0)
return;
write_pda(isidle, 0);
atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
} }
/* Called from interrupts to signify idle end */ /* Called from interrupts to signify idle end */
void exit_idle(void) void exit_idle(void)
{ {
if (current->pid | read_pda(irqcount)) /* idle loop has pid 0 */
if (current->pid)
return; return;
__exit_idle(); __exit_idle();
} }
...@@ -220,6 +220,9 @@ void cpu_idle (void) ...@@ -220,6 +220,9 @@ void cpu_idle (void)
play_dead(); play_dead();
enter_idle(); enter_idle();
idle(); idle();
/* In many cases the interrupt that ended idle
has already called exit_idle. But some idle
loops can be woken up without interrupt. */
__exit_idle(); __exit_idle();
} }
......
...@@ -25,7 +25,8 @@ struct x8664_pda { ...@@ -25,7 +25,8 @@ struct x8664_pda {
int nodenumber; /* number of current node */ int nodenumber; /* number of current node */
unsigned int __softirq_pending; unsigned int __softirq_pending;
unsigned int __nmi_count; /* number of NMI on this CPUs */ unsigned int __nmi_count; /* number of NMI on this CPUs */
int mmu_state; short mmu_state;
short isidle;
struct mm_struct *active_mm; struct mm_struct *active_mm;
unsigned apic_timer_irqs; unsigned apic_timer_irqs;
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment