|
一直听人说Linux内核中的链表是一个C实现的链表的典型,一直没有去了解。 最近看了一点点内核代码,看到链表的使用,觉得看不大懂。于是上网搜索相关文章,得出一个结论:Linux 内核的链表真是精辟!
传统的链表都是数据和指针装在一个节点里: struct node { type data; struct node *prev,*next; }; 而内核链表把指针独立出来,做成节点,在被含有数据的entry包含: struct list_head { struct list_head *prev,*next; };
struct entry { struct list_head* list; type data; };
用节点做为遍历的iterator,来处理数据。这样做很好得解决了一个问题,那就是如何使一个链表的实现能独立于数据。不同是数据type就不同,按以往的方式,一种数据就得实现一套链表处理。C++中用模板来解决,而内核链表是C,用这种方法来解决。
数据在节点以外,那怎么访问节点对应的数据呢? 内核链表提供了这个宏: #define list_entry(ptr, type, member) container_of(ptr, type, member)
而container_of的定义是: #define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
offsetof是我们熟悉的: #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
利用list_head在entry中的位置与list_head的指针,反推出entry的位置。 使用list_entry的方法: 如定义了 struct entry
{
struct list_head* list;
int data;
}myentry; 调用 struct entry* return_value=list_entry(list,struct entry,list); 则 return_value==&myentry;
|