lkml.org 
[lkml]   [2004]   [Dec]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [PATCH] Remove RCU abuse in cpu_idle()
On Sun, Dec 19, 2004 at 07:10:31PM -0700, Zwane Mwaikambo wrote:
> On Mon, 20 Dec 2004, Nick Piggin wrote:
>
> > On Sun, 2004-12-19 at 18:44 -0700, Zwane Mwaikambo wrote:
> > > On Mon, 20 Dec 2004, Nick Piggin wrote:
> > >
> > > > This thread can possibly be stalled forever if there is a CPU hog
> > > > running, right?
> > >
> > > Yep.
> > >
> > > > In which case, you will want to use ssleep rather than a busy loop.
> > >
> > > Well ssleep essentially does the same thing as the schedule_timeout.
> > >
> >
> > Yes - so long as you set ->state when using schedule_timeout ;)
>
> Nish could you please submit something to switch it to ssleep?

I believe the only files/patches that needed to be changed were the process.c
changes. Here they are re-worked to use ssleep(1) instead of
schedule_timeout(HZ).

Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>


--- 2.6.10-rc3-v/arch/i386/kernel/process.c 2004-12-08 13:38:42.000000000 -0800
+++ 2.6.10-rc3/arch/i386/kernel/process.c 2004-12-20 10:15:54.000000000 -0800
@@ -72,6 +72,7 @@ unsigned long thread_saved_pc(struct tas
* Powermanagement idle function, if any..
*/
void (*pm_idle)(void);
+static cpumask_t cpu_idle_map;

void disable_hlt(void)
{
@@ -142,16 +143,16 @@ static void poll_idle (void)
*/
void cpu_idle (void)
{
+ int cpu = smp_processor_id();
+
/* endless idle loop with no priority at all */
while (1) {
while (!need_resched()) {
void (*idle)(void);
- /*
- * Mark this as an RCU critical section so that
- * synchronize_kernel() in the unload path waits
- * for our completion.
- */
- rcu_read_lock();
+
+ if (cpu_isset(cpu, cpu_idle_map))
+ cpu_clear(cpu, cpu_idle_map);
+ rmb();
idle = pm_idle;

if (!idle)
@@ -159,12 +160,24 @@ void cpu_idle (void)

irq_stat[smp_processor_id()].idle_timestamp = jiffies;
idle();
- rcu_read_unlock();
}
schedule();
}
}

+void cpu_idle_wait(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ cpu_set(cpu, cpu_idle_map);
+
+ wmb();
+ while (cpus_equal(cpu_idle_map, cpu_online_map))
+ ssleep(1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
/*
* This uses new MONITOR/MWAIT instructions on P4 processors with PNI,
* which can obviate IPI to trigger checking of need_resched.
--- 2.6.10-rc3-v/arch/ia64/kernel/process.c 2004-12-08 13:38:43.000000000 -0800
+++ 2.6.10-rc3/arch/ia64/kernel/process.c 2004-12-20 10:16:18.000000000 -0800
@@ -46,6 +46,7 @@
#include "sigframe.h"

void (*ia64_mark_idle)(int);
+static cpumask_t cpu_idle_map;

unsigned long boot_option_idle_override = 0;
EXPORT_SYMBOL(boot_option_idle_override);
@@ -225,10 +226,24 @@ static inline void play_dead(void)
}
#endif /* CONFIG_HOTPLUG_CPU */

+void cpu_idle_wait(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ cpu_set(cpu, cpu_idle_map);
+
+ wmb();
+ while (cpus_equal(cpu_idle_map, cpu_online_map))
+ ssleep(1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
void __attribute__((noreturn))
cpu_idle (void *unused)
{
void (*mark_idle)(int) = ia64_mark_idle;
+ int cpu = smp_processor_id();

/* endless idle loop with no priority at all */
while (1) {
@@ -241,17 +256,14 @@ cpu_idle (void *unused)

if (mark_idle)
(*mark_idle)(1);
- /*
- * Mark this as an RCU critical section so that
- * synchronize_kernel() in the unload path waits
- * for our completion.
- */
- rcu_read_lock();
+
+ if (cpu_isset(cpu, cpu_idle_map))
+ cpu_clear(cpu, cpu_idle_map);
+ rmb();
idle = pm_idle;
if (!idle)
idle = default_idle;
(*idle)();
- rcu_read_unlock();
}

if (mark_idle)
--- 2.6.10-rc3-v/arch/x86_64/kernel/process.c 2004-12-08 13:38:45.000000000 -0800
+++ 2.6.10-rc3/arch/x86_64/kernel/process.c 2004-12-20 10:16:59.000000000 -0800
@@ -61,6 +61,7 @@ EXPORT_SYMBOL(boot_option_idle_override)
* Powermanagement idle function, if any..
*/
void (*pm_idle)(void);
+static cpumask_t cpu_idle_map;

void disable_hlt(void)
{
@@ -123,6 +124,19 @@ static void poll_idle (void)
}
}

+void cpu_idle_wait(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ cpu_set(cpu, cpu_idle_map);
+
+ wmb();
+ while (cpus_equal(cpu_idle_map, cpu_online_map))
+ ssleep(1);
+}
+EXPORT_SYMBOL_GPL(cpu_idle_wait);
+
/*
* The idle thread. There's no useful work to be
* done, so just try to conserve power and have a
@@ -131,21 +145,20 @@ static void poll_idle (void)
*/
void cpu_idle (void)
{
+ int cpu = smp_processor_id();
+
/* endless idle loop with no priority at all */
while (1) {
while (!need_resched()) {
void (*idle)(void);
- /*
- * Mark this as an RCU critical section so that
- * synchronize_kernel() in the unload path waits
- * for our completion.
- */
- rcu_read_lock();
+
+ if (cpu_isset(cpu, cpu_idle_map))
+ cpu_clear(cpu, cpu_idle_map);
+ rmb();
idle = pm_idle;
if (!idle)
idle = default_idle;
idle();
- rcu_read_unlock();
}
schedule();
}
-
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/
\
 
 \ /
  Last update: 2005-03-22 14:08    [from the cache]
©2003-2014 Jasper Spaans. Advertise on this site