一般我们想要实现一种数据结构的双链队列,一般都是这样操作:

  typedef struct Datastructure
{
    struct Datastructure *next;
    struct Datastructure *prev;
    //......
}datastructure;

然而在Linux内核中,使用了大量不同的数据结构的双链队列。
因此,内核作者们把指针prev和next从具体的宿主中抽象出来成为了一种数据结构list_head。

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

在其宿主结构中:

typedef struct page
{
    struct list_head list;
    //.......
    struct page *next_hash;
    //.......
    struct list_head lru;
};

数据结构之间的连接操作都通过list_head执行。
接着内核定义了如下的一个函数:
memlist_entry(cur, struct page, list);
这个函数将list_head的指针curr换算成了宿主结构的其实地址,也就是其宿主page结构的指针。
但事实上,同一文件中将memlist_entry定义为list_entry。
page = (struct page*)((char*)(curr) - (usigned long)(& (struct page*)0) -> list));
其中curr是page结构中成分list的地址,page本身的地址,通过curr减去一个位移量就能得出,而这个位移量,就是page刚好在地址0时其成分list的地址,既:
& (struct page*)0) -> list)

12-23 08:24