Linux中的数据结构抽象list_head

在Linux系统中大量使用了双向链表这一数据结构。一般的想法是在使用双向链表数据结构的时候:

typedef struct page
{
	struct page *prev;
	struct page *next;
	.........
}page
typedef struct node
{
	struct node *prev;
	struct node *next;
	.........
}page

这样每次使用一个结构体的时候,都需要定义一个双向链表,确实非极大的浪费资源,在毛德操的《情景分析》一书是这样描述的:

Linux内核中采用了一套通用的,一般的,可以用到各种不同数据结构的队列操作,为此,代码的作者把指针prev和next从具体的“宿主”数据结构中抽象出来称为一种数据结构list_head
成为数据结构的一个“连接件”,也可以独立存在成为一个队列的头。
struct list_head
{
struct list_head *next,*prev;
}

这样在具体的使用时就不一样的,如下,页面管理的Page数据结构为例,其定义为:(include/linux/mm.h)

typedef struct page
{
	struct list_head *next,*prev;
	........
	struct page *next_hash;
	........
	struct list_head lru;
	........
}page

在每个结构体内部都寄宿了list_head这个结构体,这样对该结构体的初始化可以使用宏定义INIT_LIST_HAED 来实现,定义如下:

#define INIT_LIST_HAED(ptr) do{(ptr)->next = (ptr);(ptr)->prev = (ptr);}while(0)

关于这个宏定义do{(ptr)->next = (ptr);(ptr)->prev = (ptr);}while(0)其实挺有意思的,do-while
语句是先执行一次在判断因此上面这个语句就是执行完{}里面后退出,调用一次这个宏定义,就会执行一次里面的代码。
接着说这个代码的含义:

 #define LIST_HEAD_INIT(name) { &(name), &(name) } //就是用head的地址初始化其两个成员next和prev ,使其都指向自己。 
 #define LIST_HEAD(name)    struct list_head name = LIST_HEAD_INIT(name) 
 #define INIT_LIST_HEAD(ptr) do { \ 
       (ptr)->next = (ptr); (ptr)->prev = (ptr); \ 
 } while (0)

要把page结构体通过其“队列头”list链入一个队列,使用list_add(),这是一个Inline函数,

static __inline__ void list_add(struct list_head *new, struct list_head *head) 
{ 
       __list_add(new, head, head->next); 
} 
//这个函数在head节点后面插入new节点。 
`
这个inline函数内部又调用了一个inline函数__list_add()来完成操作:
/** 
 * __list_add - Insert a new entry between two known consecutive entries. 
 * @new: 
 * @prev: 
 * @next: 
 * 
 * This is only for internal list manipulation where we know the prev/next 
 * entries 
 */ 
static __inline__ void __list_add(struct list_head * new, 
             struct list_head * prev, struct list_head * next) 
{ 
       next->prev = new; 
       new->next = next; 
       new->prev = prev; 
       prev->next = new; 
} 

对于知道队列我们可以进行add或者del操作,但是如果我们进去的一个队列其中的一项的时候,又该如何找到宿主结构呢?
看下面这个代码

page = memlist_entry(curr,struct page ,list);

这段代码,curr是list_head类型的结构体,函数把curr换算成宿主结构的起始地址,也就是其指向宿主的结构的指针。

#define list_entry(ptr,typr,member) (type*)((char*)(ptr)-(unsigned long)(&((type*0)->member)))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值