Linux内核链表

来源:互联网 发布:mac环境变量在哪 编辑:程序博客网 时间:2024/06/04 18:24

一、简介

  链表是一种常用的数据结构,它通过指针将一系列数据节点连接成一条数据链。相对于数组,链表具有更好的动态性,建立链表时无需预先知道数据总量,可以随机分配空间,可以高效地在链表中的任意位置实时插入或删除数据。链表的开销主要是访问的顺序性和组织链的空间损失。
  通常链表数据结构至少包含两个域:数据域和指针域,数据域用于存储数据,指针域用于建立与下一个节点的联系。按照指针域的组织以及各个节点之间的联系形式,链表又可以分为单链表、双链表、循环链表等多种类型。

二、内核链表

在Linux内核中使用了大量的链表结构来组织数据。这些链表大多采用了[include/linux/list.h]中实现的一套链表数据结构。

1. 定义

链表数据结构的定义:

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

list_head结构包含两个指向list_head结构的指针prev和next,由此可见,内核的链表具备双链表功能,实际上,通常它都组织成双向循环链表

传统的链表,指针的类型会随着节点struct的类型改变而改变,带数据域的链表降低了链表的通用性,不容易扩展;而Linux内核链表中,指针的类型固定不变都是 stuct list_head*。
传统链表-Linux内核链表

2. 链表操作

初始化链表头

/* * Simple doubly linked list implementation. * * Some of the internal functions ("__xxx") are useful when * manipulating whole lists rather than single entries, as * sometimes we already know the next/prev entries and we can * generate better code by using them directly rather than * using the generic single-entry routines. */#define LIST_HEAD_INIT(name) { &(name), &(name) }// 实例化list_head,并通过结构体直接赋值方式初始化#define LIST_HEAD(name) \    struct list_head name = LIST_HEAD_INIT(name)static inline void INIT_LIST_HEAD(struct list_head *list){    list->next = list;    list->prev = list;}

从链表头插入节点(插入头节点时)

/** * 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. * 在heah节点后面插入new节点,适用于实现栈 * This is good for implementing stacks. */static inline void list_add(struct list_head *new, struct list_head *head){    // 在head和head->next之间插入new节点    __list_add(new, head, head->next);}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;}

从链表尾插入节点(插入头节点时)

/** * 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. * 在heah节点前面插入new节点,适用于实现队列 * This is useful for implementing queues. */static inline void list_add_tail(struct list_head *new, struct list_head *head){    __list_add(new, head->prev, head);}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;}

删除节点

static inline void list_del(struct list_head *entry){    __list_del(entry->prev, entry->next);    entry->next = LIST_POISON1;    entry->prev = LIST_POISON2;}/* * 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_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. * 已知数据结构(type型)中的节点指针ptr,找出数据结构 */#define list_entry(ptr, type, member) \    container_of(ptr, 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)

3. 应用例子

#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/list.h>MODULE_LICENSE("GPL");MODULE_AUTHOR("XY");MODULE_DESCRIPTION("List Module");MODULE_ALIAS("List module");struct student{    cahr name [100];    int num;    struct list_head list;};struct student *pstudent;struct student *tmp_student;struct list_head student_list;struct list_head *pos;int mylist_init(){    int i =0;    INIT_LIST_HEAD(&student_list);    pstudent = kmalloc(sizeof(struct student)*5,GFP_KERNEL);    memset(pstudent,0,sizeof(struct student)*5);    for(i=0;i<5;i++)    {        sprintf(pstudent[i].name,"Student%d",i+1);        pstudent[i].num = i+1;        list_add(&(pstudent[i].list),&student_list);    }    list_for_each(pos,&student_list)    {        tmp_student=list_entry(pos,struct student,list);        printk("<0>student %d name: %s\n",tmp_student->num,tmp_student->name);    }    return 0;}void mylist_exit(){    int i;    for(i=0;i<5;i++)    {        list_del(&(&pstudent[i].list));    }    kfree(pstudent);}module_init(mylist_init);module_exit(mylist_exit);
原创粉丝点击