Linux 内核 链表 的简单模拟(2)

  接上一篇Linux 内核 链表 的简单模拟(1)

  第五章:Linux内核链表的遍历


/**
* list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop cursor.
* @head: the head for your list.
*/
#define list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)

这是遍历链表的一个方法,其实就是一个for循环的宏啦!写得很清楚。但是这些操作的还是struct
list_head,跟我要的结构体没有半毛钱关系,怎么办?继续看:


/**
* 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_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)

这个就是由我们自定义的结构体中包含的struct
list_head获得结构体的方式,其实就是上一篇博客的container_of的第二个名字啦!container_of到了这山沟里就换了一个很土的名字啦!

好了,下面看代码就一清二楚了:


    struct list_head *p;    //pointer to each struct list_head
struct Book *pb; //pointer to struct Book

list_for_each(p,&MyBkList)
{
pb = list_entry(p, struct Book,list);
cout << pb->bkId << " " << pb->bkName << endl;
}

输出:


#include <string>

using std::string;

/*á?±í?úμ?*/
struct list_head {
struct list_head *next, *prev;
};

/*±íê?êéμ??á11ì?*/
struct Book
{
int bkId;
string bkName;
struct list_head list; //?ùóDμ?Book?á11ì?D?3éá?±í
};

/*3?ê??ˉá?±í*/
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}

/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head * new1,struct list_head * prev,struct list_head * next)
{
next->prev = new1;
new1->next = next;
new1->prev = prev;
prev->next = new1;
}

/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new1, struct list_head *head)
{
__list_add(new1, head->prev, head);
}

/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new1, struct list_head *head)
{
__list_add(new1, head, head->next);
}

/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ const typeof(((type *)0)->member) *__mptr = (ptr); (type *)((char *)__mptr - offsetof(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.
*/
#define list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)

/**
* 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_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)

/**
* 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_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)

/**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_struct within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)

/**
* 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_struct within the struct.
*/
#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))

#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

至此源代码myList.h


#include <iostream>
#include "myList.h"

using namespace std;

int main(void)
{
struct list_head MyBkList; //?????òμ?á?±íí·
INIT_LIST_HEAD(&MyBkList); //3?ê??ˉ?a??á?±í

/*????D?êé?á11ì?*/
struct Book bk1;
bk1.bkId = 1;
bk1.bkName = "book1";

list_add_tail(&bk1.list, &MyBkList); //°?D?êé1?óμ?í·?áμ?MyBkListoó??

struct Book bk2;
bk2.bkId = 2;
bk2.bkName = "book2";

list_add_tail(&bk2.list,&MyBkList); //°?êé2?óμ?bk1ó?MyBkList????£?°?MyBkList??×?í·£??ò?aMyBkList->bk1->bk2(°????úμ?next????£?MyBkListμ?next????ê???óD±?μ?£?MyBkListμ?prev????±?á?)

struct Book bk3 = { 3, "book3" };
list_add(&bk3.list, &MyBkList); //°?êé3?óμ?head??oó£???headμ?next????

struct list_head *p; //pointer to each struct list_head
struct Book *pb; //pointer to struct Book

list_for_each(p,&MyBkList)
{
pb = list_entry(p, struct Book,list);
cout << pb->bkId << " " << pb->bkName << endl;
}

/*
list_for_each_entry(pb, &MyBkList, list)
{
cout << pb->bkId << " " << pb->bkName << endl;
}*/

cin.get();
}

至此源代码main.cpp

还有一个人更漂亮的遍历函数list_for_each_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_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)

/**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_struct within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)

/**
* 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_struct within the struct.
*/
#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))

使用起来更好看:


  struct Book *pb;        //pointer to struct Book
list_for_each_entry(pb, &MyBkList, list)
{
cout << pb->bkId << " " << pb->bkName << endl;
}

当然还有反向遍历等,就不多赘述了。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

  第六章:Linux内核链表删除

  先来看看这个基本的删除节点的函数,这是其他删除函数的基础。其实这个删除函数和添加节点到链表的函数是对应的,添加的基本函数不也是以前后指针为参数并把节点添加到中间吗?Linux内核就是帅!


/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}

下面看调用上面函数的函数,其实list_del()是最常用的函数了,其他函数也只是铺垫:


/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
#ifndef CONFIG_DEBUG_LIST
static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}

static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
#else
extern void __list_del_entry(struct list_head *entry);
extern void list_del(struct list_head *entry);
#endif

其中,LIST_POISON1、LIST_POISON2
在我的M:\linux-3.14.5\include\linux下poison.h文件中:


