Skip to content

Commit

Permalink
[PATCH] sched: disable preempt in idle tasks
Browse files Browse the repository at this point in the history
Run idle threads with preempt disabled.

Also corrected a bugs in arm26's cpu_idle (make it actually call schedule()).
How did it ever work before?

Might fix the CPU hotplugging hang which Nigel Cunningham noted.

We think the bug hits if the idle thread is preempted after checking
need_resched() and before going to sleep, then the CPU offlined.

After calling stop_machine_run, the CPU eventually returns from preemption and
into the idle thread and goes to sleep.  The CPU will continue executing
previous idle and have no chance to call play_dead.

By disabling preemption until we are ready to explicitly schedule, this bug is
fixed and the idle threads generally become more robust.

From: alexs <[email protected]>

  PPC build fix

From: Yoichi Yuasa <[email protected]>

  MIPS build fix

Signed-off-by: Nick Piggin <[email protected]>
Signed-off-by: Yoichi Yuasa <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Nick Piggin authored and Linus Torvalds committed Nov 9, 2005
1 parent ede3d0f commit 5bfb5d6
Show file tree
Hide file tree
Showing 36 changed files with 125 additions and 43 deletions.
4 changes: 2 additions & 2 deletions arch/arm/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,13 @@ void cpu_idle(void)

