关于内核数据结构struc list_head的用法。 在list.h头文件中,定义了struct list_head这个双向链表结构,它是怎样的呢? Struct list_head { struct list_head *prev; struct list_head *next; } 粗略一看,起始很普通,就是定义了两个指针而已,但是却相当有用。 我们平时定义双链表的数据结构的时候,是这样的: struct list_node { int data; struct list_node *prev; struct list_node *next; } 这样我们把数据嵌入到链表节点中:如图而内核的数据结构却是将链表的节点嵌入到数据中 struct list_node { int data; struct list_head list; }而我们对链表的操作(或者对数据的操作)就是通过对每个list_head结构来访问的。 但是,碰到一个问题,因为所有的链表操作涉及的指针都是指向list_head结构的,而不是包含的数据结构(即外面的结构,这里就是list_node),那么我们怎样从list_head的地址转而得到list_node的地址呢,这是问题的关键。 在list.h中,定义了一个宏: list_entry (ptr,type,member) 其中,ptr是指向list_head类型的链表指针 type是包含list_head结构的结构类型,这里位struct list_node member为外面结构中list_head类型的名称。 比如在上面的struct list_node结构中,定义一个struct list_head *p 使其执行这个双链表。 那么这里的ptr即p type即struct list_node member即list 这个宏返回的就是指向某个外面结构struct list_node的指针, 即我们用这个宏可以达到:用结构里面的成员变量的地址(struct list_head类型)来求出结构的地址(struct list_node类型)。下面我们举个例子: 遍历所有的进程,通过task_struct结构。 我们知道,每个task_struct结构代表一个进程,且这个结构中含有 struct list_head 结构,它的名字叫做tasks。 这样,所有的task_struct结构就通过各自的tasks而构成了双向链表。#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> static void taskprint(void) { struct task_struct *p=NULL; struct list_head *plist=NULL; plist=(¤t->tasks)->prev;//使struct list_head结构指向双向链表中某个结构的struct list_head类型的变量,这里即tasks. int count=0; printk("pid\tcommd\n"); for(;plist!=(¤t->tasks);plist=plist->prev)//用plist来遍历,让它循环整个双向链表 { p=list_entry(plist,struct task_struct,tasks); printk("pid=%d\t,commd=%s\n",p->pid,p->comm); count++; } printk("pid=%d\t,commd=%s\n",p->pid,p->comm); printk("total task is %d\n",count); } static int taskprintinit(void) { printk("task print is working....\n"); taskprint(); return 0; } static void taskprintexit(void) { printk("task print is leaving...\n"); } module_init(taskprintinit); module_exit(taskprintexit);
注意: 1,current是当前进程的指针是指针! 2,->优先级高于&,故 ¤t->taks和 &(current->tasks)是一样的效果 3,在struct_task中,tasks是struct list_head结构而不是结构指针。 所以,这两句:plist=(¤t->tasks)->prev;意思是取前个结构的tasks域。(current前面要加&,因为list_head不是指针)。输出结果: 完