Messages in this thread Patch in this message | | | Date | Wed, 29 Nov 2006 08:41:12 -0800 | From | Stephane Eranian <> | Subject | Re: [PATCH] i386 add idle notifier (take 2) |
| |
Hello,
[This is the second take due to stray '}' in the patch. Sorry about that]
Here is a patch that adds an idle notifier to the i386 tree. The idle notifier functionalities and implementation are identical to the x86_64 idle notifier. We use the idle notifier in the context of perfmon.
The patch is against Andi Kleen's x86_64-2.6.19-rc6-061128-1.bz2 kernel. It may apply to other kernels but it needs some updates to poll_idle() and default_idle() to work correctly.
changelog: - add an idle notifier mechanism to i386 tree
signed-off-by: stephane eranian <eranain@hpl.hp.com>
diff --exclude=.gitignore -urNp linux-2.6.19-rc6-ak.orig/arch/i386/kernel/apic.c linux-2.6.19-rc6-ak.base/arch/i386/kernel/apic.c --- linux-2.6.19-rc6-ak.orig/arch/i386/kernel/apic.c 2006-11-28 13:17:21.000000000 -0800 +++ linux-2.6.19-rc6-ak.base/arch/i386/kernel/apic.c 2006-11-29 06:31:26.000000000 -0800 @@ -36,6 +36,7 @@ #include <asm/hpet.h> #include <asm/i8253.h> #include <asm/nmi.h> +#include <asm/idle.h> #include <mach_apic.h> #include <mach_apicdef.h> @@ -1255,6 +1256,7 @@ fastcall void smp_apic_timer_interrupt(s * Besides, if we don't timer interrupts ignore the global * interrupt lock, which is the WrongThing (tm) to do. */ + exit_idle(); irq_enter(); smp_local_timer_interrupt(); irq_exit(); @@ -1305,6 +1307,7 @@ fastcall void smp_spurious_interrupt(str { unsigned long v; + exit_idle(); irq_enter(); /* * Check if this really is a spurious interrupt and ACK it @@ -1329,6 +1332,7 @@ fastcall void smp_error_interrupt(struct { unsigned long v, v1; + exit_idle(); irq_enter(); /* First tickle the hardware, only then report what went on. -- REW */ v = apic_read(APIC_ESR); diff --exclude=.gitignore -urNp linux-2.6.19-rc6-ak.orig/arch/i386/kernel/cpu/mcheck/p4.c linux-2.6.19-rc6-ak.base/arch/i386/kernel/cpu/mcheck/p4.c --- linux-2.6.19-rc6-ak.orig/arch/i386/kernel/cpu/mcheck/p4.c 2006-11-28 13:16:35.000000000 -0800 +++ linux-2.6.19-rc6-ak.base/arch/i386/kernel/cpu/mcheck/p4.c 2006-11-29 06:31:30.000000000 -0800 @@ -12,6 +12,7 @@ #include <asm/system.h> #include <asm/msr.h> #include <asm/apic.h> +#include <asm/idle.h> #include <asm/therm_throt.h> @@ -59,6 +60,7 @@ static void (*vendor_thermal_interrupt)( fastcall void smp_thermal_interrupt(struct pt_regs *regs) { + exit_idle(); irq_enter(); vendor_thermal_interrupt(regs); irq_exit(); diff --exclude=.gitignore -urNp linux-2.6.19-rc6-ak.orig/arch/i386/kernel/irq.c linux-2.6.19-rc6-ak.base/arch/i386/kernel/irq.c --- linux-2.6.19-rc6-ak.orig/arch/i386/kernel/irq.c 2006-11-28 13:16:35.000000000 -0800 +++ linux-2.6.19-rc6-ak.base/arch/i386/kernel/irq.c 2006-11-29 06:31:34.000000000 -0800 @@ -19,6 +19,8 @@ #include <linux/cpu.h> #include <linux/delay.h> +#include <asm/idle.h> + DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; EXPORT_PER_CPU_SYMBOL(irq_stat); @@ -61,6 +63,7 @@ fastcall unsigned int do_IRQ(struct pt_r union irq_ctx *curctx, *irqctx; u32 *isp; #endif + exit_idle(); if (unlikely((unsigned)irq >= NR_IRQS)) { printk(KERN_EMERG "%s: cannot handle IRQ %d\n", diff --exclude=.gitignore -urNp linux-2.6.19-rc6-ak.orig/arch/i386/kernel/process.c linux-2.6.19-rc6-ak.base/arch/i386/kernel/process.c --- linux-2.6.19-rc6-ak.orig/arch/i386/kernel/process.c 2006-11-28 13:17:21.000000000 -0800 +++ linux-2.6.19-rc6-ak.base/arch/i386/kernel/process.c 2006-11-29 06:55:58.000000000 -0800 @@ -48,6 +48,7 @@ #include <asm/i387.h> #include <asm/desc.h> #include <asm/vm86.h> +#include <asm/idle.h> #ifdef CONFIG_MATH_EMULATION #include <asm/math_emu.h> #endif @@ -80,6 +81,46 @@ void (*pm_idle)(void); EXPORT_SYMBOL(pm_idle); static DEFINE_PER_CPU(unsigned int, cpu_idle_state); +static ATOMIC_NOTIFIER_HEAD(idle_notifier); + +void idle_notifier_register(struct notifier_block *n) +{ + atomic_notifier_chain_register(&idle_notifier, n); +} +EXPORT_SYMBOL_GPL(idle_notifier_register); + +void idle_notifier_unregister(struct notifier_block *n) +{ + atomic_notifier_chain_unregister(&idle_notifier, n); +} +EXPORT_SYMBOL(idle_notifier_unregister); + +static DEFINE_PER_CPU(volatile unsigned long, idle_state); + +void enter_idle(void) +{ + /* needs to be atomic w.r.t. interrupts, not against other CPUs */ + __set_bit(0, &__get_cpu_var(idle_state)); + atomic_notifier_call_chain(&idle_notifier, IDLE_START, NULL); +} + +void __exit_idle(void) +{ + /* needs to be atomic w.r.t. interrupts, not against other CPUs */ + if (__test_and_clear_bit(0, &__get_cpu_var(idle_state)) == 0) + return; + atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); +} + +/* Called from interrupts to signify idle end */ +void exit_idle(void) +{ + /* idle loop has pid 0 */ + if (current->pid) + return; + __exit_idle(); +} + void disable_hlt(void) { hlt_counter++; @@ -184,7 +225,9 @@ void cpu_idle(void) play_dead(); __get_cpu_var(irq_stat).idle_timestamp = jiffies; + enter_idle(); idle(); + __exit_idle(); } preempt_enable_no_resched(); schedule(); diff --exclude=.gitignore -urNp linux-2.6.19-rc6-ak.orig/arch/i386/kernel/smp.c linux-2.6.19-rc6-ak.base/arch/i386/kernel/smp.c --- linux-2.6.19-rc6-ak.orig/arch/i386/kernel/smp.c 2006-11-28 13:16:35.000000000 -0800 +++ linux-2.6.19-rc6-ak.base/arch/i386/kernel/smp.c 2006-11-29 06:31:38.000000000 -0800 @@ -23,6 +23,7 @@ #include <asm/mtrr.h> #include <asm/tlbflush.h> +#include <asm/idle.h> #include <mach_apic.h> /* @@ -629,6 +630,7 @@ fastcall void smp_call_function_interrup /* * At this point the info structure may be out of scope unless wait==1 */ + exit_idle(); irq_enter(); (*func)(info); irq_exit(); diff --exclude=.gitignore -urNp linux-2.6.19-rc6-ak.orig/include/asm-i386/idle.h linux-2.6.19-rc6-ak.base/include/asm-i386/idle.h --- linux-2.6.19-rc6-ak.orig/include/asm-i386/idle.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.19-rc6-ak.base/include/asm-i386/idle.h 2006-11-29 08:31:43.000000000 -0800 @@ -0,0 +1,14 @@ +#ifndef _ASM_I386_IDLE_H +#define _ASM_I386_IDLE_H 1 + +#define IDLE_START 1 +#define IDLE_END 2 + +struct notifier_block; +void idle_notifier_register(struct notifier_block *n); +void idle_notifier_unregister(struct notifier_block *n); + +void exit_idle(void); +void enter_idle(void); + +#endif - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |