From: Ingo Molnar This patch tweaks cpu_idle() semantics a bit: it changes the idle loops (that do preemption) to call the first schedule() unconditionally. The advantage is that as a result we dont have to set the idle thread's NEED_RESCHED flag in init_idle(), which in turn makes cond_resched() even more of an invariant: it can be called even from init code without it having any effect. A cond resched in the init codepath hangs otherwise. This patch, while having no negative side-effects, enables wider use of cond_resched()s. (which might happen in the stock kernel too, but it's particulary important for voluntary-preempt) (note that for now this patch only covers architectures that use kernel/Kconfig.preempt, but all other architectures will work just fine too.) Signed-off-by: Ingo Molnar Acked-by: Nick Piggin Signed-off-by: Andrew Morton --- arch/i386/kernel/process.c | 2 ++ arch/ppc64/kernel/idle.c | 1 + arch/x86_64/kernel/process.c | 2 ++ kernel/sched.c | 10 +++++++++- 4 files changed, 14 insertions(+), 1 deletion(-) diff -puN arch/i386/kernel/process.c~sched-remove-set_tsk_need_resched-from-init_idle-v2 arch/i386/kernel/process.c --- 25/arch/i386/kernel/process.c~sched-remove-set_tsk_need_resched-from-init_idle-v2 2005-05-25 00:53:41.000000000 -0700 +++ 25-akpm/arch/i386/kernel/process.c 2005-05-25 00:53:41.000000000 -0700 @@ -183,6 +183,8 @@ void cpu_idle(void) { int cpu = _smp_processor_id(); + set_tsk_need_resched(current); + /* endless idle loop with no priority at all */ while (1) { while (!need_resched()) { diff -puN arch/ppc64/kernel/idle.c~sched-remove-set_tsk_need_resched-from-init_idle-v2 arch/ppc64/kernel/idle.c --- 25/arch/ppc64/kernel/idle.c~sched-remove-set_tsk_need_resched-from-init_idle-v2 2005-05-25 00:53:41.000000000 -0700 +++ 25-akpm/arch/ppc64/kernel/idle.c 2005-05-25 00:53:41.000000000 -0700 @@ -305,6 +305,7 @@ static int native_idle(void) void cpu_idle(void) { + set_tsk_need_resched(current); idle_loop(); } diff -puN arch/x86_64/kernel/process.c~sched-remove-set_tsk_need_resched-from-init_idle-v2 arch/x86_64/kernel/process.c --- 25/arch/x86_64/kernel/process.c~sched-remove-set_tsk_need_resched-from-init_idle-v2 2005-05-25 00:53:41.000000000 -0700 +++ 25-akpm/arch/x86_64/kernel/process.c 2005-05-25 00:53:41.000000000 -0700 @@ -162,6 +162,8 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait); */ void cpu_idle (void) { + set_tsk_need_resched(current); + /* endless idle loop with no priority at all */ while (1) { while (!need_resched()) { diff -puN kernel/sched.c~sched-remove-set_tsk_need_resched-from-init_idle-v2 kernel/sched.c --- 25/kernel/sched.c~sched-remove-set_tsk_need_resched-from-init_idle-v2 2005-05-25 00:53:41.000000000 -0700 +++ 25-akpm/kernel/sched.c 2005-05-25 00:53:41.000000000 -0700 @@ -4240,6 +4240,15 @@ void show_state(void) read_unlock(&tasklist_lock); } +/** + * init_idle - set up an idle thread for a given CPU + * @idle: task in question + * @cpu: cpu the idle task belongs to + * + * NOTE: this function does not set the idle thread's NEED_RESCHED + * flag, to make booting more robust. Architecture-level cpu_idle() + * functions should set it explicitly, before entering their idle-loop. + */ void __devinit init_idle(task_t *idle, int cpu) { runqueue_t *rq = cpu_rq(cpu); @@ -4257,7 +4266,6 @@ void __devinit init_idle(task_t *idle, i #if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW) idle->oncpu = 1; #endif - set_tsk_need_resched(idle); spin_unlock_irqrestore(&rq->lock, flags); /* Set the preempt count _outside_ the spinlocks! */ _