简介
当您编写Linux驱动程序,模块或内核程序时,某些进程应等待或休眠某些事件。在Linux中,有几种处理睡眠和唤醒的方法,每种方法都适合不同的需求。Waitqueue也是处理这种情况的方法之一。
每当进程必须等待事件(例如数据到达或进程终止)时,它就应该进入睡眠状态。睡眠会导致进程挂起执行,从而释放处理器以供其他用途。一段时间后,该过程将被唤醒,并在我们等待的事件到达时继续其工作。
等待队列是内核提供的用于实现等待的机制。顾名思义,waitqueue是等待事件的进程列表。换句话说,当特定条件为真时,使用等待队列来等待有人将您唤醒。必须小心使用它们,以确保没有比赛状况。
使用步骤
动态
wait_queue_head_t wq; init_waitqueue_head (&wq);
<a name="e7tIz"></a>
### 睡眠API
```c
wait_event(wq_head, condition)
wait_event_timeout(wq, condition, timeout);
wait_event_cmd(wq, condition, cmd1, cmd2);
wait_event_interruptible(wq, condition);
wait_event_interruptible_timeout(wq, condition, timeout);
wait_event_killable(wq, condition);
唤醒API
wake_up(&wq)
wake_up_all(&wq);
wake_up_interruptible(&wq);
wake_up_sync(&wq);
wake_up_interruptible_sync(&wq);
静态方法创建
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h> //kmalloc()
#include <linux/uaccess.h> //copy_to/from_user()
#include <linux/kthread.h>
#include <linux/wait.h> // Required for the wait queues
uint32_t read_count = 0;
static struct task_struct *wait_thread;
DECLARE_WAIT_QUEUE_HEAD(wait_queue_etx);
dev_t dev = 0;
static struct class *dev_class;
static struct cdev etx_cdev;
int wait_queue_flag = 0;
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
/*************** Driver Fuctions **********************/
static int etx_open(struct inode *inode, struct file *file);
static int etx_release(struct inode *inode, struct file *file);
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off);
static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t *off);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = etx_read,
.write = etx_write,
.open = etx_open,
.release = etx_release,
};
static int wait_function(void *unused)
{
while (1)
{
printk(KERN_INFO "Waiting For Event...\n");
wait_event_interruptible(wait_queue_etx, wait_queue_flag != 0);
if (wait_queue_flag == 2)
{
printk(KERN_INFO "Event Came From Exit Function\n");
return 0;
}
printk(KERN_INFO "Event Came From Read Function - %d\n", ++read_count);
wait_queue_flag = 0;
}
do_exit(0);
return 0;
}
static int etx_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Opened...!!!\n");
return 0;
}
static int etx_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Closed...!!!\n");
return 0;
}
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Read Function\n");
wait_queue_flag = 1;
wake_up_interruptible(&wait_queue_etx);
return 0;
}
static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Write function\n");
return 0;
}
static int __init etx_driver_init(void)
{
/*Allocating Major number*/
if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0)
{
printk(KERN_INFO "Cannot allocate major number\n");
return -1;
}
printk(KERN_INFO "Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&etx_cdev, &fops);
etx_cdev.owner = THIS_MODULE;
etx_cdev.ops = &fops;
/*Adding character device to the system*/
if ((cdev_add(&etx_cdev, dev, 1)) < 0)
{
printk(KERN_INFO "Cannot add the device to the system\n");
goto r_class;
}
/*Creating struct class*/
if ((dev_class = class_create(THIS_MODULE, "etx_class")) == NULL)
{
printk(KERN_INFO "Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if ((device_create(dev_class, NULL, dev, NULL, "etx_device")) == NULL)
{
printk(KERN_INFO "Cannot create the Device 1\n");
goto r_device;
}
//Initialize wait queue
init_waitqueue_head(&wait_queue_etx);
//Create the kernel thread with name 'mythread'
wait_thread = kthread_create(wait_function, NULL, "WaitThread");
if (wait_thread)
{
printk("Thread Created successfully\n");
wake_up_process(wait_thread);
}
else
printk(KERN_INFO "Thread creation failed\n");
printk(KERN_INFO "Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev, 1);
return -1;
}
void __exit etx_driver_exit(void)
{
wait_queue_flag = 2;
wake_up_interruptible(&wait_queue_etx);
device_destroy(dev_class, dev);
class_destroy(dev_class);
cdev_del(&etx_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Device Driver Remove...Done!!!\n");
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
MODULE_DESCRIPTION("A Sample Static Waitqueue Demo");
MODULE_VERSION("2:1.0");
动态创建
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h> //kmalloc()
#include <linux/uaccess.h> //copy_to/from_user()
#include <linux/kthread.h>
#include <linux/wait.h> // Required for the wait queues
uint32_t read_count = 0;
static struct task_struct *wait_thread;
dev_t dev = 0;
static struct class *dev_class;
static struct cdev etx_cdev;
wait_queue_head_t wait_queue_etx;
int wait_queue_flag = 0;
static int __init etx_driver_init(void);
static void __exit etx_driver_exit(void);
/*************** Driver Fuctions **********************/
static int etx_open(struct inode *inode, struct file *file);
static int etx_release(struct inode *inode, struct file *file);
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off);
static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t *off);
static struct file_operations fops =
{
.owner = THIS_MODULE,
.read = etx_read,
.write = etx_write,
.open = etx_open,
.release = etx_release,
};
static int wait_function(void *unused)
{
while (1)
{
printk(KERN_INFO "Waiting For Event...\n");
wait_event_interruptible(wait_queue_etx, wait_queue_flag != 0);
if (wait_queue_flag == 2)
{
printk(KERN_INFO "Event Came From Exit Function\n");
return 0;
}
printk(KERN_INFO "Event Came From Read Function - %d\n", ++read_count);
wait_queue_flag = 0;
}
return 0;
}
static int etx_open(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Opened...!!!\n");
return 0;
}
static int etx_release(struct inode *inode, struct file *file)
{
printk(KERN_INFO "Device File Closed...!!!\n");
return 0;
}
static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Read Function\n");
wait_queue_flag = 1;
wake_up_interruptible(&wait_queue_etx);
return 0;
}
static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
{
printk(KERN_INFO "Write function\n");
return 0;
}
static int __init etx_driver_init(void)
{
/*Allocating Major number*/
if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0)
{
printk(KERN_INFO "Cannot allocate major number\n");
return -1;
}
printk(KERN_INFO "Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
/*Creating cdev structure*/
cdev_init(&etx_cdev, &fops);
/*Adding character device to the system*/
if ((cdev_add(&etx_cdev, dev, 1)) < 0)
{
printk(KERN_INFO "Cannot add the device to the system\n");
goto r_class;
}
/*Creating struct class*/
if ((dev_class = class_create(THIS_MODULE, "etx_class")) == NULL)
{
printk(KERN_INFO "Cannot create the struct class\n");
goto r_class;
}
/*Creating device*/
if ((device_create(dev_class, NULL, dev, NULL, "etx_device")) == NULL)
{
printk(KERN_INFO "Cannot create the Device 1\n");
goto r_device;
}
//Initialize wait queue
init_waitqueue_head(&wait_queue_etx);
//Create the kernel thread with name 'mythread'
wait_thread = kthread_create(wait_function, NULL, "WaitThread");
if (wait_thread)
{
printk("Thread Created successfully\n");
wake_up_process(wait_thread);
}
else
printk(KERN_INFO "Thread creation failed\n");
printk(KERN_INFO "Device Driver Insert...Done!!!\n");
return 0;
r_device:
class_destroy(dev_class);
r_class:
unregister_chrdev_region(dev, 1);
return -1;
}
void __exit etx_driver_exit(void)
{
wait_queue_flag = 2;
wake_up_interruptible(&wait_queue_etx);
device_destroy(dev_class, dev);
class_destroy(dev_class);
cdev_del(&etx_cdev);
unregister_chrdev_region(dev, 1);
printk(KERN_INFO "Device Driver Remove...Done!!!\n");
}
module_init(etx_driver_init);
module_exit(etx_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
MODULE_DESCRIPTION("A Sample Dynamic Waitqueue Demo");
MODULE_VERSION("2:1.0");