linux中list的使用

 (注:最近在研究系统源码,发现有些时候,要自己写才能知道自己是否真的已完全理解。也可借此加深记忆,锻炼自己的表达,所以会经常在博客中乱写,如果有错,千万表拍砖……)

        linux内核实现中,涉及到很多的队列,比如运行队列runqueue,其中保存了所有的处于就绪状态等待运行的进程的task_struct结构体对象,它们是怎么链接起来的?当然是通过list了。如果看过task_struct的实现,就会知道其中有一个list_head对象run_list,list_head就是linux中list的实现,其实现为双向链表。

struct list_head{
struct list_head *next,*prev;
}

        学习过数据结构吧!!! 这个双向链表的实现我们很熟悉,可如果你对当年写的链表记忆犹存的话,应该会发现这个双向链表的实现中是没有具体的数据的。当年我写的双线链表中一般是这样:

struct list{
valuetype data;
struct list *prev;
struct list *next;
}

       在data中保存实际的数据,然后是各种队列操作的实现,插入、删除等等。在linux之所以将链表实现跟具体的数据分开,是因为在linux内核中用到许多队列,这也就意味着list_head要被许多地方用到,自然就要抽象出list_head的实现。

       所以linux中list_head的使用形式是这样的:

struct **queue{
     ....
     list_head *list;
}

       在需要的地方如这里的**queue中加入list_head,然后如果需要构建一个**queue的队列,假如说是taskqueue则只需要声明一个双向链表头taskqueue,

list_head taskqueue;

        通过list_head就可以将它们链接起来形成队列。是不是很高明??? 问题还是有的……想想linux中的进程调度,它是怎么做的?是的,它要遍历运行队列runqueue(貌似是这个名字……,知道是运行队列就好了),取得进程的task_struct,计算其权值,以此来决定调度那个进程运行。

       这就奇怪了?通过list_head链接起来的运行队列,其中只有list_head(task_struct是通过它里面的list_head结构对象run_list链接到运行队列的),那么如何根据结构中list_head成员对象,找到其宿主对象,如task_struct呢???看到list_entry操作函数的实现你就会明白了。

#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) );})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

       具体list_entry的使用是,通过传入队列指针对象,宿主结构体类型,宿主结构体中list_head的成员名来取得具体对象指针。比如取得要获取队列p中的task_struct,则可以list_entry(p,struct task_struct,run_list)。

list_entry的实现原理是。offsetof宏将0强制转换为type类型对象指针,以->MEMBER取得其成员对象,再以&取得成员对象地址,因为起始是0,所以这里得到的也就是MEMBER的偏移地址。container_of宏中((type *)0)->member 道理是一样的,不过它通过typeof取得成员的类型,并定义成员类型的指针__mptr并赋值为传入的对象指针ptr,指针也即存的对象的地址,所以将成员指针__mptr减去成员的偏移量(也即offsetof宏得到的)得到的就是其宿主结构的地址。





 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值