
From: Ingo Molnar <mingo@elte.hu>

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 <mingo@elte.hu>
Acked-by: Nick Piggin <nickpiggin@yahoo.com.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 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! */
_
