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    [W:0.033 / U:0.476 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site