Container_of Usage Analysis

Source: Internet
Author: User
Tags semaphore

 

When learning the Linux driver, a macro is called container_of.
This macro is defined in include/Linux/kernel. H. First, paste its code:

/**
* 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.
**/

# Define container_of (PTR, type, member )({/
Const typeof (type *) 0)-> member) * _ mptr = (PTR );/
(Type *) (char *) _ mptr-offsetof (type, member ));})

Its role is obvious, that is, the pointer to the entire struct variable is obtained based on the pointer of a domain member variable in a struct variable. For example, a struct variable is defined as follows:

Struct demo_struct {
Type1 member1;
Type2 member2;
Type3 member3;
Type4 member4;
};
Struct demo_struct demo;
At the same time, in another place, the pointer to a domain member variable in the variable demo is obtained, for example:
Type3 * memp = get_member_pointer_from_somewhere ();
At this point, if you need to obtain a pointer to the entire struct variable, not just a pointer to its member variable in a certain domain, we can do this:
Struct demo_struct * demop = container_of (memp, struct demo_struct, member3 );
In this way, we obtain the pointer of the entire struct variable through a pointer to a struct variable's domain member variable.
The following describes my understanding of the container_of implementation:
First, we will expand container_of (memp, struct demo_struct, type3) according to the macro definition as follows:
Struct demo_struct * demop = ({/
Const typeof (struct demo_struct *) 0)-> member3) * _ mptr = (memp );/

(Struct demo_struct *) (char *) _ mptr-offsetof (struct demo_struct, member3 ));})
Typeof is an extension of gnu c to Standard C. It is used to obtain the type of a Variable Based on the variable. Therefore, the function of row 2nd in the above Code is to first use typeof to obtain the type of the struct domain variable member3 as type3, and then define a Temporary Variable _ mptr of the type3 pointer type, and assign the value of the memp pointer to the domain variable in the actual struct variable to the Temporary Variable _ mptr.

(Char *) _ mptr to byte pointer. (Char *) _ mptr-offsetof (type, member) is used to find the starting address of the struct (char * pointer), and then (type *) (char *) _ mptr-offsetof (type, member) converts the starting pointer of a byte struct to the starting pointer of A type * struct under the action of (type.

Suppose the position of the struct variable demo in the actual memory is shown in:
Demo
+ ------------- + 0xa000
| Member1 |
+ ------------- + 0xa004
| Member2 |
+ ------------- + 0xa010
| Member3 |
+ ------------- + 0xa018
| Member4 |
+ ------------- +

The value of _ mptr after the first line of the Code is 0xa010.
Next, let's look at the 3rd lines of the above Code. here we need to describe offsetof, which is defined in include/Linux/stddef. H. Its definition is as follows:
# Define offsetof (type, member) (size_t) & (type *) 0)-> Member)
First, analyze the operating mechanism of this macro:
4 steps
1. (type *) 0) convert zero to type pointer;
2. (type *) 0)-> data member in the member access structure;
3. & (type *) 0)-> member) retrieves the address of the data member;
4. (size_t) (& (type *) 0)-> member) result conversion type. The trick is to convert 0 to (type *). The structure uses the first address 0 in the memory space as the starting address, and the member address is naturally an offset address;
Similarly, we expand the above offsetof call, that is:
(Struct demo_struct *) (char *) _ mptr-(size_t) & (struct demo_struct *) 0)-> member3 ));
It can be seen that the implementation principle of offsetof is described above, which is to take the offset address of the Domain Member in the struct to the address 0, that is, the offset of the domain member variable to the first address of the struct variable.
Therefore, the value returned by offsetof (struct demo_struct, member3) is the offset of member3 from the demo variable. According to the preceding variable address distribution chart, offsetof (struct demo_struct, member3) returns 0x10.
Therefore, the above analysis shows that, __mptr = 0xa010, offsetof (struct demo_struct, member3) = 0x10.
Therefore, (char *) _ mptr-(size_t) & (struct demo_struct *) 0)-> member3) = 0xa010-0x10 = 0xa000, that is, the first address of the Structure Variable demo (as shown in ).
This is the first pointer from a member variable pointer of the struct. The pointer type is converted from a member variable type of the struct to the struct type.
Therefore, container_of provides a function to obtain the pointer to the entire struct Variable Based on the pointer of a domain member variable in a struct variable.

