1

While browsing Linux kernel source, I found hlist_bl_for_each_entry_rcu macro.Below is its definition

for (pos = hlist_bl_first_rcu(head);                            \
                pos &&                                                  \
                ({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1; }); \
                pos = rcu_dereference_raw(pos->next))

This macro is used in __d_lookup() to get the dentry. What I do not understand is the line

({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1; });

It gets the tpos. What is the use of 1 here ? How to understand this condition in the for loop ?

bornfree
  • 2,308
  • 1
  • 23
  • 33
  • That line is uses a [GCC extension known as a statement expression](https://stackoverflow.com/questions/6440021). Think of that line as a function whose return value is always `1`. – user3386109 Apr 15 '18 at 06:48
  • @user3386109- it means the condition in for loop is "pos && 1" irrespective of value of tpos ? – bornfree Apr 15 '18 at 07:00
  • Yes. Due to [short-circuit evaluation](https://en.wikipedia.org/wiki/Short-circuit_evaluation), `tpos` will only be updated when `pos` is not NULL. And the body of the loop will *always* execute when `pos` is not NULL. The loop condition doesn't check whether `tpos` is NULL. Either it's guaranteed that `tpos` is always valid when `pos` is not NULL, or the body of the loop needs to handle the case where `tpos` is NULL. – user3386109 Apr 15 '18 at 18:25

1 Answers1

2

If you were writing it macroless, it would probably look like this:

for (pos = hlist_bl_first_rcu(head); pos; pos = rcu_dereference_raw(pos->next)) {
    tpos = hlist_bl_entry(pos, typeof(*tpos), member);

    /* do something with pos and tpos */

}

For the macro, you would want to move tpos = hlist_bl_entry(pos, typeof(*tpos), member); into the for (...), so the user only has to supply the for block. In the macroless version, you want tpos' value set every time pos is non-NULL, thus you add it in the loop condition after a pos &&:

pos && (tpos = hlist_bl_entry(pos, typeof(*tpos), member))

but now tops non-nullness becomes a loop condition, so you tell C to ignore the return value:

pos && ((tpos = hlist_bl_entry(pos, typeof(*tpos), member)), 1)

but kernel code is GNU C anyway, so you may use statement expressions instead:

pos && ({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1; })
a3f
  • 8,517
  • 1
  • 41
  • 46