[systemd-devel] [PATCH] shared: make container_of() use unique variable names
Lennart Poettering
lennart at poettering.net
Tue Aug 26 11:43:38 PDT 2014
On Fri, 22.08.14 14:54, David Herrmann (dh.herrmann at gmail.com) wrote:
Looks good to me. Go ahead, commit.
> If you stack container_of() macros, you will get warnings due to shadowing
> variables of the parent context. To avoid this, use unique names for
> variables.
>
> Two new helpers are added:
> UNIQ: This evaluates to a truly unique value never returned by any
> evaluation of this macro. It's a shortcut for __COUNTER__.
> UNIQ_T: Takes two arguments and concatenates them. It is a shortcut for
> CONCATENATE, but meant to defined typed local variables.
>
> As you usually want to use variables that you just defined, you need to
> reference the same unique value at least two times. However, UNIQ returns
> a new value on each evaluation, therefore, you have to pass the unique
> values into the macro like this:
>
> #define my_macro(a, b) __max_macro(UNIQ, UNIQ, (a), (b))
> #define __my_macro(uniqa, uniqb, a, b) ({
> typeof(a) UNIQ_T(A, uniqa) = (a);
> typeof(b) UNIQ_T(B, uniqb) = (b);
> MY_UNSAFE_MACRO(UNIQ_T(A, uniqa), UNIQ_T(B, uniqb));
> })
>
> This way, MY_UNSAFE_MACRO() can safely evaluate it's arguments multiple
> times as they are local variables. But you can also stack invocations to
> the macro my_macro() without clashing names.
>
> This is the same as if you did:
>
> #define my_macro(a, b) __max_macro(__COUNTER__, __COUNTER__, (a), (b))
> #define __my_macro(prefixa, prefixb, a, b) ({
> typeof(a) CONCATENATE(A, prefixa) = (a);
> typeof(b) CONCATENATE(B, prefixb) = (b);
> MY_UNSAFE_MACRO(CONCATENATE(A, prefixa), CONCATENATE(B, prefixb));
> })
>
> ...but in my opinion, the first macro is easier to write and read.
>
> This patch starts by converting container_of() to use this new helper.
> Other macros may follow (like MIN, MAX, CLAMP, ...).
> ---
> src/shared/macro.h | 13 ++++++++-----
> src/test/test-util.c | 19 +++++++++++++++++++
> 2 files changed, 27 insertions(+), 5 deletions(-)
>
> diff --git a/src/shared/macro.h b/src/shared/macro.h
> index 2807bc7..e673480 100644
> --- a/src/shared/macro.h
> +++ b/src/shared/macro.h
> @@ -79,6 +79,9 @@
> #define XCONCATENATE(x, y) x ## y
> #define CONCATENATE(x, y) XCONCATENATE(x, y)
>
> +#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq))
> +#define UNIQ __COUNTER__
> +
> /* Rounds up */
>
> #define ALIGN4(l) (((l) + 3) & ~3)
> @@ -122,13 +125,13 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
> * @ptr: the pointer to the member.
> * @type: the type of the container struct this is embedded in.
> * @member: the name of the member within the struct.
> - *
> */
> -#define container_of(ptr, type, member) \
> +#define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member)
> +#define __container_of(uniq, ptr, type, member) \
> __extension__ ({ \
> - const typeof( ((type *)0)->member ) *__mptr = (ptr); \
> - (type *)( (char *)__mptr - offsetof(type,member) ); \
> - })
> + const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \
> + (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type,member) ); \
> + })
>
> #undef MAX
> #define MAX(a,b) \
> diff --git a/src/test/test-util.c b/src/test/test-util.c
> index 34d5f2e..7b2e71c 100644
> --- a/src/test/test-util.c
> +++ b/src/test/test-util.c
> @@ -96,6 +96,24 @@ static void test_max(void) {
> assert_cc(MAXSIZE(char, long) == sizeof(long));
> }
>
> +static void test_container_of(void) {
> + struct mytype {
> + uint8_t pad1[3];
> + uint64_t v1;
> + uint8_t pad2[2];
> + uint32_t v2;
> + } _packed_ myval = { };
> +
> + assert_cc(sizeof(myval) == 17);
> + assert_se(container_of(&myval.v1, struct mytype, v1) == &myval);
> + assert_se(container_of(&myval.v2, struct mytype, v2) == &myval);
> + assert_se(container_of(&container_of(&myval.v2,
> + struct mytype,
> + v2)->v1,
> + struct mytype,
> + v1) == &myval);
> +}
> +
> static void test_first_word(void) {
> assert_se(first_word("Hello", ""));
> assert_se(first_word("Hello", "Hello"));
> @@ -1218,6 +1236,7 @@ int main(int argc, char *argv[]) {
> test_streq_ptr();
> test_align_power2();
> test_max();
> + test_container_of();
> test_first_word();
> test_close_many();
> test_parse_boolean();
Lennart
--
Lennart Poettering, Red Hat
More information about the systemd-devel
mailing list