[PATCH] sched_yield() flawed since 2.2.13?

From: Giuseppe Ciaccio (ciaccio@disi.unige.it)
Date: Fri May 19 2000 - 11:24:52 EDT

  • Next message: Johannes Erdfelt: "Re: [linux-usb] Re: Problem with New PCI IRQ routing code for pre9-2"

    Hello,
    This message reports about a possible bug in the implementation of sched_yield()
    in kernel 2.2.13, which might not have been fixed in later kernels. A patch
    is proposed, which should solve the problem.

    I did the following experiment on a single-CPU machine with kernel 2.2.13:

    1) Open three shells

    2) Launch "top" on the first shell

    3) Launch the following (endless) "loop" program on the second shell:
    void main (void)
    {
            for (;;);
            return;
    }

    4) Launch the following (endless) "yield_loop" program on the third shell:
    #include <asm/unistd.h>
    int sched_yield (void)
    {
            long res;
            __asm__ __volatile__ ("int $0x80":"=a"(res):
                    "0"(__NR_sched_yield)
            );
            return (int)res;
    }

    void main (void)
    {
            for (;;) sched_yield();
            return;
    }

    5) Look at "top" in the first shell. You will see that both "loop" and
        "yield_loop" consume about 50% CPU time. According to the semantics of
        sched_yield(), however, one would expect 99% CPU time to be consumed by
        "loop", and only a negligible fraction of CPU time to be consumed by
        "yield_loop". Apparently, the implementation of sched_yield() is flawed.

    I could solve the problem by modifying file kernel/sched.c in 2.2.13.

    By comparing file kernel/sched.c in 2.2.13 and 2.3.99pre8 kernels, it
    appears that the same bug should also occur with the latter, at least with
    single-CPU machines. Could anyone confirm? If so, could anybody try applying
    the following patch to kernel/sched.c in 2.3.99pre8 and see if it fixes the
    bug? Thank you!

    Giuseppe

    Giuseppe Ciaccio http://www.disi.unige.it/person/CiaccioG/
    DISI - Universita' di Genova via Dodecaneso 35 16146 Genova, Italy
    phone +39 10 353 6638 fax +39 010 3536699 ciaccio@disi.unige.it
    ------------------------------------------------------------------------

    *** sched.c Fri May 19 12:41:36 2000
    --- sched.c.new Fri May 19 12:55:22 2000
    ***************
    *** 10,15 ****
    --- 10,17 ----
       * 1998-11-19 Implemented schedule_timeout() and related stuff
       * by Andrea Arcangeli
       * 1998-12-28 Implemented better SMP scheduling by Ingo Molnar
    + * 2000-05-19 Fixed wrong semantics of sched_yield() caused by bugs in
    + * prev_goodness() and goodness(), by Giuseppe Ciaccio
       */
      
      /*
    ***************
    *** 113,118 ****
    --- 115,126 ----
      {
              int weight;
      
    + /* Goodness of sched_yield()ed processes must be zero. */
    + if (p->policy & SCHED_YIELD) {
    + p->policy &= ~SCHED_YIELD;
    + return 0;
    + }
    +
              /*
               * Realtime process, select the first one on the
               * runqueue (taking priorities within processes
    ***************
    *** 150,170 ****
              return weight;
      }
      
    - /*
    - * subtle. We want to discard a yielded process only if it's being
    - * considered for a reschedule. Wakeup-time 'queries' of the scheduling
    - * state do not count. Another optimization we do: sched_yield()-ed
    - * processes are runnable (and thus will be considered for scheduling)
    - * right when they are calling schedule(). So the only place we need
    - * to care about SCHED_YIELD is when we calculate the previous process'
    - * goodness ...
    - */
      static inline int prev_goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm)
      {
    ! if (p->policy & SCHED_YIELD) {
    ! p->policy &= ~SCHED_YIELD;
                      return 0;
    - }
              return goodness(p, this_cpu, this_mm);
      }
      
    --- 158,167 ----
              return weight;
      }
      
      static inline int prev_goodness(struct task_struct * p, int this_cpu, struct mm_struct *this_mm)
      {
    ! if (p->policy & SCHED_YIELD)
                      return 0;
              return goodness(p, this_cpu, this_mm);
      }
      

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.rutgers.edu
    Please read the FAQ at http://www.tux.org/lkml/



    This archive was generated by hypermail 2b29 : Fri May 19 2000 - 11:29:16 EDT