Chinaunix首页 | 论坛 | 博客
  • 博客访问: 652940
  • 博文数量: 90
  • 博客积分: 1201
  • 博客等级: 少尉
  • 技术积分: 2048
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-09 14:28
文章分类

全部博文(90)

文章存档

2013年(10)

2012年(80)

分类:

2012-07-20 10:18:14

原文地址:双向链表辅助接口 作者:add358

 内核中大量使用双向链表来维护相关数据的关系,特别是在一些数据处理模块上面;
 双向链表结构和接口分别在“linux/types.h"和"linux/list.h"中定义。

1 双向链表结构
  1. struct list_head {
  2.     struct list_head *next, *prev;
  3. };
2 该链表使用方法
  通常将这个链表内嵌到其他数据结构体里面,用来组成带有数据的一个链表, 示意图如下:

3 内核提供的接口

  这里是列出几个经常用到的接口,如果想了解更多的接口请查看"linux/list.h"头文件。

初始操作

LIST_HEAD(name);      /*定义并初始化name变量*/
LIST_HEAD_INIT(name); /*初始化name变量*/

插入操作

void list_add(struct list_head *new, struct list_head *head);
/*在head节点后面添加新节点,如果head为链表头,则添加在链表头部*/
void list_add_tail(struct list_head *new, struct list_head *head);
     /*在head节点前面添加新节点,如果head为链表头,则添加在链表尾部*/

删除操作

void list_del(struct list_head *entry);      /*删除链表中指定的节点*/
void list_del_init(struct list_head *entry); /*删除链表中指定的节点并重新初始化该节点*/

移动操作

void list_move(struct list_head *list, struct list_head *head);
/*将list节点移动 到head节点后面*/
void list_move_tail(struct list_head *list, struct list_head *head);
/*将list节点移动到head节点前面*/

判断操作

int list_empty(const struct list_head *head); /*判断链表是否为空,是的话返回1*/

合并操作

void list_splice(const struct list_head *list, struct list_head *head);
/*将list链表添加到head节点后面*/

读取操作

void *list_entry(struct list_head *ptr, type, member);
/*将ptr指针映射回指向包含它的大结构的指针*/

遍历操作

list_for_each(*pos, *head);               /*遍历链表,使用时需加{}*/
list_for_each_prev(*pos, *head);          /*向后遍历链表*/
list_for_each_entry(*pos, *head, member); /*遍历链表,并将大结构的指针赋给pos*/ list_for_each_entry_safe(*pos, *n, *head, member); /*同上*/
注意:使用链表时,千万要注意指针的使用,使用错误的指针可能会导致内核崩溃。

4 示例代码    list.rar  
 这里只使用几个接口进行演示。

点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/init.h>
  3. #include <linux/list.h>
  4. #include <linux/slab.h>

  5. MODULE_LICENSE("Dual BSD/GPL");
  6. MODULE_AUTHOR("Kozo");

  7. /*自己定义的结构体,内嵌list_head结构体*/
  8. struct my_struct{
  9.     const char *name;
  10.     int index;
  11.     struct list_head list;
  12. };

  13. /*两种定义及初始化list_head结构的变量*/
  14. //struct list_head head = LIST_HEAD_INIT(head);
  15. LIST_HEAD(head);
  16. static int __init demo_init(void)
  17. {
  18.     struct my_struct *task1;
  19.     struct my_struct *task2;
  20.     struct my_struct *task3;

  21.     task1 = (struct my_struct *)kmalloc(sizeof(struct my_struct),GFP_KERNEL);
  22.     task2 = (struct my_struct *)kmalloc(sizeof(struct my_struct),GFP_KERNEL);
  23.     task3 = (struct my_struct *)kmalloc(sizeof(struct my_struct),GFP_KERNEL);

  24.     task1->name="One";
  25.     task1->index=1;
  26.     task2->name="Two";
  27.     task2->index=2;
  28.     task3->name="Three";
  29.     task3->index=3;
  30.     
  31.     list_add(&task1->list,&head);
  32.     list_add(&task2->list,&head);
  33.     list_add(&task3->list,&head);

  34.     printk(KERN_DEBUG"added node\n");
  35.     return 0;
  36. }

  37. static void __exit demo_exit(void)
  38. {
  39.     struct my_struct *task;
  40.     struct my_struct *tmp = NULL;
  41.     list_for_each_entry(task,&head,list){
  42.         printk(KERN_DEBUG"name:%s,index:%d\n",task->name,task->index);
  43.         if(tmp == NULL)
  44.    /*注意,使用list_for_each_entry时,不能删除读取到节点,但可以删除该节点的前节点或后节点*/
  45.             tmp = task;
  46.         else
  47.         {
  48.             list_del(&tmp->list);
  49.             kfree(tmp);
  50.             tmp = task;
  51.         }
  52.     }
  53.         list_del(&tmp->list);
  54.         kfree(tmp);
  55.     /*确认已经删除所有添加的节点*/
  56.     list_for_each_entry(task,&head,list){
  57.         printk(KERN_DEBUG"name:%s,index:%d\n",task->name,task->index);
  58.     }
  59.     printk("drop node,and free memory\n");
  60. }
  61. module_init(demo_init);
  62. module_exit(demo_exit);
5 执行结果


注:转载时请注明出自:add358.blog.chinaunix.net
阅读(1913) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~