zoukankan      html  css  js  c++  java
  • 内核链表的应用

    本文构建了一个双向循环的内核链表,然后对链表进行遍历并打印了数据,最后释放了链表节点。

    方法1:

    使用到的数据结构和链表操作函数如下:

            struct list_head                      内核提供的双向循环链表节点的结构体

                 LIST_HEAD(name)               该宏定义并初始化一个名为name的struct list_head类型节点

                 INIT_LIST_HEAD(name)      该宏初始化一个由name指向的 struct list_head类型节点,事先需要定义好一个struct list_head类型变量,

                                                             并将变量的指针赋给name,然后再使用该宏

                 list_for_each(pos, head)          该宏可以遍历以head为链表头的循环链表,pos是遍历到的每个节点,pos和head均为指针类型。

                 list_entry(ptr, type, number)      该宏可以得到type类型的结构体指针,number为包含在该type类型结构体中的struct list_head类型成员变量,

                                                                   ptr为&number。返回值为指向type类型的指针。

                 list_for_each_safe(pos, n, head)    该宏类似于list_for_each宏,区别在于每次遍历,n指向了pos的下一个节点。该宏可用于释放链表节点之用。

    程序代码如下:

     1  #include <linux/slab.h>
     2   #include <linux/sched.h>
     3   #include <linux/module.h>
     4   #include <linux/kernel.h>
     5   #include <linux/init.h>
     6   #include <linux/list.h>
     7    
     8   struct fox {
     9           int data;
    10           struct list_head list;
    11   };
    12   
    13   int i;
    14   struct list_head *temp;
    15   struct fox *tmp;
    16   LIST_HEAD(head);
    17   
    18   static int __init test_init(void)
    19   {
    20           for (i = 0; i < 10; i++) {
    21                   tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
    22                   tmp->data = i;
    23                   INIT_LIST_HEAD(&tmp->list);
    24                   list_add_tail(&tmp->list, &head);
    25           }
    26   
    27           list_for_each(temp, &head) {
    28                   tmp = list_entry(temp, struct fox, list);
    29                   printk("<0> %d
    ", tmp->data);
    30           }
    31   
    32           return 0;
    33   }
    34   
    35   static void __exit test_exit(void)
    36   {
    37           struct list_head *next;
    38   
    39           printk("<1> byebye
    ");
    40           list_for_each_safe(temp, next, &head) {
    41                   tmp = list_entry(temp, struct fox, list);
    42                   printk("<0> %d
    ", tmp->data);
    43                   kfree(tmp);
    44           }
    45   }
    46   
    47   module_init(test_init);
    48   module_exit(test_exit);
    49   MODULE_LICENSE("GPL");

    需要注意的是,在释放链表时,不可以直接用list_del(pos)宏来删除节点,该宏仅仅是把struct list_head节点从其链表中卸下来,而且不释放。而我们需要删除的是fox结构体,所以只能使用本文中的这种方法,利用list_for_each_safe()宏,将需要释放的节点指针保存到pos中,同时将下一个节点指针保存在next中,这样就保证了释放节点时链表不会丢失。其实list_head节点是不用单独去释放的,该结构体一般会以结构体变量的形式保存在更大的结构体中,只要释放更大结构题即可。如本例所示的那样。

    方法2:

    也可以用list_for_each_entry()和list_for_each_entry_safe()宏来完成,代码如下:

     1 #include <linux/slab.h>
     2 #include <linux/sched.h>
     3 #include <linux/module.h>
     4 #include <linux/kernel.h>
     5 #include <linux/init.h>
     6 #include <linux/list.h>
     7 
     8 struct fox {
     9     int data;
    10     struct list_head list;
    11 };
    12 
    13 int i;
    14 struct fox *tmp;
    15 LIST_HEAD(head);
    16 
    17 static int __init test_init(void)
    18 {
    19     for (i = 0; i < 10; i++) {
    20         tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
    21         tmp->data = i;
    22         INIT_LIST_HEAD(&tmp->list);
    23         list_add_tail(&tmp->list, &head);
    24     }
    25 
    26     list_for_each_entry(tmp, &head, list) {
    27         printk("<0> %d
    ", tmp->data);
    28     }
    29     
    30     return 0;
    31 }
    32 
    33 static void __exit test_exit(void)
    34 {
    35     struct fox *next;
    36 
    37     printk("<1> byebye
    ");
    38     list_for_each_entry_safe(tmp, next, &head, list) {
    39         printk("<0> %d
    ", tmp->data);
    40         kfree(tmp);    
    41     }
    42 }
    43 
    44 module_init(test_init);
    45 module_exit(test_exit);
    46 MODULE_LICENSE("GPL");

    list_for_each_entry()是list_for_each()和list_entry()二者的结合体,在该程序中对二者进行了替换,使用起来更方便。

    同样,list_for_each_entry_safe是list_for_each_safe()和list_entry()二者的结合体,在本程序中替换了二者。其余都不变。

  • 相关阅读:
    变量的含义,内存管理机制,数据类型的含义
    操作系统、应用程序的含义,编程语言的优缺点
    Pycharm常用快捷键
    计算机组成及原理
    仿酷狗音乐播放器开发日志——整体框架分析
    仿酷狗音乐播放器开发日志——整体框架分析
    c++与java的优缺点
    c++与java的优缺点
    unicode ansi utf-8 unicode_big_endian编码的区别
    unicode ansi utf-8 unicode_big_endian编码的区别
  • 原文地址:https://www.cnblogs.com/liangning/p/3841768.html
Copyright © 2011-2022 走看看