if (!idle)
idle = default_idle;
preempt_disable();
leds_event(led_idle_start);
while (!need_resched())
idle();
leds_event(led_idle_end);
preempt_enable();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down
5 changes: 4 additions & 1 deletion arch/arm/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,9 @@ void __cpuexit cpu_die(void)
asmlinkage void __cpuinit secondary_start_kernel(void)
{
struct mm_struct *mm = &init_mm;
unsigned int cpu = smp_processor_id();
unsigned int cpu;

cpu = smp_processor_id();

printk("CPU%u: Booted secondary processor\n", cpu);

Expand All @@ -273,6 +275,7 @@ asmlinkage void __cpuinit secondary_start_kernel(void)
local_flush_tlb_all();

cpu_init();
preempt_disable();

/*
* Give the platform a chance to do its own initialisation.
Expand Down
12 changes: 5 additions & 7 deletions arch/arm26/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,13 @@ __setup("hlt", hlt_setup);
void cpu_idle(void)
{
/* endless idle loop with no priority at all */
preempt_disable();
while (1) {
while (!need_resched()) {
local_irq_disable();
if (!need_resched() && !hlt_counter)
local_irq_enable();
}
while (!need_resched())
cpu_relax();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
schedule();
}

static char reboot_mode = 'h';
Expand Down
1 change: 1 addition & 0 deletions arch/cris/arch-v32/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ void __init smp_callin(void)
REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
unmask_irq(IPI_INTR_VECT);
unmask_irq(TIMER_INTR_VECT);
preempt_disable();
local_irq_enable();

cpu_set(cpu, cpu_online_map);
Expand Down
2 changes: 2 additions & 0 deletions arch/cris/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,9 @@ void cpu_idle (void)
idle = default_idle;
idle();
}
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down
6 changes: 5 additions & 1 deletion arch/frv/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,20 @@ void (*idle)(void) = core_sleep_idle;
*/
void cpu_idle(void)
{
int cpu = smp_processor_id();

/* endless idle loop with no priority at all */
while (1) {
while (!need_resched()) {
irq_stat[smp_processor_id()].idle_timestamp = jiffies;
irq_stat[cpu].idle_timestamp = jiffies;

if (!frv_dma_inprogress && idle)
idle();
}

preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down
28 changes: 15 additions & 13 deletions arch/h8300/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,18 @@ asmlinkage void ret_from_fork(void);
#if !defined(CONFIG_H8300H_SIM) && !defined(CONFIG_H8S_SIM)
void default_idle(void)
{
while(1) {
if (!need_resched()) {
local_irq_enable();
__asm__("sleep");
local_irq_disable();
}
schedule();
}
local_irq_disable();
if (!need_resched()) {
local_irq_enable();
/* XXX: race here! What if need_resched() gets set now? */
__asm__("sleep");
} else
local_irq_enable();
}
#else
void default_idle(void)
{
while(1) {
if (need_resched())
schedule();
}
cpu_relax();
}
#endif
void (*idle)(void) = default_idle;
Expand All @@ -81,7 +77,13 @@ void (*idle)(void) = default_idle;
*/
void cpu_idle(void)
{
idle();
while (1) {
while (!need_resched())
idle();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

void machine_restart(char * __unused)
Expand Down
4 changes: 3 additions & 1 deletion arch/i386/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ static inline void play_dead(void)
*/
void cpu_idle(void)
{
int cpu = raw_smp_processor_id();
int cpu = smp_processor_id();

/* endless idle loop with no priority at all */
while (1) {
Expand All @@ -201,7 +201,9 @@ void cpu_idle(void)
__get_cpu_var(irq_stat).idle_timestamp = jiffies;
idle();
}
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down
1 change: 1 addition & 0 deletions arch/i386/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ static void __devinit start_secondary(void *unused)
* things done here to the most necessary things.
*/
cpu_init();
preempt_disable();
smp_callin();
while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
rep_nop();
Expand Down
2 changes: 2 additions & 0 deletions arch/ia64/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,9 @@ cpu_idle (void)
#ifdef CONFIG_SMP
normal_xtp();
#endif
preempt_enable_no_resched();
schedule();
preempt_disable();
check_pgt_cache();
if (cpu_is_offline(smp_processor_id()))
play_dead();
Expand Down
1 change: 1 addition & 0 deletions arch/ia64/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ start_secondary (void *unused)
Dprintk("start_secondary: starting CPU 0x%x\n", hard_smp_processor_id());
efi_map_pal_code();
cpu_init();
preempt_disable();
smp_callin();

cpu_idle();
Expand Down
2 changes: 2 additions & 0 deletions arch/m32r/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,9 @@ void cpu_idle (void)

idle();
}
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down
1 change: 1 addition & 0 deletions arch/m32r/kernel/smpboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,7 @@ void __init smp_cpus_done(unsigned int max_cpus)
int __init start_secondary(void *unused)
{
cpu_init();
preempt_disable();
smp_callin();
while (!cpu_isset(smp_processor_id(), smp_commenced_mask))
cpu_relax();
Expand Down
2 changes: 2 additions & 0 deletions arch/m68k/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,9 @@ void cpu_idle(void)
while (1) {
while (!need_resched())
idle();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down
2 changes: 2 additions & 0 deletions arch/mips/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ ATTRIB_NORET void cpu_idle(void)
while (!need_resched())
if (cpu_wait)
(*cpu_wait)();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down
4 changes: 3 additions & 1 deletion arch/mips/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ extern ATTRIB_NORET void cpu_idle(void);
*/
asmlinkage void start_secondary(void)
{
unsigned int cpu = smp_processor_id();
unsigned int cpu;

cpu_probe();
cpu_report();
Expand All @@ -95,6 +95,8 @@ asmlinkage void start_secondary(void)
*/

calibrate_delay();
preempt_disable();
cpu = smp_processor_id();
cpu_data[cpu].udelay_val = loops_per_jiffy;

prom_smp_finish();
Expand Down
2 changes: 2 additions & 0 deletions arch/parisc/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ void cpu_idle(void)
while (1) {
while (!need_resched())
barrier();
preempt_enable_no_resched();
schedule();
preempt_disable();
check_pgt_cache();
}
}
Expand Down
1 change: 1 addition & 0 deletions arch/parisc/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ void __init smp_callin(void)
#endif

smp_cpu_init(slave_id);
preempt_disable();

#if 0 /* NOT WORKING YET - see entry.S */
istack = (void *)__get_free_pages(GFP_KERNEL,ISTACK_ORDER);
Expand Down
4 changes: 4 additions & 0 deletions arch/powerpc/platforms/iseries/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,9 @@ static void iseries_shared_idle(void)
if (hvlpevent_is_pending())
process_iSeries_events();

preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down Expand Up @@ -726,7 +728,9 @@ static void iseries_dedicated_idle(void)
}

ppc64_runlatch_on();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

Expand Down
4 changes: 4 additions & 0 deletions arch/powerpc/platforms/pseries/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,9 @@ static void pseries_dedicated_idle(void)
lpaca->lppaca.idle = 0;
ppc64_runlatch_on();

preempt_enable_no_resched();
schedule();
preempt_disable();

if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
Expand Down Expand Up @@ -583,7 +585,9 @@ static void pseries_shared_idle(void)
lpaca->lppaca.idle = 0;
ppc64_runlatch_on();

preempt_enable_no_resched();
schedule();
preempt_disable();

if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
Expand Down
17 changes: 12 additions & 5 deletions arch/ppc/kernel/idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,29 @@ void default_idle(void)
}
#endif
}
if (need_resched())
schedule();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
}

/*
* The body of the idle task.
*/
void cpu_idle(void)
{
for (;;)
int cpu = smp_processor_id();

for (;;) {
if (ppc_md.idle != NULL)
ppc_md.idle();
else
default_idle();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
if (need_resched()) {
preempt_enable_no_resched();
schedule();
preempt_disable();
}

}
}

#if defined(CONFIG_SYSCTL) && defined(CONFIG_6xx)
Expand Down
1 change: 1 addition & 0 deletions arch/ppc/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,7 @@ int __devinit start_secondary(void *unused)
cpu = smp_processor_id();
smp_store_cpu_info(cpu);
set_dec(tb_ticks_per_jiffy);
preempt_disable();
cpu_callin_map[cpu] = 1;

printk("CPU %d done callin...\n", cpu);
Expand Down
4 changes: 4 additions & 0 deletions arch/ppc64/kernel/idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ void default_idle(void)
}

ppc64_runlatch_on();
preempt_enable_no_resched();
schedule();
preempt_disable();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
}
Expand All @@ -77,7 +79,9 @@ void native_idle(void)

if (need_resched()) {
ppc64_runlatch_on();
preempt_enable_no_resched();
schedule();
preempt_disable();
}

if (cpu_is_offline(smp_processor_id()) &&
Expand Down
11 changes: 8 additions & 3 deletions arch/s390/kernel/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ void default_idle(void)
local_irq_disable();
if (need_resched()) {
local_irq_enable();
schedule();
return;
}

Expand Down Expand Up @@ -139,8 +138,14 @@ void default_idle(void)

void cpu_idle(void)
{
for (;;)
default_idle();
for (;;) {
while (!need_resched())
default_idle();

preempt_enable_no_resched();
schedule();
preempt_disable();
}
}

void show_regs(struct pt_regs *regs)
Expand Down
1 change: 1 addition & 0 deletions arch/s390/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,7 @@ int __devinit start_secondary(void *cpuvoid)
{
/* Setup the cpu */
cpu_init();
preempt_disable();
/* init per CPU timer */
init_cpu_timer();
#ifdef CONFIG_VIRT_TIMER
Expand Down
Loading

0 comments on commit 5bfb5d6

Please sign in to comment.