Linux kernel中的list怎么使用

需要使用链表的时候, 就想到直接使用Linux kernel 里面的 list 了. 于是找到一片文章, 相当于翻译这篇文章. 学习怎么用的笔记

原文地址: http://isis.poly.edu/kulesh/stuff/src/klist/ 

原文日期: This is a working copy, last updated on April 5th, 2005. Feel free to email your comments.

我看完之后,总结这些函数 的用处,以后方便的立刻使用, 像知道为什么, 就往下看哦

 struct list_head : 链表结构体的指针的数据结构

LIST_HEAD_INIT: 用于初始化这个头部编成独立结点

INIT_LIST_HEAD(ptr) : 将这个指针初始化为孤立的结点

LIST_HEAD(name) : 初始化一个变量为name, 并且初始化

list_add(struct list_head *new, struct list_head *head): 将新元素, 放到了链表的头端

 void list_add_tail(struct list_head *new, struct list_head *head): 添加一个到尾部

list_del(struct list_head *entry): 删除这个结点, 没有切断联系

list_del_init(struct list_head *entry) : 删除这个元素并且初始化

list_move(struct list_head *list, struct list_head *head): 将第一个链表的头删, 然后连接到第二个链表.

list_move_tail(struct list_head *list, struct list_head *head): 将第一个链表移动到, 到第二个链表后面

list_empty(struct list_head *head): 判断这个链表是否为空

list_splice(struct list_head *list, struct list_head *head): 将第一个链表接到第二个链表的开头.

list_splice_init(struct list_head *list, struct list_head *head): 在上面的功能之上, 再将第一个头结点初始化

list_entry(ptr, type, member): 获得这个指针的所再的项的开头

list_for_each(pos, head): 从前到后遍历链表

list_for_each_prev(pos, head): 从后到前遍历链表

list_for_each_safe(pos, n, head): 删除当前结点不会造成断链

list_for_each_entry(pos, head, member): 这个可以自己少写一句list_entry

 list_for_each_entry_safe(pos, n, head, member): 遍历可以安全删除

 

 

 

 


 

简介:

linux内核大部分都是C语言写的. 不像其他语言, C语言没有一个很好的内置的数据结构. 也没有一些标准库能够支持. 因此, 能够借用内核里面的一个循环链表是十分让人兴奋的.

源文件是在 include/linux/list.h. 这是个与类型无关, 容易实用, 循环的链表, 使用C语言写成. 这个实现能够有效率,并且可移植. 在下面的使用当中, 作者修改了部分, 删除了有关硬件的细节. 所以也可以使用这个东西在我们的程序. 文中提供了下在文件.

使用这个列表, 有以下的优点:

类型无关, 可移植, 容易使用, 可读, 节约时间.

 

如果要创建一个list, 我们可以这样定义数据结构

struct my_cool_list{
    struct list_head list; /* kernel's list structure */
    int my_cool_data;
    void* my_cool_void;
};

注意:

链表是在你的数据项里面的一个成员.

你可以将struct list_head 这个结构体放在任何地方

你可以将struct list_head 变量命名为任意的名字

你可以有多个list

比如说下面这个例子:

struct todo_tasks{
    char *task_name;
    unsigned int name_len;
    short int status;

    int sub_tasks;

    int subtasks_completed;
    struct list_head completed_subtasks;/* list structure */

    int subtasks_waiting;
    struct list_head waiting_subtasks;     /* another list of same or different items! */

    struct list_head todo_list;            /* list of todo_tasks */
};

在linux kernel 里面有很多使用这个的例子:

比如说 struct inode 和 struct block_device.

list_head的定义是

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

 

如何使用这个list

正如下面这段代码所显示的:

#include <stdio.h>
#include <stdlib.h>

#include "list.h"

struct kool_list{
    int to;
    struct list_head list;
    int from;
    };

