Chinaunix首页 | 论坛 | 博客
  • 博客访问: 465074
  • 博文数量: 85
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 32
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-13 13:49
文章分类

全部博文(85)

文章存档

2018年(1)

2014年(40)

2013年(44)

分类: LINUX

2013-05-24 23:38:34

原文地址:Linux内核中的container_of() 作者:zonian

hat exactly does the weird Linux kernel container_of() macro do? This macro is defined as:

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

To help explain pointer mess, let us go through the steps of what it is doing. In the include/linux/i2c.h file, the to_i2c_driver() macro is defined as:

container_of(d, struct i2c_driver, driver)

and is used in code as:

i2c_drv = to_i2c_driver(drv);

where dev is a pointer to a struct device_driver.

Replacing the above code with the first macro expansion produces:

i2c_drv = container_of(drv, struct i2c_driver, driver);

Then, the next level of expansion creates:

i2c_drv = ({
const typeof( ((struct i2c_driver *)0)->driver) *__mptr = drv;
(struct i2c_driver *)( (char *)__mptr - offsetof(struct i2c_driver, driver));
})

To simplify this, remember that driver is a variable within the i2c_driver function. The first line of the macro sets up a pointer that points to thestruct device_driver passed to the code. The second line of the macro finds the real location in memory of the struct i2c_driver that we want to access.

So with the type of the driver variable known, the macro can be reduced to:

i2c_drv = ({
const struct device driver *__mptr = drv;
(struct i2c_driver *)( (char *)__mptr - offsetof(struct i2c_driver, driver));
})

To show this using real numbers, say the i2c_driver structure looks like:

struct i2c_driver {
char name[32];
struct device_driver driver;
};

The location of the driver variable usually is 32 bytes into the structure, depending on the packing rules of the compiler at the time. For more information on how to see where variables are located in structures, see my article  in the May/June 2002 issue of Embedded Linux Journal.

So, if the drv pointer is at location 0xc0101020, the __mptr variable is assigned that location in the first line of the macro. Then, the offset of the driver variable is subtracted from this address, giving us the value 0xc0101000. This would be assigned to the variable on the left side of the original assignment, i2c_drv.

Putting these values into the macro, it then is reduced to:

i2c_drv = ({
const struct device_driver *__mptr = drv;
(struct i2c_driver *)( (char *)__mptr - 0x20);
})

which is then evaluated at runtime by the processor as a simple subtraction on a pointer, which should be quite fast.

In order to do this kind of pointer manipulation, the code has to know the type of pointer being passed to it. The driver core only passes in the type of driver structure registered with it, so this type of manipulation is safe. This also prevents other parts of the kernel from modifying the unique fields of the structure used to control the subsystem's code.

指针ptr指向结构体type中的成员member;通过指针ptr,返回结构体type的起始地址
          type
      |----------|
      |          |
      |          |
      |----------|
ptr-->| member --|
      |----------|
      |          |
      |          |
      |----------|
/**
* 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(ptrtypemember) ({                    \        
        const typeof( ((type *)0)->member ) *__mptr = (ptr); -
\
        (type *)( (char *)__mptr - offsetof(type,member) );})




--------------------------------------------------
d = usb_device->dev.driver
container_of(d, struct usb_device_driver, drvwrap.driver)

     struct usb_device
|----------------------------|
|                            |
|                            |
|----------------------------|
|                            | struct device
|struct device_driver *driver|--+
|                            | -|
|----------------------------| 
-
|
|                            | 
-
|
|                            | 
-
|
|----------------------------| 
-
|
                                |
+-------------------------------+
|
|    struct usb_device_driver
--
|---------------------------|
|
--
 |                           |
|
--
 |                           |
--
|---------------------------|
+-->|struct device_driver driver| struct usbdrv_wrap drvwrap
    |int             for_devices|
    |---------------------------|
    |                           |
    |---------------------------|

 

 


--------------------------------------------
container_of宏,它的功能是得到包含某个结构成员的结构的指针:
 
其实现如下:
 
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) ({                      \
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
        (type *)( (char *)__mptr - offsetof(type,member) );})
 
    分析可知__mptr指向的是一个type结构里typeof(((type *)0)->member)类型member成员的指针,offsetof(type,member)是这个成员在结构中的偏移,单位是字节,所以为了计算type结构的起始地址,__mptr减去它自己的偏移。
阅读(1202) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~