I'm trying to do a deep dive into the linux source code and I'm seeing the following pattern of embedding a struct list_head to form a doubly linked list, this is on skbuff.h
struct sk_buff {
union {
struct {
/* These two members must be first to match sk_buff_head. */
struct sk_buff *next;
struct sk_buff *prev;
};
...
struct list_head list; <- list_head as above mentioned
};
...
}
So, basically, whenever you want access some member of the list you need some pointer to list_head, move it however you want and when you are in the position you need use this convenient macro defined on include/linux/container_of.h to get an outer reference (a reference to sk_buff-><some member> for example)
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
static_assert(__same_type(*(ptr), ((type *)0)->member) || \
__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
But I'm having trouble at understanding what container_of macro do, especially what ((type *)0)->member) means (I never saw that kind of pointer to 0) and why ((type *)(__mptr - offsetof(type, member)) works (I believe my concern here is how to use it in the context of mantaining the linked list and not just accesing a member of a given struct).
Could someone please help explaining the above two points about container_of macro ?, I'm not a noob on C but I never saw those patterns before and I was unable to get some interesting results on Google.
Really thanks, cheers.