The above content is carried from the network. This article is very thorough analysis. By the way, Song Baohua's Linux device driver development details p132's last line will incorrectly explain the macro parameters! Of course, you can't hide it!
Some of my own understandings are as follows:
First, I defined a character device struct.
Struct globalmem_dev
{
Struct cdev my_cdev; // basic structure of character Devices
Unsigned char mem [globalmem_size];
Struct semaphore SEM ;/
};
Next, I instantiate a pointer object for this device.
Struct globalmem_dev * pdev;

Later I used this in the open function.
Int globalmem_open (struct inode * inode, struct file * filp) for the generation and elimination of filp, see Driver Details P92
{
Struct globalmem_dev * pdev;
Printk ("/nfunction globalmem_open invoked/N ");
Pdev = container_of (inode-> I _cdev, struct globalmem_dev, my_cdev );
Filp-> private_da

Ta = pdev;
If (down_trylock (& pdev-> SEM) // obtain the semaphore. I really love container_of !!!! I love container_of !!!
Return-ebusy;
Return 0;
}
Description of the above usage:
Parameter 3 is the name of a member of parameter 2! Not the type name! Parameter 1 is a pointer pointing to the member of parameter 3.
The I _cdev field in inode is a pointer. When we successfully create a device driver in insmod, we will create a device file node through mknod and associate it with a specific device (driver, the device file node corresponds to an instance of the struct inode struct, which has an I _cdev field, which is a pointer of the struct cdev type and points to the my_cdev field of the device struct. Now you have a pointer pointing to the my_cdev field of a globalmem_dev (the pdev memory allocation is assumed to have been completed before calling open) therefore, container_of can help you calculate the pointer to the device struct.
When a device driver corresponds to multiple devices (sub-devices), you will know the role of container_of! When you call open for each device, because the file nodes of each device are different, the device struct pointers calculated based on the I _cdev field of the node are different, you can find the device struct corresponding to a specific node! Instead of writing different device drivers for different sub-devices.

Source: http://blog.csdn.net/zyhorse2010/article/details/6455091

When learning the Linux driver, a macro is called container_of.
This macro is defined in include/Linux/kernel. H. First, paste its code:

/**
* 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.
**/

# Define container_of (PTR, type, member )({/
Const typeof (type *) 0)-> member) * _ mptr = (PTR );/
(Type *) (char *) _ mptr-offsetof (type, member ));})

Its role is obvious, that is, the pointer to the entire struct variable is obtained based on the pointer of a domain member variable in a struct variable. For example, a struct variable is defined as follows:

Struct demo_struct {
Type1 member1;
Type2 member2;
Type3 member3;
Type4 member4;
};
Struct demo_struct demo;
At the same time, in another place, the pointer to a domain member variable in the variable demo is obtained, for example:
Type3 * memp = get_member_pointer_from_somewhere ();
At this point, if you need to obtain a pointer to the entire struct variable, not just a pointer to its member variable in a certain domain, we can do this:
Struct demo_struct * demop = container_of (memp, struct demo_struct, member3 );
In this way, we obtain the pointer of the entire struct variable through a pointer to a struct variable's domain member variable.
The following describes my understanding of the container_of implementation:
First, we will expand container_of (memp, struct demo_struct, type3) according to the macro definition as follows:
Struct demo_struct * demop = ({/
Const typeof (struct demo_struct *) 0)-> member3) * _ mptr = (memp );/

(Struct demo_struct *) (char *) _ mptr-offsetof (struct demo_struct, member3 ));})
Typeof is an extension of gnu c to Standard C. It is used to obtain the type of a Variable Based on the variable. Therefore, the function of row 2nd in the above Code is to first use typeof to obtain the type of the struct domain variable member3 as type3, and then define a Temporary Variable _ mptr of the type3 pointer type, and assign the value of the memp pointer to the domain variable in the actual struct variable to the Temporary Variable _ mptr.

