Skip to contentSkip to conversation

kernel/timer.c: next_timer_interrupt() strange/buggy(?) code (2.6.18-rc1-mm2)

PATCH In review Andreas Mohr 7 participants 12 messages Jul 17, 2006 – Jul 18, 2006

lore
Share & tools
lore
#0 lore raw

Hi all,

next_timer_interrupt() contains the following gem:

        /* Check tv2-tv5. */
        varray[0] = &base->tv2;
        varray[1] = &base->tv3;
        varray[2] = &base->tv4;
        varray[3] = &base->tv5;
        for (i = 0; i < 4; i++) {
                j = INDEX(i);
                do {
                        if (list_empty(varray[i]->vec + j)) {
                                j = (j + 1) & TVN_MASK;
                                continue;
                        }
                        list_for_each_entry(nte, varray[i]->vec + j, entry)
                                if (time_before(nte->expires, expires))
                                        expires = nte->expires;
                        if (j < (INDEX(i)) && i < 3)
                                list = varray[i + 1]->vec + (INDEX(i + 1));
                        goto found;
                } while (j != (INDEX(i)));
        }
found:
        if (list) {

Excuse me, but why do we have a while loop here if the last instruction in the while loop is a straight "goto found"?
(a "continue" simply continue:s the loop without checking the loop condition at the bottom, right?)

Few lines above there's similar code:

        /* Look for timer events in tv1. */
        j = base->timer_jiffies & TVR_MASK;
        do {
                list_for_each_entry(nte, base->tv1.vec + j, entry) {
                        expires = nte->expires;
                        if (j < (base->timer_jiffies & TVR_MASK))
                                list = base->tv2.vec + (INDEX(0));
                        goto found;
                }
                j = (j + 1) & TVR_MASK;
        } while (j != (base->timer_jiffies & TVR_MASK));

However in this case now we process *one* list only, so the "goto found" should be ok since we don't need to iterate through the multiple tv2-tv5 lists as in the other potentially buggy loop.

Also, is the base->tv1.vec vs. base->tv2.vec difference above ok?

Possibly I'm too dense while reading this code, though...

Andreas Mohr

#1 lore raw
Quoted 2 lines · Andreas Mohr

(a "continue" simply continue:s the loop without checking the loop condition at the bottom, right?)

I don't think so. Test it. This is no infinite loop:

int main(void)

{
        int i = 0;
        do {
                i++;
                continue;
        } while (i < 1000);
}
Signature · 1 line
Greetings Michael.
#2 lore raw
In reply to Andreas Mohr
Quoted 12 lines · Andreas Mohr

Hi all,

        for (i = 0; i < 4; i++) {
                j = INDEX(i);
                do {

                        if (j < (INDEX(i)) && i < 3)
                                list = varray[i + 1]->vec + (INDEX(i + 1));
                        goto found;
                } while (j != (INDEX(i)));
        }
Quoted 4 lines

found:

Excuse me, but why do we have a while loop here if the last instruction in the while loop is a straight "goto found"?

Consider if we take the 'goto found' when i==1. We leave not only the do/while but also the for loop. A 'continue' instead would leave the do/while and then drive the i==2 and subsequent 'for' iterations....

(Unless my C mastery has severely faded of late?)

#3 lore raw
Quoted 15 lines · On Mon, 2006-07-17 at 15:57 -0400, [email protected] wrote:
Quoted 13 lines · Andreas Mohr

Hi all,

        for (i = 0; i < 4; i++) {
                j = INDEX(i);
                do {

                        if (j < (INDEX(i)) && i < 3)
                                list = varray[i + 1]->vec + (INDEX(i + 1));
                        goto found;
                } while (j != (INDEX(i)));
        }

found:

Quoted 8 lines
Quoted 2 lines

Excuse me, but why do we have a while loop here if the last instruction in the while loop is a straight "goto found"?

Consider if we take the 'goto found' when i==1. We leave not only the do/while but also the for loop. A 'continue' instead would leave the do/while and then drive the i==2 and subsequent 'for' iterations....

(Unless my C mastery has severely faded of late?)

No you are right. We jump to found because we found what we are looking for and don't need to look further in any more loops.

-- Steve

#4 lore raw
In reply to [email protected]
Quoted 15 lines · On Monday 17 July 2006 21:57, [email protected] wrote:
Quoted 13 lines · Andreas Mohr

Hi all,

        for (i = 0; i < 4; i++) {
                j = INDEX(i);
                do {

                        if (j < (INDEX(i)) && i < 3)
                                list = varray[i + 1]->vec + (INDEX(i + 1));
                        goto found;
                } while (j != (INDEX(i)));
        }

found:

Quoted 6 lines
Quoted 2 lines

Excuse me, but why do we have a while loop here if the last instruction in the while loop is a straight "goto found"?

Consider if we take the 'goto found' when i==1. We leave not only the do/while but also the for loop. A 'continue' instead would leave the do/while and then drive the i==2 and subsequent 'for' iterations....

No, it would not. A 'continue' instead of the 'goto found' would compile to nothing.
Try the following example with and without the 'continue'.

#include <stdio.h>
int main(void)

{
        int i, j;
        for (i = 0; i < 2; i++) {
                j = 0;
                do {
                        printf("i==%d, j==%d\n", i, j);
                        j++;
                        /* goto found; */
                        continue;
                } while (j < 2);
        }
}

Continue is equal to:

LOOP {
	/* foo */
	goto continue; /* == continue */
	/* foo */

continue:
} LOOP

Signature · 1 line
Greetings Michael.
#5 lore raw
Quoted 5 lines · Michael Buesch

Continue is equal to:

LOOP {
	/* foo */
	goto continue; /* == continue */
	/* What the code actually had: */
        goto found; /* Note placement of the label *AFTER* end of loop */
Quoted 3 lines
	/* foo */

continue:
} LOOP

found: /* out of the loop entirely */

A 'continue' drops you *at* the end of the loop. The 'goto found:' in the original code drops you *after* the end of the loop. One will potentially go around for another pass, the other you're *done*.

#6 lore raw
Quoted 13 lines · On Tuesday 18 July 2006 16:50, [email protected] wrote:
Quoted 5 lines · Michael Buesch

Continue is equal to:

LOOP {
	/* foo */
	goto continue; /* == continue */
	/* What the code actually had: */
        goto found; /* Note placement of the label *AFTER* end of loop */
Quoted 3 lines
	/* foo */

continue:
} LOOP

Quoted 5 lines

found: /* out of the loop entirely */

A 'continue' drops you *at* the end of the loop. The 'goto found:' in the original code drops you *after* the end of the loop. One will potentially go around for another pass, the other you're *done*.

I did not say something else.
I just wanted to say the sentence

Quoted 2 lines

A 'continue' instead would leave the do/while and then drive the i==2 and subsequent 'for' iterations....

is wrong. It would _not_ leave the do/while directly. It will check condition first and _might_ leave it.

Signature · 1 line
Greetings Michael.
#7 lore raw
In reply to Andreas Mohr
Quoted 2 lines · Andreas Mohr

(a "continue" simply continue:s the loop without checking the loop condition at the bottom, right?)

No. A continue jumps to the end of the loop body.

Andreas.

Signature · 4 lines
Andreas Schwab, SuSE Labs, [email protected]
SuSE Linux Products GmbH, Maxfeldstraße 5, 90409 Nürnberg, Germany
PGP key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
#8 lore raw

PATCH 1/1 fix bad macro param in timer.c (was: kernel/timer.c: next_timer_interrupt() strange/buggy(?) code (2.6.18-rc1-mm2))

In reply to Andreas Mohr
Quoted 4 lines · Andreas Mohr

Hi all,

next_timer_interrupt() contains the following gem:

Quoted 16 lines
        /* Check tv2-tv5. */
        varray[0] = &base->tv2;
        varray[1] = &base->tv3;
        varray[2] = &base->tv4;
        varray[3] = &base->tv5;
        for (i = 0; i < 4; i++) {
                j = INDEX(i);
                do {
                        if (list_empty(varray[i]->vec + j)) {
                                j = (j + 1) & TVN_MASK;
                                continue;
                        }
                        list_for_each_entry(nte, varray[i]->vec + j, entry)
                                if (time_before(nte->expires, expires))
                                        expires = nte->expires;
                        if (j < (INDEX(i)) && i < 3)

Looking at what INDEX is defined to be:

#define INDEX(N) (base->timer_jiffies >> (TVR_BITS + N * TVN_BITS)) & TVN_MASK

Quoted 1 line
                                list = varray[i + 1]->vec + (INDEX(i + 1));

And this INDEX(i+1) is now a ... (TVR_BITS + i + 1 * TVN_BITS)) ... This doesn't quite look like it suppose to be that way. Probably having some funny results because of it.

Here's the patch to clean up the macro used to find the index of the timer vector.

This is definitely a bug fix and should go into 2.6.18

-- Steve

kernel/timer.c +1 -1
Index: linux-2.6.18-rc2/kernel/timer.c
===================================================================
@@ -408,7 +408,7 @@ static int cascade(tvec_base_t *base, tv
  * This function cascades all vectors and executes all expired timer
  * vectors.
  */
-#define INDEX(N) (base->timer_jiffies >> (TVR_BITS + N * TVN_BITS)) & TVN_MASK
+#define INDEX(N) (base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK
 
 static inline void __run_timers(tvec_base_t *base)
 {
#9 lore raw

Re: [PATCH] fix bad macro param in timer.c

Joe Perches suggested another set of parans. And I believe he's right.

kernel/timer.c +1 -1
Index: linux-2.6.18-rc2/kernel/timer.c
===================================================================
@@ -408,7 +408,7 @@ static int cascade(tvec_base_t *base, tv
  * This function cascades all vectors and executes all expired timer
  * vectors.
  */
-#define INDEX(N) (base->timer_jiffies >> (TVR_BITS + N * TVN_BITS)) & TVN_MASK
+#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)
 
 static inline void __run_timers(tvec_base_t *base)
 {
#10 lore raw
In reply to Andreas Mohr

Am Montag Juli 17 2006 20:53 schrieb Andreas Mohr:

Quoted 15 lines
        for (i = 0; i < 4; i++) {
                j = INDEX(i);
                do {
                        if (list_empty(varray[i]->vec + j)) {
                                j = (j + 1) & TVN_MASK;
                                continue;
                        }
                        list_for_each_entry(nte, varray[i]->vec + j, entry)
                                if (time_before(nte->expires, expires))
                                        expires = nte->expires;
                        if (j < (INDEX(i)) && i < 3)
                                list = varray[i + 1]->vec + (INDEX(i + 1));
                        goto found;
                } while (j != (INDEX(i)));
        }
Quoted 1 line

found:

is equivalent to

  for (i = 0; i < 4; i++) {
      j = INDEX(i);
      do {
          if (!list_empty(varray[i]->vec + j)) {
              list_for_each_entry(nte, varray[i]->vec + j, entry)
                  if (time_before(nte->expires, expires))
                      expires = nte->expires;
              if (j < (INDEX(i)) && i < 3)
                  list = varray[i + 1]->vec + (INDEX(i + 1));
              goto found;
          }
          j = (j + 1) & TVN_MASK;
      } while (j != (INDEX(i)));
  }
  found:

But probably the code in timer.c takes account of probabilities, thus it is a bit more obscure.

HTH,

Signature · 3 lines
(°=                 =°)
//\ Prakash Punnoor /\\
V_/                 \_V
#11 lore raw

offtopic boot parameter notsc [Was: Re: kernel/timer.c: next_timer_interrupt() strange/buggy(?) code (2.6.18-rc1-mm2)]

Hi,
I am suffer a problem with lost tickets , that I suspect that begins in timer.c, I have to boot with notsc , but this is only one workaround, that don't resolve all problems.
Where I can find some help about this topic ?
more info about my bug http://bugme.osdl.org/show_bug.cgi?id=6419

Thanks in advance,
--
Sérgio M. B.