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