linux内核_list

概述

内核有一个include/linux/list.h头文件是一个经典简单的双向连表实现,在内核使用及其广泛。

list使用方式:

  • 将list结构体list_head定义在私有结构体的任意位置
    struct rapl_pmu {
    	raw_spinlock_t		lock;
    	int			n_active;
    	int			cpu;
    	struct list_head	active_list; //> 在私有结构体中添加链表结构体
    	struct pmu		*pmu;
    	ktime_t			timer_interval;
    	struct hrtimer		hrtimer;
    };
    
  • 调用list链表操作接口,即可将操作链表

list应用场景:

  • 需要通过连表存储数据
  • 需要增,删,改,查的连表操作
  • 简化链表操作

常用接口说明

  • LIST_HEAD_INIT: 初始化节点,会将next,prev指针指向实例本身地址, 声明实例时使用 | INIT_LIST_HEAD: 初始化节点, 内链函数实现
    #define LIST_HEAD_INIT(name) { &(name), &(name) }
    
  • LIST_HEAD: 定义一个list_head实例并初始化
    #define LIST_HEAD(name) \
    	struct list_head name = LIST_HEAD_INIT(name)
    
  • list_add_tail: 追加节点到链表尾部
  • list_del: 从链表中将当前节点删除
  • list_empty: 空链表判断 | list_empty_careful 比前者判断更加严谨
  • list_entry: 从成员(这里指list成员)的地址获取结构体的地址,同container_of
    #define container_of(ptr, type, member) ({				\
    	void *__mptr = (void *)(ptr);					\
    	BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&	\
    			 !__same_type(*(ptr), void),			\
    			 "pointer type mismatch in container_of()");	\
    	((type *)(__mptr - offsetof(type, member))); })
    
  • list_for_each: 遍历链表(仅读)
  • list_for_each_safe: 遍历链表(有珊链表操作时使用)

使用场景举例

linux-5.9/fs/ext4/super.c 

	printk(KERN_ERR "sb_info orphan list:\n");
	list_for_each(l, &sbi->s_orphan) {
		struct inode *inode = orphan_list_entry(l);
		printk(KERN_ERR "  "
		       "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
		       inode->i_sb->s_id, inode->i_ino, inode,
		       inode->i_mode, inode->i_nlink,
		       NEXT_ORPHAN(inode));
	}

"list_for_each(l, &sbi->s_orphan)" : 等同for循环,将复杂的判断和迭代过程封装, 便于使用# 概述
内核有一个include/linux/list.h头文件是一个简单的双向连表实现,在内核使用及其广泛。

list使用方式:

  • 将list结构体list_head定义在私有结构体的任意位置
    struct rapl_pmu {
    	raw_spinlock_t		lock;
    	int			n_active;
    	int			cpu;
    	struct list_head	active_list; //> 在私有结构体中添加链表结构体
    	struct pmu		*pmu;
    	ktime_t			timer_interval;
    	struct hrtimer		hrtimer;
    };
    
  • 调用list链表操作接口,即可将操作链表

list应用场景:

  • 需要通过连表存储数据
  • 需要增,删,改,查的连表操作
  • 简化链表操作

常用接口说明

  • LIST_HEAD_INIT: 初始化节点,会将next,prev指针指向实例本身地址 | 声明实例时使用
    #define LIST_HEAD_INIT(name) { &(name), &(name) }
    
  • INIT_LIST_HEAD: 初始化节点, 内链函数实现
  • LIST_HEAD: 定义一个list_head实例并初始化
    #define LIST_HEAD(name) \
    	struct list_head name = LIST_HEAD_INIT(name)
    
  • list_add_tail: 追加节点到链表尾部
  • list_del: 从链表中将当前节点删除
  • list_empty: 空链表判断 | list_empty_careful 比前者判断更加严谨
  • list_entry: 从成员(这里指list成员)的地址获取结构体的地址,同container_of
    #define container_of(ptr, type, member) ({				\
    	void *__mptr = (void *)(ptr);					\
    	BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&	\
    			 !__same_type(*(ptr), void),			\
    			 "pointer type mismatch in container_of()");	\
    	((type *)(__mptr - offsetof(type, member))); })
    
  • list_for_each: 遍历链表(仅读)
  • list_for_each_safe: 遍历链表(有珊链表操作时使用)

使用场景举例

linux-5.9/fs/ext4/super.c 

	printk(KERN_ERR "sb_info orphan list:\n");
	list_for_each(l, &sbi->s_orphan) {
		struct inode *inode = orphan_list_entry(l);
		printk(KERN_ERR "  "
		       "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
		       inode->i_sb->s_id, inode->i_ino, inode,
		       inode->i_mode, inode->i_nlink,
		       NEXT_ORPHAN(inode));
	}

"list_for_each(l, &sbi->s_orphan)" : 等同for循环,将复杂的判断和迭代过程封装, 便于使用

posted @ 2022-06-02 23:16  whilewell  阅读(194)  评论(0编辑  收藏  举报