Container_of source code analysis

  • Container_of macro definition
  • Analysis BUILD_BUG_ON_MSG
  • Analysis offsetof

The container_of function is a common one in Linux/Android code. Container_of (PTR, type, member),

  1. Type is a struct, which is typically assigned to container_ofstruct xxx;
  2. Member is the name of the member in the structure, and PTR is the pointer to the member, the first address in the storage space where the member is stored.
  3. When called, container_of returns the first address of the structure in the storage space.

I took the time to learn how container_of works. The code of this article is based on android10, RK3399 platform code.

Container_of macro definition

Defined in: rk3399 – android – 10 / kernel/include/Linux/kernel. H

/** * container_of - cast a member of a structure out to the containing structure * @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. * */
#definecontainer_of(ptr, type, member) ({ \ void *__mptr = (void *)(ptr); \ BUILD_BUG_ON_MSG(! __same_type(*(ptr), ((type *)0)->member) && \ ! __same_type(*(ptr), void), \"pointer type mismatch in container_of()");    \
        ((type *)(__mptr - offsetof(type, member))); })
Copy the code

Analysis BUILD_BUG_ON_MSG

Let’s look at the function’s first argument:! __same_type(*(ptr), ((type *)0)->member) && ! __same_type (* (PTR), void) __same_type defined in: rk3399 – android – 10 / kernel/include/Linux/compiler_types. H

/* Are two types/vars the same type (ignoring qualifiers)? * /
#define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
Copy the code

The __builtin_types_compatible_p function checks whether a and B are of the same type and returns 1 if they are the same, or 0 otherwise. So if same_type returns 1 in this && statement, it will be 0; This statement is 1 only if both same_type’s return 0.

Look at BUILD_BUG_ON_MSG macro definition, lies in: rk3399 – android – 10 / kernel/include/Linux/build_bug. H

/** * BUILD_BUG_ON_MSG - break compile if a condition is true & emit supplied * error message. * @condition: the condition which the compiler should know is false. * * See BUILD_BUG_ON for description. */
#defineBUILD_BUG_ON_MSG(cond, msg) compiletime_assert(! (cond), msg)
Copy the code

Which compiletime_assert macro definition, lies in: rk3399 – android – 10 / kernel/include/Linux/compiler. H

/** * compiletime_assert - break build and emit msg if condition is false * @condition: a compile-time constant condition to check * @msg: a message to emit if condition is false * * In tradition of POSIX assert, this macro will break the build if the * supplied condition is *false*, emitting the supplied error message if the * compiler has support to do so. */
#define compiletime_assert(condition, msg) \
        _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
Copy the code

MSG will be sent when condition on compiletime_assert is false.

So, for BUILD_BUG_ON_MSG, when! (cond) == false, that is, if cond == true, its MSG will be sent and the compilation will stop. Back to container_of’s macro definition. __same_type(*(ptr), ((type *)0)->member) && ! Error “Pointer type mismatch in container_of()” if __same_type(*(PTR), void) == true

Take a closer look at the && statement. The first half sentence:! __same_type (* (PTR), (0) (type *) – > member). (type *)0) means that, assuming we start at address 0, we cast it to a type structure, i.e. we read address 0-(sizeof(type) -1) to store the type structure. PTR = member; PTR = member; PTR = member; The last half sentence:! __same_type(*(PTR), void).

Analysis offsetof

((type *)(__mptr – offsetof(type, member))); __mptr is a void* pointer to the same address as PTR. Offsetof defined in: rk3399 – android – 10 / kernel/include/Linux/stddef. H

#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE, MEMBER)  __compiler_offsetof(TYPE, MEMBER)
#else
#define offsetof(TYPE, MEMBER)  ((size_t)&((TYPE *)0)->MEMBER)
#endif
Copy the code

If the __compiler_offsetof macro function is defined, the __compiler_offsetof function is called.

__compiler_offsetof defined in: rk3399 – android – 10 / kernel/include/Linux/compiler_types. H

#define __compiler_offsetof(a, b)       __builtin_offsetof(a, b)
Copy the code

Else branch offsetof:

Suppose you havestruct Test {
inta; .intmember; . }struct Test *A;
Copy the code

Call container_of(PTR, type, member). The PTR refers to the first memory address of the member in the structure. Container_of should return the first memory address of the structure pointed to by A.



Struct Test (A->member address -0); struct Test (A->member -0); The illustration is shown in Figure 2:



Convert (&((TYPE *)0)->MEMBER) to size_t as offsetof return.

((type *)(__mptr - offsetof(type, member)));The address of the head of the structure can be obtained by subtracting the difference between the address of the PTR in Figure 1 and the address of the head of the structure calculated by Figure 2.

Structure head address = PTR pointing address – address difference