等待队列
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) )
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;
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的学习也算是一点点慰藉。

浙公网安备 33010602011771号