1

I want to implement container_of macro/function from scratch like that is available in linux kernel to get the address of parent structure from the member of the parent structure.

e.g. if the parent structure is

struct parent{ int id; struct list_head list; };

and i have the address of the list_head element inside the structure.

So i want to get the address of struct parent so that i can access id of the parent.

I have only three known information 1. Type of parent structure 2. Type of struct list_head 3. identifire/name of the list_head variable.

#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})

Thaks i any body can explain.

Dpk
  • 311
  • 5
  • 16

1 Answers1

0

Firstly your question is not appropriate. From my understanding you want to understand the working of the macro, not implement it.

Moving on,

Linked lists used in the linux kernel are nicely explained in Linux Kernel Linked List Explained

In the linux kernel the list is contained in the list node. Example:

struct list_head {  /* Kernel list structure */
    struct list_head *next, *prev;
}

struct my_list {
    int to;
    struct list_head list; /* list is contained in the node */
    int from;
}

So we iterate the linked list using the list_head variable. The tricky part is that we use the list variable to get the node structure ( in which it is contained )

See Q. 2.14 and 2.15 in MIT FAQ. The question explains how we can retrieve pointer to the CONTAINING structure if we have the offset of a variable in the struct.

So in layman terms, we could say,

struct s address = <address of struct variable> - <offset of that variable in the struct>

Coming to the macro, consider this definition of the macro. (simplistic implementation, i found in drivers/gpu/drm/nouveau/include/nvif/list.h )

#define container_of(ptr, type, member) \
    (type *)((char *)(ptr) - (char *) &((type *)0)->member)

So think of the left operand as the structure VARIABLE ( this is the list_head variable usually). Now coming to the right operator. To get the OFFSET of that variable ( say list_head variable ) in the containing strict ( say struct my_list ), we create a zeroed struct ( i.e., a temp struct with the address 0x0 ) so the addresses of any variables in the struct corresponds to the offset of that variable.

Now the last part to understand is why cast to char *. Well this basic pointer arithmetic. char * addtion would increment the values by 1 at a time ( char* points to a char of 1 byte ).

((char*)0) + 1  -> 0x1

Had it been int * addition of 1 to the pointer would increment the offset by 4 , as int * points to a int of size 4( on my computer).

((int*)0) + 1  -> 0x4

Hope that helped .. :)

Ankit
  • 89
  • 7