现在的位置: 首页 > 综合 > 正文

关于内核数据结构struc list_head的用法。

2014年10月21日 ⁄ 综合 ⁄ 共 1923字 ⁄ 字号 评论关闭

关于内核数据结构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
使其执行这个双链表。
那么这里的ptrp	
			typestruct list_node
			memberlist
这个宏返回的就是指向某个外面结构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);
注意:

1current是当前进程的指针是指针!
2->优先级高于&,故 &current->taks&current->tasks)是一样的效果
3,在struct_task中,tasksstruct list_head结构而不是结构指针。
 所以,这两句:plist=(&current->tasks)->prev;意思是取前个结构的tasks域。(current前面要加&,因为list_head不是指针)。

输出结果:

抱歉!评论已关闭.