等待队列

add_wait_queue_exclusive();

add_wait_queue();

插入队列的位置不同:一个从尾,一个在头。前者插入元素的优先级较高。

#include <linux/module.h>
#include <linux/sched.h>
#include <linux/list.h>

MODULE_LICENSE("GPL");

int my_function(void * argc)
{
	printk("<0>in the kernel thread function!\n");	
	printk("<0>the current pid is:%d\n",current->pid);
	printk("<0>out the kernel thread function\n");
	return 0;
}

static int __init my_init(void)
{	
	int result, result1, result2;	
	int wait_queue_num = 0;
	wait_queue_head_t head;
	wait_queue_t data, data1, data2, *curr, *next;	

	printk("<0>into my_init.\n");
	
				
	result =kernel_thread(my_function,NULL,CLONE_KERNEL);
	result1=kernel_thread(my_function,NULL,CLONE_KERNEL);
	result2=kernel_thread(my_function,NULL,CLONE_KERNEL);


	struct pid * kpid = find_get_pid(result);
	struct task_struct * task = pid_task(kpid,PIDTYPE_PID);

	struct pid * kpid1 = find_get_pid(result1);
	struct task_struct * task1 = pid_task(kpid1,PIDTYPE_PID);

	struct pid * kpid2 = find_get_pid(result2);
	struct task_struct * task2 = pid_task(kpid2,PIDTYPE_PID);

	init_waitqueue_head(&head);


	init_waitqueue_entry(&data, task);
	init_waitqueue_entry(&data1,task1);
	init_waitqueue_entry(&data2,task2);


	add_wait_queue_exclusive(&head,&data1);
	add_wait_queue_exclusive(&head,&data2);
	add_wait_queue(&head,&data);


	list_for_each_entry_safe(curr, next, &(head.task_list), task_list) 
	{
		wait_queue_num++;
		
		printk("<0>the flag value of the current data of the waitqueue is:%d\n",curr->flags);	
			
		printk("<0>the pid value of the current data of the waitqueue is:%d\n", \
                                                        ((struct task_struct *)(curr->private))->pid);
	}

	printk("<0>the value of the wait_queue_num is :%d\n",wait_queue_num);
	
	printk("<0>the result  of the kernel_thread is :%d\n", result); 
	printk("<0>the result1 of the kernel_thread is :%d\n",result1);
	printk("<0>the result2 of the kernel_thread is :%d\n",result2);
	printk("<0>the current pid is:%d\n",current->pid);
	printk("<0>out my_init.\n");
	return 0;
}

static void __exit my_exit(void)
{	
        printk("<0>Goodbye mytest\n");	
}

module_init(my_init);
module_exit(my_exit);

又是一位内核界的明星,通过内核链表遍历一大串结构体的典型。

#define list_for_each_entry_safe(pos, n, head, member) \
for ( pos = list_entry((head)->next, typeof(*pos), member), \
n
= list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos
= n, n = list_entry(n->member.next, typeof(*n), member) )

它都遍历了哪些东西,看看下面的结构体,也就一目了然了。

-- include/linux/wait.h --

struct __wait_queue_head {
spinlock_t
lock;
struct list_head task_list;
};
typedef
struct __wait_queue_head wait_queue_head_t;


struct __wait_queue {
unsigned
int flags;
void*private;
wait_queue_func_t func;
struct list_head task_list;
};
typedef
struct __wait_queue wait_queue_t;

以下是运行的结果,通过遍历队列打印出的pid可以看出插入队列的方式。

[103891.133838] into my_init.
[103891.133875] the result  of the kernel_thread is :22093
[103891.133878] the result1 of the kernel_thread is :22094
[103891.133880] the result2 of the kernel_thread is :22095
[103891.133883] the current pid is:22092
[103891.133886] the flag value of the current data of the waitqueue is:0
[103891.133889] the pid value of the current data of the waitqueue is:22094
[103891.133891] the flag value of the current data of the waitqueue is:0
[103891.133894] the pid value of the current data of the waitqueue is:22093
[103891.133897] the flag value of the current data of the waitqueue is:1
[103891.133900] the pid value of the current data of the waitqueue is:22095
[103891.133903] the value of the wait_queue_num is :3
[103891.133905] out my_init.
[103891.134519] in the kernel thread function!
[103891.134522] the current pid is:22094
[103891.134525] out the kernel thread function
[103891.134621] in the kernel thread function!
[103891.134623] the current pid is:22095
[103891.134625] out the kernel thread function
[103891.134679] in the kernel thread function!
[103891.134681] the current pid is:22093
[103891.134683] out the kernel thread function

  

