Understanding of container_of macro in Linux kernel

The Linux kernel contains a very useful macro named “container_of”. This article is about Understanding of container_of macro in Linux kernel. This article includes a simple program that illustrates how this macro is used, and explains why it is so useful.

Understanding of container_of macro in Linux kernel

Introduction

Now we will assume that we have three containers. Container-1 has gold, Container-2 has diamond and Container-3 has filled with Water (Probably water is the most precious than gold and diamond). One guy come and ask you that which container contains Water (Container of water). I need it desperately. You would say, Container-3 has water.

So in this example, that guy knows that one container contains water, but don’t know which container it is. He was using the member name (water) to know the container name or container address. So this is the use of Container_of macro in Linux kernel.

I know the address of one member in the structure. But i don’t know the address of that structure. That structure may have many members. So we can find the address of the structure using this container_of macro in Linux Kernel.

Hope you understood this concept. If you don’t, you can understand that by using example.

Container_of()

container_of() is a macro defined in <linux/kernel.h>

The syntax of the Macro is given below.

container_of(ptr, type, member)

Where,

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.

It returns the address of the container structure of the member.

We will see the example. This Example is not the Linux kernel example. This is just C example. I’ll show you the Linux kernel example later of this post.

Example

Container_of macro will not be there in normal C program library. This is the Linux Kernel library. So manually I’ve added the macro to my program. Container_of macro is used to find the container structure address of given member. In this example, I’ve declared one structure which contains two members (mem1, mem2). I’m going to get the structure address by using the member mem2.

Since we know the address of the structure sample1 already. But, for your understanding about the container_of I made very easy program. Okay, What will be the output? Both address should be same or different?  Let’s see the output.

Output

Yessss!!!!!. Both address should be same. I hope you understood the concept of container_of macro. Do you know how that container of macro works? Start to read more.

Working of the Container_of macro

The full expansion of this macro is shown below.

Did you understand anything by seeing this macro? Ok we will go step by step. Now we will take the first line.

const typeof( ((type *)0)->member ) *__mptr = (ptr);

Here everyone knows the use of const. So I’ll explain typeof in this line.

typeof()

Since typeof is a compiler extension, there is not really a definition for it, but in the tradition of C it would be an operator like sizeof. It takes one argument and returns the static type of the operand. Just see below example.

Example

Output

Here is the output.

If you see the output carefully, the type of the name is assigned to the role.

Zero Point Reference

But what about the zero pointer dereference? Well, it’s a little pointer magic to get the type of the member. It won’t crash, because the expression itself will never be evaluated. All the compiler cares for is its type. The same situation occurs in case we ask back for the address. The compiler again doesn’t care for the value, it will simply add the offset of the member to the address of the structure, in this particular case 0, and return the new address.

Example

Output

In this example it returns the offset of the mem2. mem1 will occupy offset 0 to 3. So mem2 will take 4.

So, Also note that the following two definitions are equivalent:

typeof(((struct sample *)0)->mem2) test_var;

char test_var;

Now let’s take our original example that we have seen earlier of this post.

const typeof( ((type *)0)->member ) *__mptr = (ptr) this line creates the local constant pointer variable.

const typeof( ((type *)0)->member ) *__mptr = (ptr)—–> const char * __mptr = &sample1.mem2

Now we can take second line which is (type *)( (char *)__mptr - offsetof(type,member) ).

offsetof()

offsetof is a macro which will return a byte offset of a member to the beginning of the structure. The macro shown below.

It is even part of the standard library (available in stddef.h ).

We have already seen the example for this &((TYPE *)0)->MEMBER).

It returns an address of a member called MEMBER of a structure of type TYPE that is stored in memory from address 0 (which happens to be the offset we’re looking for).

Now we need to convert these both macro (offsetof(), container_of()) based on our original example. Theses macros will replace our example  like below.

Linux Kernel Driver Example Scenario

This is the macro of Linux Kernel. Below snippet is the example scenario of container_of used in Linux Kernel driver.

 

3
Leave a Reply

avatar
2 Comment threads
1 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
3 Comment authors
EmbeTronicx IndiaDivin RajNguyên Nguyễn Đình Recent comment authors

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  Subscribe  
newest oldest most voted
Notify of
Nguyên Nguyễn Đình
Guest
Nguyên Nguyễn Đình

Thank you very much! You save my life 😀

Divin Raj
Guest
Divin Raj

Thank you for the explanation
I have
some doubts Why
do we use container_of macro ?
container_of(pointer, container_type, container_field);
It is
said in the explanation that “This macro takes a pointer to a field named container_field, within a structure of type container_type, and returns a pointer to the containing structure”.
My questions
are: 1. If we want a pointer to the structure (ie container_type) we can directly assign, right?. 2. Then why the pointer of one of its field in taken to assign an address to the whole structure? 3. Please tell me the advantage of using that macro?
thank you

EmbeTronicx India
Guest
EmbeTronicx India

Hi Divin Raj, Here we used very simple example. That’s why you have doubt like that. Below I’ll explain one of the real example. struct foo { spinlock_t lock; struct workqueue_struct *wq; struct work_struct offload; (...) }; static void foo_work(struct work_struct *work) { struct foo *foo = container_of(work, struct foo, offload); <code>(...) </code> 12 <code>(...)</code> } static irqreturn_t foo_handler(int irq, void *arg) { struct foo *foo = arg; <code>queue_work(foo->wq, &foo->offload); (...) </code> 123 <code>queue_work(foo->wq, &foo->offload);(...)</code> } static int foo_probe(...) { struct foo *foo; <code>foo->wq = create_singlethread_workqueue("foo-wq"); INIT_WORK(&foo->offload, foo_work); (...) </code> 1234 <code>foo->wq = create_singlethread_workqueue("foo-wq");INIT_WORK(&foo->offload, foo_work);(...)</code> } Code Ref : https://www.kernel.org/… Read more »

%d bloggers like this: