[转帖]Linux内核链表基础_VMware, Unix及操作系统讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  VMware, Unix及操作系统讨论区 »
总帖数
1
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 3771 | 回复: 0   主题: [转帖]Linux内核链表基础        下一篇 
mengyuanye
注册用户
等级:少校
经验:1413
发帖:108
精华:7
注册:2012-11-14
状态:离线
发送短消息息给mengyuanye 加好友    发送短消息息给mengyuanye 发消息
发表于: IP:您无权察看 2012-11-22 15:54:16 | [全部帖] [楼主帖] 楼主

Linux内核链表基础

分类: Linux笔记 2012-08-28 21:50180人阅读评论(0)收藏举报

1、内核链表的定义在include/linux/list.h

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


容易看出,Linux内核链表为双向链表

2Linux链表与普通链表区别
我们通常定义的链表是在链表节点中嵌入元素,比如

struct MyList
{
      int StudentID;
      struct MyList *prev;
      struct MyList *next;
}


LInux为了移植方便性和通用性,在元素结构体中嵌入链表节点

strcut MyList
{
      int StudentID;
      struct list_head head;
}


3Linux内核链表中提供的操作链表函数
(1)初始化

static inline void INIT_LIST_HEAD(struct list_head *list)
{
      list->next = list;
      list->prev = list;
}


(2)添加链表节点

static inline void list_add(struct list_head *new, struct list_head *head)
{
      __list_add(new, head, head->next);
}


__list_add函数如下

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;
}


(3)删除节点
方法一:

static inline void list_del(struct list_head *entry)
{
      __list_del(entry->prev, entry->next);
      entry->next = (void *)0xDEADBEEF;
      entry->prev = (void *)0xBEEFDEAD;
}


其中调用的__list_del函数如下,

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


注意list_del函数中的最后两条语句,类似于free()的作用。
当用户打算访问地址0xDEADBEEF0xBEEFDEAD时,将产生页中断。

方法二:
为了更安全的删除节点,可使用list_del_init

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


(4)提取结构的数据信息
按通常的方式使用链表很容易获取数据信息,
但使用Linux内核链表要访问数据则比较困难,
关键是如何求取链表节点地址和数据地址的偏移量。
注意list_entry传递的参数!type指传递的是类型,不是变量。

#define list_entry(ptr, type, member) \
container_of(ptr, type, member)


container_of定义在include/linux/kernel.h中,

#define container_of(ptr, type, member) ({ \
      const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); })


而其中,

[a]#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)


[b]typeof()gcc的扩展,和sizeof()类似

(5)、遍历链表

#define list_for_each(pos, head) \
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
pos = pos->next)


遍历链表也是一个宏定义,且是一个没加{}for循环,
因此调用此函数时一定要加上{}
使用时注意参数pos是指针类型,我们要定义一个list_head类型的
结构体变量指针传送给这个函数。

    4、链表使用实例

[cpp]view plaincopyprint?
1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/init.h>
4 #include <linux/slab.h>
5 #include <linux/list.h>
6
7 MODULE_LICENSE("GPL");
8 MODULE_AUTHOR("monkeyzx");
9 MODULE_DESCRIPTION("Mylist Module");
10 MODULE_VERSION("V1.0");
11
12 struct student
13 {
      14 char name[100];
      15 int id;
      16 struct list_head list;
17 };
18
19 struct student *pstudent;
20 struct student *tmp_student;
21 struct list_head student_list;
22 struct list_head *pos;
23
24 int __init mylist_init()
25 {
      26 int i = 0;
      27
      28 INIT_LIST_HEAD(&student_list);
      29
      30 pstudent = kmalloc(sizeof(struct student)*5, GFP_KERNEL);
      31 memset(pstudent, 0, sizeof(struct student)*5);
      32
      33 for(i=0; i<5; i++)
      34 {
            35 sprintf(pstudent[i].name, "Student %d", i+1);
            36 pstudent[i].id = i + 1;
            37 list_add(&(pstudent[i].list), &student_list);
      38 }
      39
      40 list_for_each(pos, &student_list)
      41 {
            42 tmp_student = list_entry(pos, struct student, list);
            43 printk("<0>student %d name: %s\n", tmp_student->id, tmp_student->name);
            44
      45 }
46 }
47
48 void __exit mylist_exit()
49 {
      50 int i = 0;
      51
      52 for(i=0; i<5; i++)
      53 {
            54 list_del(&(pstudent[i].list));
      55 }
      56
      57 kfree(pstudent);
58 }
59
60 module_init(mylist_init);
61 module_exit(mylist_exit);


makefile文件如下

#######################################################################
[cpp]view plaincopyprint?
62 ifneq ($(KERNELRELEASE),)
63
64 obj-m := mylist.o
65
66 else
67
68 KDIR := /lib/modules/2.6.18-53.el5/build
69 all:
70     make -C $(KDIR) M=$(PWD) modules
71 clean:
72     rm -f *.ko *.o *.mod.o *.mod.c *.symvers
73
74 endif




赞(0)    操作        顶端 
总帖数
1
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论