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 标准链表遍历#includelinux/list.hstructmy_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-data0){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保护的链表遍历#includelinux/rculist.hstructmy_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 哈希链表遍历#includelinux/list.h#defineHASH_SIZE256structhlist_headhash_table[HASH_SIZE];structmy_struct{intkey;structhlist_nodenode;// 哈希链表节点};// 遍历单个哈希桶structmy_struct*entry;structhlist_head*headhash_table[hash_index];hlist_for_each_entry(entry,head,node){if(entry-keytarget_key){// 找到目标break;}}// 安全遍历可删除structmy_struct*entry,*tmp;hlist_for_each_entry_safe(entry,tmp,head,node){if(entry-keytarget_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遍历#includelinux/cpumask.h// 1. 遍历所有可能的CPUintcpu;for_each_possible_cpu(cpu){structper_cpu_data*dataper_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 进程遍历#includelinux/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_nstask_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 内存区域遍历#includelinux/mm.h// 遍历进程的虚拟内存区域structmm_struct*mmcurrent-mm;structvm_area_struct*vma;down_read(mm-mmap_lock);for_each_vma(vma,mm){printk(VMA: 0x%lx-0x%lx flags0x%lx\n,vma-vm_start,vma-vm_end,vma-vm_flags);}up_read(mm-mmap_lock);// 遍历内存节点intnid;for_each_node(nid){structpglist_data*pgdatNODE_DATA(nid);printk(Node %d: start_pfn0x%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 网络设备遍历#includelinux/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*netcurrent-nsproxy-net_ns;for_each_netdev(net,dev){// 处理该命名空间的设备}6.2 PCI设备遍历#includelinux/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 挂载点遍历#includelinux/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 目录项遍历#includelinux/dcache.h// 遍历目录下的所有目录项structdentry*parentdir-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 定时器遍历#includelinux/timer.h// 遍历定时器调试用structtimer_list*timer;structtimer_base*basethis_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__i0;\(__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*dper_cpu_ptr(my_data,cpu);d-counter;// 可能跨CPU缓存行}// 好的遍历本地访问intcpuget_cpu();structdata*dthis_cpu_ptr(my_data);d-counter;put_cpu();十一、常见错误与调试11.1 遍历时删除节点的错误// 错误遍历时删除导致崩溃structmy_struct*entry;list_for_each_entry(entry,head,list){if(entry-data0){list_del(entry-list);// 错误破坏了遍历kfree(entry);}}// 正确使用_safe版本structmy_struct*entry,*tmp;list_for_each_entry_safe(entry,tmp,head,list){if(entry-data0){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;intcount0;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 遍历宏的核心特点类型安全通过宏参数传递类型避免强制转换简洁高效减少重复代码编译器优化好模式统一所有遍历宏遵循相似的使用模式上下文感知有些宏需要特定的锁或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 最佳实践总是使用正确的遍历宏普通/安全/RCU在需要时使用适当的锁保护避免在遍历中长时间阻塞使用prefetch优化长链表遍历注意遍历方向对缓存的影响自定义遍历宏时保持内核风格遍历宏是Linux内核代码中最常见的模式之一理解并正确使用它们对于编写高效、安全的内核代码至关重要。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2471146.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!