/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)


/*
* Architectures might want to move the poison pointer offset
* into some well-recognized area such as 0xdead000000000000,
* that is also not mappable by user-space exploits:
*/
#ifdef CONFIG_ILLEGAL_POINTER_VALUE
# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
#else
# define POISON_POINTER_DELTA 0
#endif

上面的一些宏定义作用是:调用 __list_del_entry(struct list_head *entry)删除一个给定节点,这个函数会调用__list_del(struct list_head * prev, struct
list_head *
next),这样使得待删除的节点的前后节点因为正确连到链表里面而没有了问题了,但是待删除节点还是的结构体还是在的,其实并没有删除它,只是把它从链表里面踢出去了。为了防止意外访问到这个节点的前后节点(因为它已经不在链表中了)而出错,就给它的前后指针赋了一个非空但访问会引起页面错误的指针,表明小心中毒哦!

目前为止代码如下:

#include <iostream>
#include "myList.h"

using namespace std;

int main(void)
{
struct list_head MyBkList; //?????òμ?á?±íí·
INIT_LIST_HEAD(&MyBkList); //3?ê??ˉ?a??á?±í

/*????D?êé?á11ì?*/
struct Book bk1;
bk1.bkId = 1;
bk1.bkName = "book1";

list_add_tail(&bk1.list, &MyBkList); //°?D?êé1?óμ?í·?áμ?MyBkListoó??

struct Book bk2;
bk2.bkId = 2;
bk2.bkName = "book2";

list_add_tail(&bk2.list,&MyBkList); //°?êé2?óμ?bk1ó?MyBkList????£?°?MyBkList??×?í·£??ò?aMyBkList->bk1->bk2(°????úμ?next????£?MyBkListμ?next????ê???óD±?μ?£?MyBkListμ?prev????±?á?)

struct Book bk3 = { 3, "book3" };
list_add(&bk3.list, &MyBkList); //°?êé3?óμ?head??oó£???headμ?next????

struct list_head *p; //pointer to each struct list_head

/*
list_for_each(p,&MyBkList)
{
pb = list_entry(p, struct Book,list);
cout << pb->bkId << " " << pb->bkName << endl;
}*/

struct Book *pb; //pointer to struct Book
list_for_each_entry(pb, &MyBkList, list)
{
cout << pb->bkId << " " << pb->bkName << endl;
}

cout<<"------------------------------------"<<endl;

struct Book bk4={4,"book4"};
list_add_tail(&bk4.list,&MyBkList);

list_del(&bk3.list);

list_for_each_entry(pb, &MyBkList, list)
{
cout << pb->bkId << " " << pb->bkName << endl;
}

cin.get();
}

main.cpp

#include <string>

/*
* Architectures might want to move the poison pointer offset
* into some well-recognized area such as 0xdead000000000000,
* that is also not mappable by user-space exploits:
*/
#ifdef CONFIG_ILLEGAL_POINTER_VALUE
# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL)
#else
# define POISON_POINTER_DELTA 0
#endif

/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
* non-initialized list entries.
*/
#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA)
#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA)

using std::string;

/*á?±í?úμ?*/
struct list_head {
struct list_head *next, *prev;
};

/*±íê?êéμ??á11ì?*/
struct Book
{
int bkId;
string bkName;
struct list_head list; //?ùóDμ?Book?á11ì?D?3éá?±í
};

/*3?ê??ˉá?±í*/
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}

/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head * new1,struct list_head * prev,struct list_head * next)
{
next->prev = new1;
new1->next = next;
new1->prev = prev;
prev->next = new1;
}

/**
* list_add_tail - add a new entry
* @new: new entry to be added
* @head: list head to add it before
*
* Insert a new entry before the specified head.
* This is useful for implementing queues.
*/
static inline void list_add_tail(struct list_head *new1, struct list_head *head)
{
__list_add(new1, head->prev, head);
}

/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new1, struct list_head *head)
{
__list_add(new1, head, head->next);
}

