Chinaunix首页 | 论坛 | 博客
  • 博客访问: 968379
  • 博文数量: 113
  • 博客积分: 7235
  • 博客等级: 少将
  • 技术积分: 2101
  • 用 户 组: 普通用户
  • 注册时间: 2008-07-14 11:24
文章分类

全部博文(113)

文章存档

2013年(7)

2012年(5)

2011年(6)

2010年(8)

2009年(15)

2008年(72)

分类: LINUX

2008-07-20 11:18:53

在linux内核中经常用到container_of,实际上它是一个宏,被定义在:
linux/include/linux/kernel.h中,原型为:
/**
* 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 (, , ) ({ \
const ( (( *)0)-> ) * = (); \
( *)( (char *) - (,) );})



指针ptr指向结构体type中的成员member;通过指针ptr,返回结构体type的起始地址。

       type
     |----------|
     |          |
     |          |
     |----------|
ptr-->| member --|
     |----------|
     |          |
     |          |
     |----------|

其中offsetof宏定义在[include/linux/stddef.h]中定义为:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
这里,要说明的是,((size_t) &((TYPE *)0)->MEMBER)把0地址转化为TYPE结构的指针,
然后获取该结构中MEMBER成员的指针,并将其强制转换为size_t类型。于是,由于结构从0地址开始定义,因此,这样求出的MEMBER成员地址,实际上就是它在结构中的偏移量。分析可知__mptr指向的是一个type结构里typeof(((type *)0)->member)类型member成员的指针,offsetof(type,member)是这个成员在结构中的偏移,单位是字节,所以为了计算type结构的起始地址,__mptr减去它自己的偏移。
那么具体看一个它的应用。
在/linux/lib/kobject.c中kobject_release被定义如下
static void (struct *)
{
((, struct , ));
}

它的作用是kobject清除函数。当其引用计数为0时,释放对象占用的资源。

它的实现中就用到了container_of。它的参数是kref为struct kref类型,而
kobject_cleanup的定义为:

void (struct * ) //在/linux/lib/kobject.c
中,它的参数为struct kobject *类型,而struct kobject结构中就包含struct
kref 类型的成员:linux/include/linux/kobject.h
  59/* The list of strings defining the valid kobject actions as specified above */
  60extern const char *kobject_actions[];
  61
  62
  63struct kobject {
  64        const char              * k_name;
  65        char                    name[KOBJ_NAME_LEN];
  66        struct kref             kref;
  67        struct list_head        entry;
  68        struct kobject          * parent;
  69        struct kset             * kset;
  70        struct kobj_type        * ktype;
  71        struct dentry        * dentry;
  72};

从宏观的效果来看,container_of的确是取得了ptr所在结构,那么它是如何实现的?
在看看container_of的定义:
#define (, , ) ({                      \
const ( (( *)0)-> ) * = (); \
( *)( (char *) - (,) );})
此处ptr就是kobject_release的参数kref,type就是struct kobject,member就是

struct kobject结构中的成员kref,那么替换之后就为:
container_of(para_kref,struct kobject,kref) //次处由于ptr和member的名字
都为kref,但是不一样的,所以使用para_kref代替
kobject_release的参数kref
({
const typeof(((struct kobject*)0)->kref) *__mptr = (para_ptr);
(struct kobject *)((char *)__mptr - offsetof(struct kobject,kref));
})
((struct kobject *)0)->kref是取得kobject结构的kref成员,在使用typeof作用于它就取
得了kref成员的类型,即struct kref,到此整体的第一行可翻译为:
const struct kref *__mptr=(para_ptr);

offsetof(struct kobject,kref)是取得kref成员在struct kobject结构中的偏移
,我编写了一个内核模块测试的结果为24, 所以第二行可以翻译为:
(struct kobject *)((char *)__mptr-24);
这样就取得了para_ptr所在的指向struct kobject的地址,在使用(struct kobject *)将其强制转化成指向struct kobject结
构的指针,到此实现了上面所说的container_of的功能。

阅读(1207) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~