Linux内核的驱动阻塞机制

    技术2022-07-10  88

    什么叫阻塞,阻塞就是执行操作的时候,如果条件不满足则进程挂起,进入睡眠状态,知道等待的条件满足。阻塞的实现机制,应用程序是无法实现阻塞的,进程阻塞是通过Linux内核的等待队列来实现的。如果像将一个进程阻塞,就将它放入等待队列中,运行条件不满足的时候就将等待队列上的进程睡眠,实现阻塞的目的。实现函数: 0.wait_queue_head_t myQueue; 功能描述:创建一个等待队列头,相当于生成一个空节点 1.init_waitqueue_head(&myQueue); 功能描述:初始化队列头,相当于生成一个空节点 2.DECLARE_WAITQUEUE(name,current); 功能描述:定义一个等待队列任务,相当于生成一个链式队列的节点,但此时并没有放入等待队列中 参数说明:name是一个wait_queue_t类型的等待队列变量,第二个参数是进程,一般用current这个默认的 指针,代表的是用户当前进程。 3.add_wait_queue(myQueue,name); 功能描述:将等待队列任务放入等待队列中,相当于入队操作 参数说明:第一个参数是头结点,第二个参数是要插入的节点 4.remove_wait_queue(myQueue,name); 功能描述:将等待队列任务删除出队列,相当于出队操作 参数说明:第一个参数是头结点,第二个参数是要删除的节点 ----------------------以下是等待队列的睡眠操作接口函数------------------------------ 5.wait_event(myQueue, condition); wait_event_interruptible(myQueue, condition); 功能描述:使等待队列上的进程睡眠,改睡眠不可/可被信号打断 参数说明:第一个参数是等待队列头变量,第二个参数是睡眠条件,如果是假则一直睡眠,为真就退出睡眠 6.wait_event_timeout(myQueue, condition, timeout); wait_event_interruptible_timeout(myQueue, condition,timeout); 功能描述:使等待队列上的进程睡眠一段时间,改睡眠不可/可被信号打断 参数说明:第一个参数是等待队列头变量,第二个参数是睡眠条件,如果是假则睡眠一段时间,为真就退出 睡眠,timeout是睡眠时间 ----------------------以下是等待队列的唤醒操作接口函数------------------------------ 7.wake_up(myQueue); wake_up_interruptible(myQueue); 功能描述:唤醒不可/可被信号打断的等待队列上的睡眠进程 代码实例 实例:将A.c代码中的read函数设置成阻塞模式,只有当B.c函数执行并向内核中写东西的时候才会读取内容,否则一直阻塞。 #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include "linux/cdev.h" #include "linux/kdev_t.h" #include "linux/fs.h" #include "asm/uaccess.h" #include "linux/sched.h" MODULE_LICENSE ("GPL"); struct cdev myuart; int major = 200; int minor = 2; int read_flag = 0; wait_queue_head_t my_queue; 0.设置等待队列头结点 dev_t dev_id; char kernel_buf[64] = {0}; struct file_operations var; wait_queue_t node_var; 2.定义一个等待队列任务,相当于生成一个节点 int myopen(struct inode *pinode, struct file *pfile) { printk(KERN_INFO "myopen run\n"); return 0; } int myclose(struct inode *pinode, struct file *pfile) { printk(KERN_INFO "myclose run\n"); return 0; } ssize_t myread(struct file *pfile, char __user *buf, size_t len, loff_t *off) { int ret = 0; DECLARE_WAITQUEUE(node_var,current); 2.定义一个等待队列任务,相当于生成一个节点 printk(KERN_INFO "myread run\n"); add_wait_queue(&my_queue, &node_var); 3.入队操作 wait_event(my_queue,read_flag != 0); 4.A.c程序执行read函数时,如果read_flag = 0,此 时阻塞,否则继续执行(初值为0,当write函数执行的时候会设置为1) ret = copy_to_user(buf,kernel_buf,len); read_flag = 0; remove_wait_queue(&my_queue, &node_var); 6.remove函数放在这里,执行完以后就删除队列 return len-ret; } ssize_t mywrite(struct file *pfile, const char __user *buf, size_t len, loff_t *off) { int ret; ret = copy_from_user(kernel_buf,buf,len) ; printk(KERN_INFO "mywrite fun run") ; read_flag = 1; //write函数执行,将标志位设置成1, wake_up(&my_queue); 5.叫醒等待队列上的任务,此时可以继续进行读 return 30; } static int __init hello_init (void) { int ret = 0; int ret1; dev_id = MKDEV(major,minor) ; ret = register_chrdev_region(dev_id,1, "uart"); if(ret == -1) // { printk(KERN_INFO "dev_id = %d can't use \n",major); ret1 = alloc_chrdev_region(&dev_id,minor,1, "uart"); if(ret1 == -1) { printk(KERN_INFO "dev_id error \n"); return -1; } else { printk(KERN_INFO "major = %d \n", MAJOR(dev_id)); } } else { printk(KERN_INFO "major = %d can use \n",major); } var.open = myopen; var.release = myclose; var.write = mywrite; var.read = myread; cdev_init(&myuart,&var); cdev_add(&myuart,dev_id,1); init_waitqueue_head(&my_queue); 1.初始化等待队列 return 0; } static void __exit hello_exit (void) { unregister_chrdev_region(dev_id, 1); cdev_del(&myuart); } module_init (hello_init); module_exit (hello_exit); 代码A.c #include "stdio.h" #include "fcntl.h" #include "stdlib.h" #include "unistd.h" int main() { int fd; int len; char buf[64] = {0}; fd = open("./kkk.c",O_RDWR,0777); if(fd == -1) { printf("open error\n"); return -1; } printf("read before\n"); len = read(fd,buf,64); printf("read after: buf = %s,len = %d\n",buf,len); close(fd); return 0; } 代码B.c #include "stdio.h" #include "fcntl.h" #include "stdlib.h" #include "unistd.h" int main() { int fd; int len; char buf[64] = {0}; fd = open("./kkk.c",O_RDWR,0777); if(fd == -1) { printf("open error\n"); return -1; } printf("please input send to kernel data\n"); scanf("%s",buf); len = write(fd,buf,64); while(1); close(fd); return 0; }
    Processed: 0.013, SQL: 9