Chinaunix首页 | 论坛 | 博客
  • 博客访问: 521152
  • 博文数量: 257
  • 博客积分: 1666
  • 博客等级: 上尉
  • 技术积分: 1535
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-02 23:02
文章分类

全部博文(257)

文章存档

2013年(2)

2012年(255)

分类:

2012-07-02 10:14:49

原文地址:linux内核链表结构 作者:dinglong08

    最近在看一些内核方面的书籍,之前也有看过,但是由于功力尚浅所以没能看的太明白。今天看到内核的链表结构,觉得理解了其中的要点,故而卖弄一下,见笑了,:)
    内核中很多地方都使用到了链表,所以作为实现必定是一个通用的,而内核是用c实现的,没有c 的模板辅助,这样的通用性就实现起来有些难度。但是linux采用了比较有技巧的方式,即容器的概念。

// 首先是链表中的节点结构,注意是双向链表

点击(此处)折叠或打开

  1. struct list_head
  2. {
  3.     struct list_head *perv, *next;
  4. };

// 其次是链表要连接的真正对象

点击(此处)折叠或打开

  1. struct Object
  2. {
  3.     datatype data_1;
  4.     ...
  5.     list_head member;
  6.     ...
  7.     datatype data_n;
  8. };
    注意到,list_head的对象被嵌入到了object中。结构如下图所示:
-----------------                  -----------------
|  data_1     |                  |   data_1   |
-----------------                  |----------------
|  member  | <--------> | member  |
-----------------                  -----------------
|  data_n     |                  |  data_n    |
-----------------                  -----------------
对链表来说就是遍历的问题了,而遍历的过程就是顺着 member 走。
最主要的问题就是如何从一个 Obejetc实例中解析出 member(即list_head实例),内核提供了一些宏,其中最主要的几个如下:
// kernel.h

点击(此处)折叠或打开

  1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)

  2. #define container_of(ptr, type, member) ({
  3.     const typeof(((type*)0)->member)* __mptr = (ptr);
  4.     (type*) ((char*)__mptr - offsetof(type, member));})
对上面两个宏作一点解释:
1. 第一个宏返回TYPE类型中 MEMBER成员的位置偏移量,这个量是更具编译和cpu定的。
2. 第二个宏的作用是返回type实例中的member实例,其中参数memner是list_head的变量名。
3. 第二个宏的第一句,看似多余,实则有用。由于这是一个宏,所以在展开后ptr是一个表达式,有可能会和自己的表达式混淆,所以定义自己的变量__mptr接受这个表达式的值。其中typeof关键字是GNU C的扩展。
4. 第二个宏的第二句,计算出member的位置,并转型成为 type 类型返回,这也就说明了,其实member的prev和next指针所指的就是object对象。

实际的例子解释上面宏的展开:

点击(此处)折叠或打开

  1. struct test
  2. {
  3.     int a;
  4.     struct list_head member;
  5.     int b;
  6. };

  7. // 解析后
  8. const typeof(((struct test*)0)->member) __mptr = (ptr);
  9. (struct test*) ((char*)__mptr - offset); // 注,offsetof的具体计算省略
有了这个模型和提取list_head的宏,其余的链表操作就迎刃而解,当然其实现也有很多的精妙之处,有待好好的品味。


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