(Char *) _ mptr to byte pointer. (Char *) _ mptr-offsetof (type, member) is used to find the starting address of the struct (char * pointer), and then (type *) (char *) _ mptr-offsetof (type, member) converts the starting pointer of a byte struct to the starting pointer of A type * struct under the action of (type.

Suppose the position of the struct variable demo in the actual memory is shown in:
Demo
+ ------------- + 0xa000
| Member1 |
+ ------------- + 0xa004
| Member2 |
+ ------------- + 0xa010
| Member3 |
+ ------------- + 0xa018
| Member4 |
+ ------------- +

The value of _ mptr after the first line of the Code is 0xa010.
Next, let's look at the 3rd lines of the above Code. here we need to describe offsetof, which is defined in include/Linux/stddef. H. Its definition is as follows:
# Define offsetof (type, member) (size_t) & (type *) 0)-> Member)
First, analyze the operating mechanism of this macro:
4 steps
1. (type *) 0) convert zero to type pointer;
2. (type *) 0)-> data member in the member access structure;
3. & (type *) 0)-> member) retrieves the address of the data member;
4. (size_t) (& (type *) 0)-> member) result conversion type. The trick is to convert 0 to (type *). The structure uses the first address 0 in the memory space as the starting address, and the member address is naturally an offset address;
Similarly, we expand the above offsetof call, that is:
(Struct demo_struct *) (char *) _ mptr-(size_t) & (struct demo_struct *) 0)-> member3 ));
It can be seen that the implementation principle of offsetof is described above, which is to take the offset address of the Domain Member in the struct to the address 0, that is, the offset of the domain member variable to the first address of the struct variable.
Therefore, the value returned by offsetof (struct demo_struct, member3) is the offset of member3 from the demo variable. According to the preceding variable address distribution chart, offsetof (struct demo_struct, member3) returns 0x10.
Therefore, the above analysis shows that, __mptr = 0xa010, offsetof (struct demo_struct, member3) = 0x10.
Therefore, (char *) _ mptr-(size_t) & (struct demo_struct *) 0)-> member3) = 0xa010-0x10 = 0xa000, that is, the first address of the Structure Variable demo (as shown in ).
This is the first pointer from a member variable pointer of the struct. The pointer type is converted from a member variable type of the struct to the struct type.
Therefore, container_of provides a function to obtain the pointer to the entire struct Variable Based on the pointer of a domain member variable in a struct variable.

The above content is carried from the network. This article is very thorough analysis. By the way, Song Baohua's Linux device driver development details p132's last line will incorrectly explain the macro parameters! Of course, you can't hide it!
Some of my own understandings are as follows:
First, I defined a character device struct.
Struct globalmem_dev
{
Struct cdev my_cdev; // basic structure of character Devices
Unsigned char mem [globalmem_size];
Struct semaphore SEM ;/
};
Next, I instantiate a pointer object for this device.
Struct globalmem_dev * pdev;

Later I used this in the open function.
Int globalmem_open (struct inode * inode, struct file * filp) for the generation and elimination of filp, see Driver Details P92
{
Struct globalmem_dev * pdev;
Printk ("/nfunction globalmem_open invoked/N ");
Pdev = container_of (inode-> I _cdev, struct globalmem_dev, my_cdev );
Filp-> private_da

Ta = pdev;
If (down_trylock (& pdev-> SEM) // obtain the semaphore. I really love container_of !!!! I love container_of !!!
Return-ebusy;
Return 0;
}
Description of the above usage:
Parameter 3 is the name of a member of parameter 2! Not the type name! Parameter 1 is a pointer pointing to the member of parameter 3.
The I _cdev field in inode is a pointer. When we successfully create a device driver in insmod, we will create a device file node through mknod and associate it with a specific device (driver, the device file node corresponds to an instance of the struct inode struct, which has an I _cdev field, which is a pointer of the struct cdev type and points to the my_cdev field of the device struct. Now you have a pointer pointing to the my_cdev field of a globalmem_dev (the pdev memory allocation is assumed to have been completed before calling open) therefore, container_of can help you calculate the pointer to the device struct.
When a device driver corresponds to multiple devices (sub-devices), you will know the role of container_of! When you call open for each device, because the file nodes of each device are different, the device struct pointers calculated based on the I _cdev field of the node are different, you can find the device struct corresponding to a specific node! Instead of writing different device drivers for different sub-devices.

Source: http://blog.csdn.net/zyhorse2010/article/details/6455091

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.