/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ const typeof(((type *)0)->member) *__mptr = (ptr); (type *)((char *)__mptr - offsetof(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.
*/
#define list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)

/**
* 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_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)

/**
* 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_struct within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)

/**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_struct within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)

/**
* 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_struct within the struct.
*/
#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))

/*
* Delete a list entry by making the prev/next entries
* point to each other.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}

/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/

static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}

static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = (struct list_head *)LIST_POISON1; //Linux kernel source does not have (struct list_head *)
entry->prev = (struct list_head *)LIST_POISON2;
}

#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

myList.h

到这里已经简单模拟实现了Linux内核链表最最基本的功能,还有其他功能,有兴趣的直接上源代码!

Linux 内核 链表 的简单模拟(2),布布扣,bubuko.com

时间: 2024-12-29 06:58:58

Linux 内核 链表 的简单模拟(2)的相关文章

Linux 内核 链表 的简单模拟

第零章:扯扯淡 出一个有意思的题目:用一个宏定义FIND求一个结构体struct里某个变量相对struc的编移量,如 struct student { int a; //FIND(struct student,a) 等于0 char b; //FIND(struct student,b)等于4 double c; }; 参考答案:#define FIND(type,member) ((size_t)&((type*)0)->member) 我这样理解(可能不太正确): (type*)0,0在

例说Linux内核链表(二)

链表使用 我认为熟悉内核链表功能最好的方法就是看一些简单的实例,实例是一个非常好的素材去更好的理解链表. 下面是一个例子,包含创建,添加,删除和遍历链表. <span style="font-size:14px;"><span style="color:#330099;">#include <stdio.h> #include <stdlib.h> #include "list.h" struct

Linux 内核链表使用举例

链表数据结构的定义很简洁: struct list_head { struct list_head *next, *prev; }; list_head结构包含两个指向list_head结构的指针prev和next,该内核链表具备双链表功能,通常它都组织成双循环链表,这里的list_head没有数据域.在Linux内核链表中,不是在链表结构中包含数据,而是在数据结构中包含链表节点.下面是一个简单的内核模块的例子,包含了对链表进行插入.删除.遍历的一些函数: list.c: #include <l

Linux内核网络报文简单流程

转:http://blog.csdn.net/adamska0104/article/details/45397177 Linux内核网络报文简单流程2014-08-12 10:05:09 分类: Linux linux下的网卡驱动中通常会提供类似XXX_rx的接收函数 该函数处理与具体硬件相关的寄存器操作 包括中断检查,数据状态检查,错误检查等 在确认有数据抵达后读取数据或从DMA的接收环中获取数据地址 XXX_rx函数以skb为元数据结构组织报文数据 随后调用内核接口函数netif_rx或n

链表的艺术——Linux内核链表分析

引言: 链表是数据结构中的重要成员之中的一个.因为其结构简单且动态插入.删除节点用时少的长处,链表在开发中的应用场景许多.仅次于数组(越简单应用越广). 可是.正如其长处一样,链表的缺点也是显而易见的.这里当然不是指随机存取那些东西,而是因为链表的构造方法(在一个结构体中套入其同类型指针)使得链表本身的逻辑操作(如添加结点,删除结点,查询结点等),往往与其应用场景中的业务数据相互混杂.这导致我们每次使用链表都要进行手工打造,做过链表的人肯定对此深有了解. 是否能将链表从变换莫測的业务数据中抽象出

C语言 Linux内核链表(企业级链表)

//Linux内核链表(企业级链表) #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<string.h> #define offscfof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER) #define container_of(ptr,type,member) (type *)((char *)ptr-off

Linux内核链表复用实现队列

有了前面Linux内核复用实现栈的基础,使用相同的思想实现队列,也是非常简单的.普通单链表复用实现队列,总会在出队或入队的时候有一个O(n)复杂度的操作,大多数采用增加两个变量,一个head,一个tail来将O(n)降成O(1).但是在内核链表中,天然的双向循环链表,复用实现队列,无论出队还是入队,都是O(1)时间复杂度. /* main.c */ #include <stdio.h> #include <stdlib.h> #include "queue.h"

Linux 内核链表

一 . Linux内核链表 1 . 内核链表函数 1.INIT_LIST_HEAD:创建链表 2.list_add:在链表头插入节点 3.list_add_tail:在链表尾插入节点 4.list_del:删除节点 5.list_entry:取出节点 6.list_for_each:遍历链表 2.程序代码

例说Linux内核链表(一)

介绍 众所周知,Linux内核大部分是使用GNU C语言写的.C不同于其他的语言,它不具备一个好的数据结构对象或者标准对象库的支持.所以可以借用Linux内核源码树的循环双链表是一件很值得让人高兴的事. 在include/linux/list.h文件中用C实现了一个好用的循环链表.它是有效而且易于操作的,否则它也不会被内核使用(译者注:在kernel中大量的使用了循环双链表结构,比如在在进程描述符实体中我们就可以看到很多struct list_head的身影).不管何时,依靠这种结构,在内核中都