------------------------------------------------------------------------------

现在便有了一个真真切切的队列,作为进程调度的东西,离不开休眠、唤醒、休眠、唤醒……智商为正的大伙都能看出来:这玩意是成对儿的嘛。函数的设计也确实如此。

int my_function(void * argc)
{
	printk("<0>the state of the real_parent is :%ld\n",current->real_parent->state);
	__wake_up(&head,TASK_ALL,0,NULL);   //唤醒
	printk("<0>the state of the real_parent after __wake_up is :%ld\n",current->real_parent->state);
	printk("<0>out the kernel thread function\n");
	return 0;
}

static int __init my_init(void)
{
	int result=0;
	long left_time=0;
	wait_queue_t data;

	printk("<0>into my_init.\n");
	result=kernel_thread(my_function, NULL, CLONE_KERNEL);
             init_waitqueue_head(&head);
	init_waitqueue_entry(&data, current); 
	add_wait_queue(&head, &data);

	left_time=sleep_on_timeout(&head, 100);     //休眠
	printk("<0>the return result of the sleep_on_timeout is:%ld\n", left_time); 

	printk("<0>out my_init.\n");
	return 0;
}

主进程生了个子进程后,将自己放入队列里,睡午觉去了。

子进程运行过程中唤醒老爸,于是乎,闹钟还未响却被孩子吵醒,如此看来,带孩子的男人确实不容易a。

  

当然,从这个sleep_on_timeout的参数也能看出,这一睡就睡了整个一个队列。我想单独控制队列个别元素该怎么办?

static int __init my_init(void)
{	
	int result, result1;	
	int  wait_queue_num=0;
	wait_queue_head_t head;
	wait_queue_t data, data2, *curr, *next;	

	printk("<0>into my_init.\n");			
			
	result1=kernel_thread(my_function,NULL,CLONE_KERNEL); 
	result2=kernel_thread(my_function,NULL,CLONE_KERNEL);

	struct pid * kpid1 = find_get_pid(result);
	struct task_struct * task1 = pid_task(kpid1,PIDTYPE_PID);
	struct pid * kpid2 = find_get_pid(result1);
	struct task_struct * task2 = pid_task(kpid2,PIDTYPE_PID);

	init_waitqueue_head(&head);

	init_waitqueue_entry(&data1, task1);
	data.task_list.next=&data1.task_list;    //这里注意了,要使用prepare_to_wait,这里就必须这样初始化即将插入的队列元素
	printk("<0>the state of the current thread is:%ld\n",current->state);
	prepare_to_wait(&head, &data1, 130);  //插入队列后,同时也将当下的进程的状态改为了130
	printk("<0>the state of the current thread is:%ld\n",current->state);

	init_waitqueue_entry(&data2, task2);
	data2.task_list.next=&data2.task_list;
	prepare_to_wait_exclusive(&head, &data2, 2);    //又插了一个
	printk("<0>the state of the current thread is:%ld\n",current->state);
	
	list_for_each_entry_safe(curr, next, &(head.task_list), task_list) 
	{
		wait_queue_num++;
	}		
	printk("<0>the value of the wait_queue_num is :%d\n",wait_queue_num);    //打印后发现,队列里确实有两个元素
	finish_wait(&head,&data2);
	printk("<0>the state of the current thread is:%ld\n",current->state); 

	wait_queue_num=0;
	list_for_each_entry_safe(curr, next, &(head.task_list), task_list) 
	{
		wait_queue_num++; 
	}
	printk("<0>the value of the wait_queue_num is :%d\n",wait_queue_num);        //删掉一个后,当然就剩下一个咯

	printk("<0>out my_init.\n");
	return 0;
}

首先先解释下什么是130,当然就是128+2啦,对应的第二位和第八位。也就是说内核用一位代表了一种进程状态。在这里,

2:    TASK_INTERRUPTIBLE         128: TASK_WAKEKILL

2.6.32的版本,设计了九种状态,咋是九种?不是只有八位不?——@##% ,不是还有个零么!

  

当然,内核api里还有许多函数会对队列进行更精细的操作,比如 wake_up_process,sleep_on_interrupt_timeout 什么的,看多了,也就发现其中有着相当的规律,尤其是函数名字的命名方式,这样,对内核api的学习也算是一点点慰藉。

posted @ 2011-06-24 20:07  郝壹贰叁  阅读(604)  评论(0编辑  收藏  举报