int main(int argc, char **argv){
    struct kool_list *tmp;
    struct list_head *pos, *q;
    unsigned int i;

    struct kool_list mylist;
    INIT_LIST_HEAD(&mylist.list);
    /* or you could have declared this with the following macro
     * LIST_HEAD(mylist); which declares and initializes the list
     */

    /* adding elements to mylist */
    for(i=5; i!=0; --i){
        tmp= (struct kool_list *)malloc(sizeof(struct kool_list));
        
        /* INIT_LIST_HEAD(&tmp->list); 
         *
         * this initializes a dynamically allocated list_head. we
         * you can omit this if subsequent call is add_list() or 
         * anything along that line because the next, prev
         * fields get initialized in those functions.
         */
        printf("enter to and from:");
        scanf("%d %d", &tmp->to, &tmp->from);

        /* add the new item 'tmp' to the list of items in mylist */
        list_add(&(tmp->list), &(mylist.list));
        /* you can also use list_add_tail() which adds new items to
         * the tail end of the list
         */
    }
    printf("\n");


    /* now you have a circularly linked list of items of type struct kool_list.
     * now let us go through the items and print them out
     */


    /* list_for_each() is a macro for a for loop. 
     * first parameter is used as the counter in for loop. in other words, inside the
     * loop it points to the current item's list_head.
     * second parameter is the pointer to the list. it is not manipulated by the macro.
     */
    printf("traversing the list using list_for_each()\n");
    list_for_each(pos, &mylist.list){

        /* at this point: pos->next points to the next item's 'list' variable and 
         * pos->prev points to the previous item's 'list' variable. Here item is 
         * of type struct kool_list. But we need to access the item itself not the 
         * variable 'list' in the item! macro list_entry() does just that. See "How
         * does this work?" below for an explanation of how this is done.
         */
         tmp= list_entry(pos, struct kool_list, list);

         /* given a pointer to struct list_head, type of data structure it is part of,
          * and it's name (struct list_head's name in the data structure) it returns a
          * pointer to the data structure in which the pointer is part of.
          * For example, in the above line list_entry() will return a pointer to the
          * struct kool_list item it is embedded in!
          */

         printf("to= %d from= %d\n", tmp->to, tmp->from);

    }
    printf("\n");
    /* since this is a circularly linked list. you can traverse the list in reverse order
     * as well. all you need to do is replace 'list_for_each' with 'list_for_each_prev'
     * everything else remain the same!
     *
     * Also you can traverse the list using list_for_each_entry() to iterate over a given
     * type of entries. For example:
     */
    printf("traversing the list using list_for_each_entry()\n");
    list_for_each_entry(tmp, &mylist.list, list)
         printf("to= %d from= %d\n", tmp->to, tmp->from);
    printf("\n");
    

    /* now let's be good and free the kool_list items. since we will be removing items
     * off the list using list_del() we need to use a safer version of the list_for_each() 
     * macro aptly named list_for_each_safe(). Note that you MUST use this macro if the loop 
     * involves deletions of items (or moving items from one list to another).
     */
    printf("deleting the list using list_for_each_safe()\n");
    list_for_each_safe(pos, q, &mylist.list){
         tmp= list_entry(pos, struct kool_list, list);
         printf("freeing item to= %d from= %d\n", tmp->to, tmp->from);
         list_del(pos);
         free(tmp);
    }

    return 0;
}

 

 

这个文件, 能够使用的功能是创建, 增加, 删除和遍历这个list. 首先浏览下源代码:

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

定义一个有前一个和后一个的链表的指针.

 

#define LIST_HEAD_INIT(name) { &(name), &(name) }

初始化这个链表指向自己. 在应用的时候, 定义完自己的 struct kool_list mylist, 然后可以使用INIT_LIST_HEAD(&mylist.list) 来进行这个的连边的初始化. 但我看代码,我觉得也可以利用 LIST_HEAD(mylist)

 

#define LIST_HEAD(name) \
    struct list_head name = LIST_HEAD_INIT(name)

这个宏, 定义了一个名为name的变量, 并且初始化它位链表

 

#define INIT_LIST_HEAD(ptr) do { \
    (ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)

这个宏是将next设置为ptr,然后将ptr的宏的前一个设置位ptr. 将head设置为头结点, 也就是将ptr设置位头.

 

/*
 * 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 *new,
                  struct list_head *prev,
                  struct list_head *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}

这个函数已经注释了, 说的是, 这个函数, 只能是用于知道前后结点, 插入在这两个中间. 

 

/**
 * 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 *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

list_add() 这个就是将新添加的链表放在new这里. 要注意的是, new必须是list_head的结构, head是头部, head->next就是下一个, 那么这个函数的用法就是, 将新元素, 放到了链表的头端.

 

/**
 * 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 *new, struct list_head *head)
{
    __list_add(new, head->prev, head);
}

添加到尾部, 就是使用head->prev, 然后head作为下一个.

 

/*
 * 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(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    entry->next = (void *) 0;
    entry->prev = (void *) 0;
}

直接删除这个结点, 没有将联系斩断

 

/**
 * list_del_init - deletes entry from list and reinitialize it.
 * @entry: the element to delete from the list.
 */
static inline void list_del_init(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    INIT_LIST_HEAD(entry); 
}

将这个结点从链表中删除, 然后将这个结点初始化为自己, 也就是将这个结点初始化为孤立结点.

 

/**
 * list_move - delete from one list and add as another's head
 * @list: the entry to move
 * @head: the head that will precede our entry
 */
static inline void list_move(struct list_head *list, struct list_head *head)
{
        __list_del(list->prev, list->next);
        list_add(list, head);
}

将一个结点删除, 然后添加它添加到另外一个链表的头部

 

/**
 * list_move_tail - delete from one list and add as another's tail
 * @list: the entry to move
 * @head: the head that will follow our entry
 */
static inline void list_move_tail(struct list_head *list,
                  struct list_head *head)
{
        __list_del(list->prev, list->next);
        list_add_tail(list, head);
}

将一个结点删除, 然后将它添加到另外一个链表的尾部

 

/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
static inline int list_empty(struct list_head *head)
{
    return head->next == head;
}

测试这个链表是否是空的, 只要判断头部是否指向自己

 

static inline void __list_splice(struct list_head *list,
                 struct list_head *head)
{
    struct list_head *first = list->next;
    struct list_head *last = list->prev;
    struct list_head *at = head->next;

    first->prev = head;
    head->next = first;

    last->next = at;
    at->prev = last;
}

将两个循环链表连接起来, 做法就是找到第一个链表, 不要头,将第一个链表的头尾, 头连接到第二个头的后面, 然后将第一个链表的尾巴, 接到原来第二个第二个元素的前面..

 

/**
 * list_splice - join two lists
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
static inline void list_splice(struct list_head *list, struct list_head *head)
{
    if (!list_empty(list))
        __list_splice(list, head);
}

这个就是在上面的函数的基础上, 先判断第一个list是否为空, 然后再进行连接.

 

/**
 * list_splice_init - join two lists and reinitialise the emptied list.
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 *
 * The list at @list is reinitialised
 */
static inline void list_splice_init(struct list_head *list,
                    struct list_head *head)
{
    if (!list_empty(list)) {
        __list_splice(list, head);
        INIT_LIST_HEAD(list);
    }
}

这个是在上面的基础上, 将第一个链表的头进行了初始化为一个孤立的点.

 

/**
 * 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) \
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

这个的作用就是从ptr所指的type的类型,寻找member的这个变量.稍微讲解下这个的用法

如果调用是

 list_entry(pos, struct kool_list, list);


#define list_entry(ptr, type, member) \
    ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
那么这个宏,就会扩展为
((struct kool_list *)((char *)(pos) - (unsigned long)(&((struct kool_list *)0)->list)))
这样就可以计算出那个想要的成员的开始的地址, 最后转换,就成了这个的入口了.

 

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

这个宏, 的作用就是从head开始的第一个函数开始, 遍历这个链表, 用for语句

用例: 

list_for_each(pos, &mylist.list){

        /* at this point: pos->next points to the next item's 'list' variable and 
         * pos->prev points to the previous item's 'list' variable. Here item is 
         * of type struct kool_list. But we need to access the item itself not the 
         * variable 'list' in the item! macro list_entry() does just that. See "How
         * does this work?" below for an explanation of how this is done.
         */
         tmp= list_entry(pos, struct kool_list, list);

         /* given a pointer to struct list_head, type of data structure it is part of,
          * and it's name (struct list_head's name in the data structure) it returns a
          * pointer to the data structure in which the pointer is part of.
          * For example, in the above line list_entry() will return a pointer to the
          * struct kool_list item it is embedded in!
          */

         printf("to= %d from= %d\n", tmp->to, tmp->from);

    }

这个用于遍历, 对于删除元素并不安全,删除了可能会断链

 

 

/**
 * list_for_each_prev    -    iterate over a list backwards
 * @pos:    the &struct list_head to use as a loop counter.
 * @head:    the head for your list.
 */
#define list_for_each_prev(pos, head) \
    for (pos = (head)->prev; pos != (head); \
            pos = pos->prev)

反向遍历这个这个链表

 

/**
 * list_for_each_safe    -    iterate over a list safe against removal of list entry
 * @pos:    the &struct list_head to use as a loop counter.
 * @n:        another &struct list_head to use as temporary storage
 * @head:    the head for your list.
 */
#define list_for_each_safe(pos, n, head) \
    for (pos = (head)->next, n = pos->next; pos != (head); \
        pos = n, n = pos->next)

使用的例子是:

    list_for_each_safe(pos, q, &mylist.list){
         tmp= list_entry(pos, struct kool_list, list);
         printf("freeing item to= %d from= %d\n", tmp->to, tmp->from);
         list_del(pos);
         free(tmp);
    }

这个版本的用法就是, 你能够在循环结构里面安全的删除所遍历的元素

 

/**
 * list_for_each_entry    -    iterate over list of given type
 * @pos:    the type * to use as a loop counter.
 * @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_entry((head)->next, typeof(*pos), member);    \
         &pos->member != (head);                     \
         pos = list_entry(pos->member.next, typeof(*pos), member))

遍历链表, 寻找链表中的某个成员. 可以让我们根据某个链表来进行遍历.

list_for_each_entry(tmp

    list_for_each_entry(tmp, &mylist.list, list)
         printf("to= %d from= %d\n", tmp->to, tmp->from);
    list_for_each(pos, &mylist.list){
         tmp= list_entry(pos, struct kool_list, list);
         printf("to= %d from= %d\n", tmp->to, tmp->from);
    }

相比list_for_each, 简化了里面自己需要i写的语句.

 

/**
 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @pos:    the type * to use as a loop counter.
 * @n:        another type * to use as temporary storage
 * @head:    the head for your list.
 * @member:    the name of the list_struct within the struct.
 */
#define list_for_each_entry_safe(pos, n, head, member)            \
    for (pos = list_entry((head)->next, typeof(*pos), member),    \
        n = list_entry(pos->member.next, typeof(*pos), member);    \
         &pos->member != (head);                     \
         pos = n, n = list_entry(n->member.next, typeof(*n), member))

同样, 这个可以安全的删除元素.

 

posted @ 2017-04-23 21:58  WenYao.Huang  阅读(20387)  评论(0编辑  收藏  举报