嵌入式LINUX驱动学习之13内核数据结构(链表)

嵌入式LINUX驱动学习之13内核数据结构(链表)

一、头文件、函数及说明

/*
   1、linux内核初始化链表函数 :INIT_LIST_HEAD()
*/
   static inline void INIT_LIST_HEAD(struct list_head *list)
{
    
    
        list->next = list;
        list->prev = list;
}

/*
    2、向链表添加节点函数:list_add()
           参数说明:
                   new   : 需要添加到链表的结构体的struct list_head 成员
                   head  :链表头
           功能:向链表head中添加一个节点;
  */          
static inline void list_add(struct list_head *new, struct list_head *head)
{
    
    
        __list_add(new, head, head->next);
}

/*
    3、从链表中删除一个节点:list_del()
            参数说明:
                entry : 要删除的节点成员struct list_head变量名
*/
void list_del(struct list_head *entry);

/*
   4、将两个链表合并: list_move()
          参数说明:
              list : 被合并的链表的头
              head : 目的链表的头
*/
   void list_move(struct list_head *list, struct list_head *head)

/*
    5、判断一个节点是否为链表最后一个节点:list_is_last()
           参数说明:
                    list : 用于判断的节点
                    head : 链表的头
*/
 int list_is_last(const struct list_head *list,const struct list_head *head)

/*
    6、判断链表是否为空:list_empty()
 */
 int list_empty(const struct list_head *head)

/*
    7、遍历列表方式一 :list_for_each()
           参数说明:
                    pos  : 用于保存遍历过程中的节点结构体的struct list_head成员变量的地址
                    head : 要遍历的链表头的地址

*/
#define list_for_each(pos, head) \
        for (pos = (head)->next; pos != (head); pos = pos->next)
/*
    8、根据结构体的struct list_head成员变量的地址得到结构体地址:list_entry()
           参数说明:
                    ptr   :  struct list_head成员变量的地址
                    type  :  结构体名称,如:struct inode
                    member :  结构体中成员变量结构struct list_head 变量名称  
           主要是配合上面的list_for_each()使用;                 
*/
#define list_entry(ptr, type, member) \
        container_of(ptr, type, member)
/*
    例 A.1  后续举例均有可能参考当前实例的内容
    list_for_each()和list_entry()配合使用举例:
        struct person {
            char name[30];
            char sex[4];
            int age;
            //........省略更多........
            struct list_head person_list;//用这个成员构成链表
        }
        void xxx_func(void){
            struct person *zhangsan,*lisi,*wangwu,*zhaoliu;
            struct person *tmp_person;
            struct list_head *person_list_head;
            struct list_head *list_head_addr;
            INIT_LIST_HEAD(person_list_head);
            zhangsan = kmalloc(sizeof(*zhangsan),GFP_KERNEL);
            strcpy(zhangsan -> name , "张三");
            strcpy(zhangsan ->sex , "男");
            zhangsan ->age = 20;
            //.........省略更多..............
            //.........省略:lisi,wangwu,zhaoliu.........
            list_add(zhangsan,person_list_head); //将zhangsan结构体加入到链表person_list_head中
            list_add(lisi,person_list_head);
            list_add(wangwu,person_list_head);
            list_add(zhaoliu,person_list_head);
            //遍历列表,将每次的struct list_head对象地址保存到list_head_addr中
            list_for_each(list_head_addr,person_list_head)
                 //根据结构体struct person、成员变量链表person_list、链表中节点的地址list_head_addr得到结构体struct person的地址;
                tmp_person = list_entry(list_head_addr,struct person,person_list)
                    printk("姓名:%s , 性别 :%s , 年龄:%d .....\n",tmp_person ->name,tmp_person -> sex , tmp_person -> age);
 */ 
                   
    9、遍历列表方式二 :list_for_each_entry()
           参数说明:
               pos    : 用于保存遍历过程中的节点结构体地址
               head   : 要遍历的链表头的地址
               member :pos中的struct list_head成员变量的名称
*/
    #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))

/*
    10、可用于安全删除节点的遍历函数一:list_for_each_entry_safe()
            参数说明(引用上述的例A.1结构体):
                     pos   : struct person 结构体类型指针
                     n     : struct person 结构体类型指针
                     head  : 要遍历的链表头的地址,结构体:struct list_head
                     member: struct person 结构体中成员变量struct list_head类型结构体名
*/
#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))
/*
     使用举例(引用例A.1的结构体、对象、方法):
            //安全的删除所有节点,***实际开发中要记得加锁***
            per *pos , *pos_next;
            list_for_each_entry_safe(pos,pos_next,&per_list_head,per_list){
                list_del(&(pos -> per_list));
                kfree(pos);
            }
*/


 11、可用于安全删除节点的遍历函数二:
          参数说明:
                  pos   : struct list_head 结构体类型指针
                  n     : struct list_head 结构体类型指针
                  head  : 要遍历的链表头的地址,结构体:struct list_head
     #define list_for_each_safe(pos, n, head) \
        for (pos = (head)->next, n = pos->next; pos != (head); \
                pos = n, n = pos->next)
/*
     使用举例(引用例A.1的结构体、对象、方法):
            //安全的删除所有节点,***实际开发中要记得加锁***
            struct list_head *list_pos , *list_pos_next;
            per *tmp_per_list;
            list_for_each_safe(list_pos,list_pos_next,&per_list_head){
                tmp_per_list = list_entry(list_pos,per,per_list);
                list_del(list_pos);
                kfree(tmp_per_list);
            }
            //实例删除遍历中的某个节点,***实际开发中要记得加锁***
                list_for_each_safe(list_pos,list_pos_next,&per_list_head){
                    if(list_pos == &(per_3 ->per_list)){
                        tmp_per_list = list_entry(list_pos,per,per_list);
                        list_del(list_pos);
                         kfree(tmp_per_list);
                    }
                }
*/

猜你喜欢

转载自blog.csdn.net/weixin_47273317/article/details/108279312