Loading [Contrib]/a11y/accessibility-menu.js

Linux内核源码—list_entry(2.6.26.1)

 


list_head

在 Linux 内核中是通过链表的形式来管理进程的,其定义非常简单(/include/linux/list.h):

1
2
3
struct list_head {
    struct list_head *next, *prev;
};

只有两个指针,不包含其他数据,那怎么通过 list_head 将进程连接起来呢?

Linux 的做法是将 list_head 放入结构体中,比如下面的sched_rt_entity(/include/linux/sched.h):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct sched_rt_entity {
    struct list_head run_list;
    unsigned int time_slice;
    unsigned long timeout;
    int nr_cpus_allowed;
 
    struct sched_rt_entity *back;
#ifdef CONFIG_RT_GROUP_SCHED
    struct sched_rt_entity  *parent;
    /* rq on which this entity is (to be) queued: */
    struct rt_rq        *rt_rq;
    /* rq "owned" by this entity/group: */
    struct rt_rq        *my_q;
#endif
};

如此一来,链表其实就是将结构体中的 list_head 域进行了链接

 

地址计算

接下来的问题是,Linux 只将 list_head 进行了链接,怎么访问结构体中的其他成员呢?

方法也很简单,用 list_head 的地址减去其相对首地址的偏移量,从而得到结构体的首地址

在内核中的实现为:

1
2
3
4
5
6
#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)
 
#define container_of(ptr, type, member) ({          \
    const typeof( ((type *)0)->member ) *__mptr = (ptr); \
    (type *)( (char *)__mptr - offsetof(type,member) );})

将其展开,其实就是:

1
2
#define list_entry(ptr, type, member) /
        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

list_entry 通过结构体中某个成员变量的地址计算出结构体的首地址,ptr 是某个成员变量的地址, type 是结构体类型, member是成员变量。

计算 member 偏移量的方法很巧妙,如果假设结构体的首地址是 0 ,那么成员变量 member 的地址不就是相对于首地址的偏移量嘛。&((type *)0)->member)) 将地址 0 转换为 type 类型的指针,通过该指针去访问 member 就可以取出其地址。前半部分 (char *)(ptr) 使得指针的加减为 1 字节,最后将地址转换为 type 类型的指针。

 

 

 

References

  1. 理解 linux 中的 container_of 和 offsetof 宏
  2. linux内核链表以及list_entry--linux内核数据结构(一)
  3. list_entry() 源代码解析


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   Kayden_Cheung  阅读(144)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
历史上的今天:
2019-03-06 剑指offer:顺时针打印矩阵
2017-03-06 UVa 10801 电梯换乘
//目录
点击右上角即可分享
微信分享提示