前言
list在linux内核中使用非常频繁。
链表添加操作(函数)
定义双向链表结构体
struct list_head {
struct list_head *prev;
struct list_head *next;
};
初始化一个链表
static void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
在前一个和后一个之间插入一个新的链表项
static 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;
}
新链表项插入到head的后边
static void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
新链表项插入到head的前边,head移动到链表的尾部
static void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
删除前一个和后一个中间的链表项
static void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
删除传入的链表项
static void list_del(struct list_head * entry)
{
__list_del(entry->prev,entry->next);
}
删除传入的两个链表项之间的所有链表项(包含传入的链表项 )
static void list_remove_chain(struct list_head *ch, struct list_head *ct)
{
ch->prev->next=ct->next;
ct->next->prev=ch->prev;
}
将新链表插入到head的后边
static void list_add_chain(struct list_head *ch, struct list_head *ct, struct list_head *head)
{
ch->prev=head;
ct->next=head->next;
head->next->prev=ct;
head->next=ch;
}
将新链表插入到head的前边
static void list_add_chain_tail(struct list_head *ch, struct list_head *ct, struct list_head *head)
{
ch->prev=head->prev;
head->prev->next=ch;
head->prev=ct;
ct->next=head;
}
清空一个链表项
static int list_empty(const struct list_head *head)
{
return head->next == head;
}
链表遍历操作(宏定义)
在链表中获取包含member的type结构体的首地址
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* 在链表中获取包含member的type结构体的首地址,等同于container_of().
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
获取第一个entry
/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
* 对于双向链表来说,next就是相对于当前的第一个。
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
获取最后一个entry
/**
* list_last_entry - get the last element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
* 对于双向链表来说,next就是相对于当前的最后一个。
*/
#define list_last_entry(ptr, type, member) \
list_entry((ptr)->prev, type, member)
遍历整个链表
/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*
* @pos: 链表临时变量,或者中间变量
* @head: 需要变量的链表
* 简单的遍历整个链表
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*
* @pos: 希望获得的对象指针
* @head: 链表头
* @member: 一般是对象中的list成员
*
* 遍历获取链表上所有的指定成员:在container_of中是通过结构体中的成员来获取结构体的指针;
* 而这里是通过结构体中包含的链表来实现的,链表就是结构体中的成员。
* 这个的参数位置和list_for_entry不一样,各自的参数位置是比较合理的。
* 这个宏是直接使用一个for循环来实现的,后面要跟大括号。
* for循环的三个参数分成了三行:
* for循环第一行是第一次赋值
* for循环第二行是循环条件判断
* for循环第三行是下一次循环值
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
&pos->member != (head); \
pos = list_next_entry(pos, member))
container_of相关
用于计算member到type的地址偏移长度 ,这的(TYPE *)0就是将type的类型的起始地址转换为0,相应的member成员的地址也等于相对于0的偏移地址了, 这就是这个宏的原理。
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
通过成员ptr的指针来获取整个type的指针,指针在内存中是从低往上增长的,ptr的地址是大于type地址的, offsetof宏通过type和member来计算偏移长度, 最后通过ptr减去偏移长度就可以得到type的指针。
#define container_of(ptr, type, member) ({ \
/* typeof的作用是获取成员或者函数的类型,
* typeof的使用主要是为了在参数传递不一样的情况下,
* 编译时会发出警告
*/
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })