news 2026/5/26 15:05:54

Linux 内核遍历宏介绍

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 内核遍历宏介绍

Linux内核中的遍历宏全面详解

Linux内核中大量使用遍历宏(Iteration Macros)来简化数据结构的遍历操作。这些宏提供了类型安全、简洁且高效的遍历方式,是内核编程的核心范式之一。


一、遍历宏的分类

1.1 按功能分类

Linux内核遍历宏 ├── 链表遍历宏 │ ├── list_for_each_entry // 遍历标准链表 │ ├── hlist_for_each_entry // 遍历哈希链表 │ ├── list_for_each_entry_safe // 安全遍历(可删除) │ └── list_for_each_entry_rcu // RCU保护遍历 │ ├── CPU遍历宏 │ ├── for_each_possible_cpu // 所有可能的CPU │ ├── for_each_online_cpu // 在线CPU │ ├── for_each_present_cpu // 存在的CPU │ └── for_each_cpu_and // CPU掩码交集 │ ├── 进程遍历宏 │ ├── for_each_process // 遍历所有进程 │ ├── for_each_thread // 遍历进程的线程 │ └── for_each_task_pid // 遍历特定PID的进程 │ ├── 内存遍历宏 │ ├── for_each_sg // 遍历scatter-gather列表 │ ├── for_each_vma // 遍历虚拟内存区域 │ └── for_each_zone // 遍历内存区域 │ ├── 文件系统遍历宏 │ ├── for_each_mount_point // 遍历挂载点 │ ├── for_each_dentry // 遍历目录项 │ └── for_each_inode // 遍历inode │ ├── 设备遍历宏 │ ├── for_each_netdev // 遍历网络设备 │ ├── for_each_pci_dev // 遍历PCI设备 │ └── for_each_irq // 遍历中断 │ └── 定时器遍历宏 ├── for_each_timer // 遍历定时器 └── for_each_hrtimer // 遍历高精度定时器

二、链表遍历宏(最常用)

2.1 标准链表遍历

#include<linux/list.h>structmy_struct{intdata;structlist_headlist;// 链表节点};structlist_headhead;INIT_LIST_HEAD(&head);// 1. 基本遍历(不可删除节点)structmy_struct*entry;list_for_each_entry(entry,&head,list){printk("data: %d\n",entry->data);}// 2. 安全遍历(可删除当前节点)structmy_struct*entry,*tmp;list_for_each_entry_safe(entry,tmp,&head,list){if(entry->data==0){list_del(&entry->list);kfree(entry);}}// 3. 反向遍历list_for_each_entry_reverse(entry,&head,list){printk("data: %d\n",entry->data);}// 4. 从指定位置开始遍历structmy_struct*entry;list_for_each_entry_from(entry,&head,list){// 从entry开始继续遍历}// 5. 带锁的安全遍历spin_lock(&lock);list_for_each_entry(entry,&head,list){// 在锁保护下遍历}spin_unlock(&lock);

2.2 RCU保护的链表遍历

#include<linux/rculist.h>structmy_struct{intdata;structlist_headlist;structrcu_headrcu;};structlist_headhead;// RCU读锁保护rcu_read_lock();structmy_struct*entry;list_for_each_entry_rcu(entry,&head,list){printk("data: %d\n",entry->data);}rcu_read_unlock();// RCU安全删除list_del_rcu(&entry->list);call_rcu(&entry->rcu,my_struct_free);

2.3 哈希链表遍历

#include<linux/list.h>#defineHASH_SIZE256structhlist_headhash_table[HASH_SIZE];structmy_struct{intkey;structhlist_nodenode;// 哈希链表节点};// 遍历单个哈希桶structmy_struct*entry;structhlist_head*head=&hash_table[hash_index];hlist_for_each_entry(entry,head,node){if(entry->key==target_key){// 找到目标break;}}// 安全遍历(可删除)structmy_struct*entry,*tmp;hlist_for_each_entry_safe(entry,tmp,head,node){if(entry->key==target_key){hlist_del(&entry->node);kfree(entry);}}// RCU保护的哈希链表遍历rcu_read_lock();hlist_for_each_entry_rcu(entry,head,node){printk("key: %d\n",entry->key);}rcu_read_unlock();

2.4 链表遍历宏详解

宏名称用途是否可删除节点线程安全
list_for_each_entry标准正向遍历需外部锁
list_for_each_entry_safe安全遍历(支持删除)需外部锁
list_for_each_entry_reverse反向遍历需外部锁
list_for_each_entry_rcuRCU保护遍历RCU保护
list_for_each_entry_safe_rcuRCU安全遍历RCU保护
hlist_for_each_entry哈希链表遍历需外部锁
hlist_for_each_entry_safe哈希链表安全遍历需外部锁

三、CPU遍历宏

3.1 基本CPU遍历

#include<linux/cpumask.h>// 1. 遍历所有可能的CPUintcpu;for_each_possible_cpu(cpu){structper_cpu_data*data=per_cpu_ptr(&my_data,cpu);init_percpu_data(data);}// 2. 遍历在线CPUfor_each_online_cpu(cpu){smp_call_function_single(cpu,work_func,NULL,1);}// 3. 遍历存在的CPUfor_each_present_cpu(cpu){init_cpu_hardware(cpu);}// 4. 遍历活跃CPU(用于调度)for_each_active_cpu(cpu){assign_task_to_cpu(cpu);}// 5. 遍历CPU掩码的交集for_each_cpu_and(cpu,cpu_online_mask,cpu_active_mask){// 处理既在线又活跃的CPU}

3.2 CPU遍历宏详解

// 实现原理#definefor_each_possible_cpu(cpu)\for_each_cpu((cpu),cpu_possible_mask)#definefor_each_cpu(cpu,mask)\for((cpu)=-1;\(cpu)=cpumask_next((cpu),(mask)),\(cpu)<nr_cpu_ids;)// 实际使用示例voidshow_cpu_status(void){intcpu;charbuf[128];// 打印在线CPU列表cpumap_print_to_pagebuf(true,buf,cpu_online_mask);pr_info("Online CPUs: %s\n",buf);// 为每个在线CPU执行操作for_each_online_cpu(cpu){pr_info("CPU%d: status=%s\n",cpu,cpu_online(cpu)?"online":"offline");}}

四、进程遍历宏

4.1 进程遍历

#include<linux/sched.h>// 1. 遍历所有进程structtask_struct*p;for_each_process(p){printk("Process: %s (PID: %d)\n",p->comm,p->pid);}// 2. 遍历进程的所有线程structtask_struct*thread;for_each_thread(p,thread){printk("Thread: %s (TID: %d)\n",thread->comm,thread->pid);}// 3. 遍历特定PID命名空间的进程structpid_namespace*pid_ns=task_active_pid_ns(current);structtask_struct*p;for_each_process_in_pid_ns(pid_ns,p){// 处理该命名空间的进程}// 4. 安全遍历(防止进程退出)structtask_struct*p,*tmp;read_lock(&tasklist_lock);for_each_process_safe(p,tmp){// 在锁保护下遍历,可以安全地处理get_task_struct(p);// 增加引用计数// ... 处理进程 ...put_task_struct(p);}read_unlock(&tasklist_lock);

4.2 进程遍历注意事项

// 错误:遍历时可能导致进程退出for_each_process(p){// 进程p可能在这之后退出printk("%s\n",p->comm);// 危险!}// 正确:使用RCU保护rcu_read_lock();for_each_process(p){// RCU保护下,进程不会退出printk("%s\n",p->comm);}rcu_read_unlock();// 正确:使用引用计数structtask_struct*p;for_each_process(p){get_task_struct(p);// 防止进程退出// 安全使用pput_task_struct(p);}

五、内存区域遍历宏

5.1 内存区域遍历

#include<linux/mm.h>// 遍历进程的虚拟内存区域structmm_struct*mm=current->mm;structvm_area_struct*vma;down_read(&mm->mmap_lock);for_each_vma(vma,mm){printk("VMA: 0x%lx-0x%lx flags=0x%lx\n",vma->vm_start,vma->vm_end,vma->vm_flags);}up_read(&mm->mmap_lock);// 遍历内存节点intnid;for_each_node(nid){structpglist_data*pgdat=NODE_DATA(nid);printk("Node %d: start_pfn=0x%lx\n",nid,pgdat->node_start_pfn);}// 遍历内存区域structzone*zone;for_each_zone(zone){printk("Zone: %s, pages=%lu\n",zone->name,zone->managed_pages);}

六、设备遍历宏

6.1 网络设备遍历

#include<linux/netdevice.h>// 遍历所有网络设备structnet_device*dev;for_each_netdev(&init_net,dev){printk("Device: %s, state=%d\n",dev->name,dev->state);}// 安全遍历(可删除设备)structnet_device*dev,*tmp;for_each_netdev_safe(&init_net,dev,tmp){if(should_remove(dev)){unregister_netdev(dev);}}// 遍历特定命名空间的网络设备structnet*net=current->nsproxy->net_ns;for_each_netdev(net,dev){// 处理该命名空间的设备}

6.2 PCI设备遍历

#include<linux/pci.h>// 遍历所有PCI设备structpci_dev*pdev;for_each_pci_dev(pdev){printk("PCI: %04x:%04x\n",pdev->vendor,pdev->device);}// 遍历特定总线的设备structpci_bus*bus;for_each_pci_bus(bus){printk("PCI Bus: %02x\n",bus->number);}

七、文件系统遍历宏

7.1 挂载点遍历

#include<linux/mount.h>// 遍历所有挂载点structmount*mnt;for_each_mount(mnt){printk("Mount: %s on %s\n",mnt->mnt_devname,mnt->mnt.mnt_root->d_name.name);}

7.2 目录项遍历

#include<linux/dcache.h>// 遍历目录下的所有目录项structdentry*parent=dir->dentry;structdentry*dentry;spin_lock(&parent->d_lock);list_for_each_entry(dentry,&parent->d_subdirs,d_child){printk("Dentry: %s\n",dentry->d_name.name);}spin_unlock(&parent->d_lock);

八、定时器遍历宏

8.1 定时器遍历

#include<linux/timer.h>// 遍历定时器(调试用)structtimer_list*timer;structtimer_base*base=this_cpu_ptr(&timer_bases[BASE_STD]);spin_lock(&base->lock);for_each_timer(timer,base){printk("Timer: expires=%lu, function=%pS\n",timer->expires,timer->function);}spin_unlock(&base->lock);

九、自定义遍历宏

9.1 创建自定义遍历宏

// 1. 定义数据结构structmy_array{int*items;intsize;};// 2. 创建遍历宏#definefor_each_my_array(item,array)\for(int__i=0;\(__i<(array)->size)&&((item)=&(array)->items[__i],1);\__i++)// 3. 使用structmy_arrayarr;int*item;for_each_my_array(item,&arr){printk("Item: %d\n",*item);}// 4. 带索引的遍历宏#definefor_each_my_array_idx(item,idx,array)\for((idx)=0;\((idx)<(array)->size)&&((item)=&(array)->items[idx],1);\(idx)++)// 使用intidx;for_each_my_array_idx(item,idx,&arr){printk("arr[%d] = %d\n",idx,*item);}

9.2 复杂数据结构的遍历宏

// 树形结构遍历宏structtree_node{structtree_node*parent;structlist_headchildren;intdata;};#definefor_each_tree_child(child,parent)\list_for_each_entry(child,&(parent)->children,node)#definefor_each_tree_descendant(node,root)\for((node)=(root);(node);(node)=next_tree_node(node))// 使用structtree_node*root;structtree_node*child;structtree_node*desc;for_each_tree_child(child,root){printk("Child: %d\n",child->data);}for_each_tree_descendant(desc,root){printk("Descendant: %d\n",desc->data);}

十、遍历宏的性能优化

10.1 预取优化

// 使用prefetch预取下一个元素structmy_struct*entry;list_for_each_entry(entry,&head,list){prefetch(entry->list.next);// 预取下一个节点process_entry(entry);}

10.2 缓存友好遍历

// 不好的遍历(跳跃访问)for_each_possible_cpu(cpu){structdata*d=per_cpu_ptr(&my_data,cpu);d->counter++;// 可能跨CPU缓存行}// 好的遍历(本地访问)intcpu=get_cpu();structdata*d=this_cpu_ptr(&my_data);d->counter++;put_cpu();

十一、常见错误与调试

11.1 遍历时删除节点的错误

// 错误:遍历时删除导致崩溃structmy_struct*entry;list_for_each_entry(entry,&head,list){if(entry->data==0){list_del(&entry->list);// 错误!破坏了遍历kfree(entry);}}// 正确:使用_safe版本structmy_struct*entry,*tmp;list_for_each_entry_safe(entry,tmp,&head,list){if(entry->data==0){list_del(&entry->list);kfree(entry);}}

11.2 遍历时缺少锁保护

// 错误:无锁遍历并发修改的链表list_for_each_entry(entry,&head,list){// 其他CPU可能正在修改链表process_entry(entry);}// 正确:使用锁保护spin_lock(&list_lock);list_for_each_entry(entry,&head,list){process_entry(entry);}spin_unlock(&list_lock);

11.3 调试技巧

// 打印链表信息voiddump_list(structlist_head*head){structmy_struct*entry;intcount=0;pr_info("List dump:\n");list_for_each_entry(entry,head,list){pr_info(" [%d] data=%d, next=%p, prev=%p\n",count++,entry->data,entry->list.next,entry->list.prev);}pr_info("Total: %d entries\n",count);}// 使用lockdep检查锁lockdep_assert_held(&list_lock);list_for_each_entry(entry,&head,list){// 确保锁已持有}

十二、总结

12.1 遍历宏的核心特点

  1. 类型安全:通过宏参数传递类型,避免强制转换
  2. 简洁高效:减少重复代码,编译器优化好
  3. 模式统一:所有遍历宏遵循相似的使用模式
  4. 上下文感知:有些宏需要特定的锁或RCU保护

12.2 选择指南

场景推荐遍历宏原因
标准链表操作list_for_each_entry最常用,性能好
需要删除节点list_for_each_entry_safe保存了next指针
RCU保护读取list_for_each_entry_rcuRCU语义正确
哈希表遍历hlist_for_each_entry适合哈希桶
CPU相关操作for_each_online_cpu只处理在线CPU
进程遍历RCU保护的遍历进程可能退出
网络设备for_each_netdev网络子系统标准
内存区域RCU或锁保护VMA可能改变

12.3 最佳实践

  1. 总是使用正确的遍历宏(普通/安全/RCU)
  2. 在需要时使用适当的锁保护
  3. 避免在遍历中长时间阻塞
  4. 使用prefetch优化长链表遍历
  5. 注意遍历方向对缓存的影响
  6. 自定义遍历宏时保持内核风格

遍历宏是Linux内核代码中最常见的模式之一,理解并正确使用它们对于编写高效、安全的内核代码至关重要。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/4 17:20:39

Linux 调度器中的容量感知:cpu_capacity 的计算与应用

一、简介随着移动设备、嵌入式系统和数据中心对能效比的要求日益提高&#xff0c;异构多处理&#xff08;HMP, Heterogeneous Multi-Processing&#xff09; 架构已成为主流。ARM的big.LITTLE、Intel的Hybrid Architecture&#xff08;Alder Lake及后续&#xff09;、Apple的M系…

作者头像 李华
网站建设 2026/4/1 6:56:41

从权限请求到地图展示:实战解析navigator.geolocation API的全链路应用

1. 从权限请求到地图展示的全链路设计 当用户第一次访问需要获取地理位置的网页时&#xff0c;浏览器会弹出一个权限请求对话框。这个看似简单的弹窗&#xff0c;实际上藏着不少设计门道。我见过太多开发者直接调用API却忽略了用户体验&#xff0c;结果导致用户拒绝率居高不下。…

作者头像 李华
网站建设 2026/4/1 6:56:35

Python 并发编程高级技巧详解:从原理到实践

Python 并发编程高级技巧详解&#xff1a;从原理到实践 1. 背景与动机 在现代应用开发中&#xff0c;并发编程已经成为提高程序性能和响应速度的重要手段。Python 作为一种广泛使用的编程语言&#xff0c;提供了多种并发编程模型&#xff0c;包括多线程、多进程和异步 I/O。 随…

作者头像 李华
网站建设 2026/4/2 20:14:49

MAI-UI-8B入门:Node.js环境配置与自动化测试

MAI-UI-8B入门&#xff1a;Node.js环境配置与自动化测试 1. 开篇&#xff1a;为什么选择MAI-UI-8B进行自动化测试 如果你正在寻找一个能够真正理解图形界面、像真人一样操作应用的自动化测试方案&#xff0c;MAI-UI-8B绝对值得关注。这个由阿里通义实验室开源的GUI智能体模型…

作者头像 李华
网站建设 2026/4/4 19:22:25

SQL注入(新闻靶场练习)

一&#xff0c;目标数据库名字的获取 本地新闻靶场127.0.0.1/wz/url.php?date2026331http://127.0.0.1/wz/url.php?date2026331数据库里新闻表的表名一般都是news 由此得出数据库里的语句SELECT * FROMnewsWHERE datestr2026331 再通过时间(date)注入语句 127.0.0.1/wz/u…

作者头像 李华
网站建设 2026/4/1 6:50:34

游戏存档备份终极指南:用Ludusavi守护你的游戏记忆

游戏存档备份终极指南&#xff1a;用Ludusavi守护你的游戏记忆 【免费下载链接】ludusavi Backup tool for PC game saves 项目地址: https://gitcode.com/gh_mirrors/lu/ludusavi 你是否曾因电脑故障、系统重装或设备更换而丢失珍贵的游戏存档&#xff1f;数百小时的游…

作者头像 李华