abort_exclusive_wait函数功能描述:此函数的作用如下:
1)更改当前进程的状态,将当前进程置于TASK_RUNNING状态。
2)如果第二个参数所代表的等待队列元素在以第一个参数为头指针的等待队列中,则将其从此等待队列中删除。
3)如果第二个参数所代表的元素不在以第一个参数为头指针的等待队列中,并且此等待队列不为空,则唤醒等待队列中的进程。此时唤醒的进程的状态属于此函数的第三个参数mode所定义的范围,并且唤醒进程不是同步的,如果第一个唤醒的进程所在的等待队列中的元素的f lags字段的值等于WQ_FLAG_EXCLUSIVE,则停止唤醒其他进程,否则循环唤醒等待队列中其他的进程。
abort_exclusive_wait文件包含
#include <linux/wait.h>
abort_exclusive_wait函数定义
在内核源码中的位置:linux-3.19.3/kernel/sched/wait.c
函数定义格式:
void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, unsigned int mode, void *key)
abort_exclusive_wait输入参数说明
函数的第一个输入参数是wait_queue_head_t类型的指针,代表等待队列的头指针,其详细信息参考__wake_up( )。
此函数的第二个输入参数是wait_queue_t类型的指针,代表等待队列中的一个元素,定义见文件linux-3.19.3/include/linux/wait.h,如下:
typedef struct __wait_queue wait_queue_t;
此类型等价于__wait_queue, __wait_queue的定义如下:
struct __wait_queue {
unsigned int flags; /*优先级高低标志,1高优先级进程,0低优先级进程*/
void *private; /*私有数据段,指向某一进程的进程描述符*/
wait_queue_func_t func; /*进程唤醒函数指针*/
struct list_head task_list; /*等待队列链表元素*/
};
其中struct list_head的定义如下:
struct list_head {
struct list_head *next, *prev;
};
字段next和prev分别指向等待队列链表的下一个和前一个元素。
函数的第三个参数是无符号的整型变量,代表能够被唤醒的进程所处的状态,即只有处于此状态的进程才能够被唤醒,其详细信息参考__wake_up( )。
函数的第四个参数是一个void型的指针变量,代表唤醒进程时执行的函数,一般传递NULL。
abort_exclusive_wait返回参数说明
函数的返回值类型是void,即不返回任何类型的值。
abort_exclusive_wait实例解析
编写测试文件:abort_exclusive_wait.c
头文件引用:
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/list.h>
#include <linux/kthread.h>
MODULE_LICENSE("GPL");
子进程处理函数定义:
int my_function(void * argc)
{
printk("in the kernel thread function! \n");
printk("the current pid is:%d\n", current->pid); //显示当前进程的进程号
printk("out the kernel thread function\n");
return 0;
}
模块加载函数定义:
static int __init abort_exclusive_wait_init(void)
{
/*局部变量定义*/
struct task_struct *result, *result1, *result2;
char namefrm[] = "abort_exclusive_wait.c";
char namefrm1[] = "abort_exclusive_wait1.c";
char namefrm2[] = "abort_exclusive_wait2.c";
int wait_queue_num=0;
wait_queue_head_t head;
wait_queue_t data, data1, data2, *curr, *next;
printk("into abort_exclusive_wait_init.\n");
/*创建3个新进程*/
result=kthread_create_on_node(my_function, NULL, -1, namefrm);
result1=kthread_create_on_node(my_function, NULL, -1, namefrm1);
result2=kthread_create_on_node(my_function, NULL, -1, namefrm2);
wake_up_process(result); //唤醒新创建的进程
wake_up_process(result1);
wake_up_process(result2);
init_waitqueue_head(&head); //初始化等待队列的头指针
init_waitqueue_entry(&data, result); //用新进程初始化等待队列中的一个元素
data.task_list.next=&data.task_list; // 初始化等待队列链表的next值
prepare_to_wait(&head, &data,130); //将新进程加入等待队列,并改变当期进程的状态
init_waitqueue_entry(&data1, result1); //将新进程加入等待队列中的一个元素
data1.task_list.next=&data1.task_list; //初始化等待队列链表的next值
prepare_to_wait_exclusive(&head, &data1,2); // 将新进程加入等待队列,并改变当期进程的状态
init_waitqueue_entry(&data2, result2); //将新进程加入等待队列中的一个元素
data2.task_list.next=&data2.task_list; //初始化等待队列链表的next值
prepare_to_wait_exclusive(&head, &data2,1); // 将新进程加入等待队列,并改变当期进程的状态
list_for_each_entry_safe(curr, next, &(head.task_list), task_list)
//循环显示等待队列中的进程的PID值及状态信息
{
wait_queue_num++; //累加当前等待队列中的进程数
printk("the pid value of the current data of the waitqueue is:%d\n", ((struct task_struct *)(curr->private))->pid); //显示等待队列中当前进程的PID值
printk("the state of the current data of the waitqueue is:%ld\n", ((struct task_struct *)(curr->private))->state); //显示等待队列中当前进程的状态
}
printk("the value of the wait_queue_num is :%d\n", wait_queue_num);
// 显示当前等待队列中的等待进程数
printk("the state of the current thread is:%ld\n", current->state);
// 显示当前进程的状态
/*
((struct task_struct *)(data2.private))->state=130; //更改进程的状态
finish_wait(&head, &data1); //将进程从等待队列中删除
wait_queue_num=0;
list_for_each_entry_safe(curr, next, &(head.task_list), task_list)
// 显示函数调用之后等待队列中的进程的PID值及状态信息
{
wait_queue_num++; //累加当前等待队列中的进程数
printk("the pid value of the current data of the waitqueue is:%d\n", ((struct task_struct *)(curr->private))->pid); //显示等待队列中当前进程的PID值
printk("the state of the current data of the waitqueue is:%ld\n", ((struct task_struct *)(curr->private))->state); //显示等待队列中当前进程的状态
}
printk("the value of the wait_queue_num is :%d\n", wait_queue_num);
// 显示函数调用之后等待队列中的进程数
*/
abort_exclusive_wait(&head, &data1, TASK_NORMAL, NULL);
// 改变当前进程的状态,删除等待队列中的进程或唤醒等待队列中的进程
printk("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)
// 显示函数调用之后等待队列中的进程的PID值及状态信息
{
wait_queue_num++; // 累加当前等待队列中的进程数
printk("the pid value of the current data of the waitqueue is:%d\n", ((struct task_struct *)(curr->private))->pid); //显示等待队列中当前进程的PID值
printk("the state of the current data of the waitqueue is:%ld\n", ((struct task_struct *)(curr->private))->state); //显示等待队列中当前进程的状态
}
printk("the value of the wait_queue_num is :%d\n", wait_queue_num);
// 显示函数调用之后等待队列中的进程数
/*显示函数kernel_thread( )的返回结果*/
printk("the pid of result is :%d\n", result->pid);
printk("the pid of the result1 is :%d\n", result1->pid);
printk("the pid of the result2 is :%d\n", result2->pid);
printk("the current pid is:%d\n", current->pid); //显示当前进程的PID值
printk("out abort_exclusive_wait_init.\n");
return 0;
}
模块退出函数定义:
static void __exit abort_exclusive_wait_exit(void)
{
printk("Goodbye abort_exclusive_wait\n");
}
模块加载、退出函数调用:
module_init(abort_exclusive_wait_init);
module_exit(abort_exclusive_wait_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod abort_exclusive_wait.ko插入内核模块,然后输入命令dmesg -c查看模块插入结果,会出现如图A
所示的结果。
去掉模块加载函数中对部分语句的注释,重新编译模块,加载模块,然后输入命令dmesg -c,会出现如图B
所示的结果。
结果分析:
图A
的运行程序设计用于测试函数能够改变当前进程的状态及将进程从等待队列中删除,图B
的运行程序设计用于测试函数能够唤醒等待队列中的进程。
由图A
可以看出在函数abort_exclusive_wait( )执行前,等待队列中有3个元素,当前进程的状态值是1,即处于可中断的等待状态,此状态的设定是通过最后一次函数prepare_to_wait_exclusive( )的调用;函数abort_exclusive_wait( )执行后,等待队列中的元素个数变为2,并且当前进程的状态变为0,即处于TASK_RUNNING状态,说明函数能够完成函数功能说明部分提到的前两个作用。
由图B
可以看出函数abort_exclusive_wait( )调用之前,等待队列中的元素个数为2,函数调用之后等待队列中的元素个数还是2,说明函数没有实现函数功能说明部分的第二个作用,但函数调用之后进程号是20485的进程的状态值发生了改变,由130变为0,说明此进程被成功唤醒。
进程状态说明:
对于进程能够处于的状态,在__wake_up( )分析文档的进程状态说明部分有详细的说明。