This is ultimately a C question that arose when studying code in completion.h of the Linux kernel source, where I see a C technique I've never used in C before. Although have a vague sense what it's doing, I'd like to fine tune my understanding with a precise description, and I'm not quite sure how to search for the answer with Google without a potentially a long ordeal.
The relevant lines of code from the linux kernel's completion.h:
struct completion {
unsigned int done;
wait_queue_head_t wait;
};
#define COMPLETION_INITIALIZER_ONSTACK(work) \
(*({ init_completion(&work); &work; }))
#define DECLARE_COMPLETION_ONSTACK(work) \
struct completion work = COMPLETION_INITIALIZER_ONSTACK(work)
static inline void init_completion(struct completion *x)
{
x->done = 0;
init_waitqueue_head(&x->wait);
}
and in use:
int myFunc()
{
DECLARE_COMPLETION_ON_STACK(comp);
.
.
.
wait_for_completion(&comp);
}
Specifically, I want to understand the code
of COMPLETION_INITIALIZER_ON_STACK
.
I believe the braced body of two statements { init_completion(&work); &work; }
results in simply a value, &work
(a NOP statement), which from what I know about braced blocks in C, yeilds the value of the last assignment, in this case, the address of a struct.
But it is the enclosing of all of that in *( )
that gets interesting (and where I am bewildered).
init_completion()
being invoked (probably)? I'm not sure what is happening, how to conceive of it, and how it is it possible to assign that result to struct completion work
as is done in in DECLARE_COMPLETION_ON_STACK
.
Any education about this would be appreciated.
The syntax of statements within a ({ ... })
block is a statement expression which is a GCC extension. It allows you to run a series of statements where the last statement in the block is an expression which becomes the value of the full statement expression. So in this case the statement expression has the value &work
.
Since the statement expression evaluates to &work
, the *
right before the statement expression gives you *&work
, or equivalently work
as the value of the macro COMPLETION_INITIALIZER_ONSTACK
.
Now let's look at DECLARE_COMPLETION_ONSTACK
. When it is used:
DECLARE_COMPLETION_ON_STACK(comp);
It expands to:
struct completion comp= COMPLETION_INITIALIZER_ONSTACK(comp);
Which further expands to:
struct completion comp = (*({ init_completion(&comp ); ∁ }))
Breaking this down, the variable comp
is being initialized with a statement expression. The first statement in that expression is a call to the function init_completion
which is passed the address of the new variable. This function sets the values of the variable which at this point hasn't actually been initialized yet. The next (and last) statement in the statement expression is &comp
which is the value of the statement expression. This address is then dereferenced giving us comp
which is then assigned to comp
. So the variable is being validly initialized with itself!
Normally initializing a variable with itself would invoke undefined behavior because you would be trying to read an uninitialized variable, but not in this case because the variable's address is passed to a function which assigns values to its fields before it's initialized.
You might ask why COMPLETION_INITIALIZER_ONSTACK
was not defined like this:
#define COMPLETION_INITIALIZER_ONSTACK(work) \
({ init_completion(&work); work; })
If done this way, a temporary variable is created on the stack. Using the addrress prevents this from happening. In fact the code originally did this but was changed to what you see in the following commit: