简介

当您编写Linux驱动程序,模块或内核程序时,某些进程应等待或休眠某些事件。在Linux中,有几种处理睡眠和唤醒的方法,每种方法都适合不同的需求。Waitqueue也是处理这种情况的方法之一。
每当进程必须等待事件(例如数据到达或进程终止)时,它就应该进入睡眠状态。睡眠会导致进程挂起执行,从而释放处理器以供其他用途。一段时间后,该过程将被唤醒,并在我们等待的事件到达时继续其工作。
等待队列是内核提供的用于实现等待的机制。顾名思义,waitqueue是等待事件的进程列表。换句话说,当特定条件为真时,使用等待队列来等待有人将您唤醒。必须小心使用它们,以确保没有比赛状况。

使用步骤

  1. 初始化等待队列
  2. 排队(使任务进入睡眠状态,直到事件发生)
  3. 唤醒排队的任务

    初始化方法

  • 静态方法
  • 动态方法 ```c

    静态

    DECLARE_WAIT_QUEUE_HEAD(wq);

动态

wait_queue_head_t wq; init_waitqueue_head (&wq);

  1. <a name="e7tIz"></a>
  2. ### 睡眠API
  3. ```c
  4. wait_event(wq_head, condition)
  5. wait_event_timeout(wq, condition, timeout);
  6. wait_event_cmd(wq, condition, cmd1, cmd2);
  7. wait_event_interruptible(wq, condition);
  8. wait_event_interruptible_timeout(wq, condition, timeout);
  9. wait_event_killable(wq, condition);

唤醒API

  1. wake_up(&wq)
  2. wake_up_all(&wq);
  3. wake_up_interruptible(&wq);
  4. wake_up_sync(&wq);
  5. wake_up_interruptible_sync(&wq);

静态方法创建

  1. #include <linux/kernel.h>
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/kdev_t.h>
  5. #include <linux/fs.h>
  6. #include <linux/cdev.h>
  7. #include <linux/device.h>
  8. #include <linux/slab.h> //kmalloc()
  9. #include <linux/uaccess.h> //copy_to/from_user()
  10. #include <linux/kthread.h>
  11. #include <linux/wait.h> // Required for the wait queues
  12. uint32_t read_count = 0;
  13. static struct task_struct *wait_thread;
  14. DECLARE_WAIT_QUEUE_HEAD(wait_queue_etx);
  15. dev_t dev = 0;
  16. static struct class *dev_class;
  17. static struct cdev etx_cdev;
  18. int wait_queue_flag = 0;
  19. static int __init etx_driver_init(void);
  20. static void __exit etx_driver_exit(void);
  21. /*************** Driver Fuctions **********************/
  22. static int etx_open(struct inode *inode, struct file *file);
  23. static int etx_release(struct inode *inode, struct file *file);
  24. static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off);
  25. static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t *off);
  26. static struct file_operations fops =
  27. {
  28. .owner = THIS_MODULE,
  29. .read = etx_read,
  30. .write = etx_write,
  31. .open = etx_open,
  32. .release = etx_release,
  33. };
  34. static int wait_function(void *unused)
  35. {
  36. while (1)
  37. {
  38. printk(KERN_INFO "Waiting For Event...\n");
  39. wait_event_interruptible(wait_queue_etx, wait_queue_flag != 0);
  40. if (wait_queue_flag == 2)
  41. {
  42. printk(KERN_INFO "Event Came From Exit Function\n");
  43. return 0;
  44. }
  45. printk(KERN_INFO "Event Came From Read Function - %d\n", ++read_count);
  46. wait_queue_flag = 0;
  47. }
  48. do_exit(0);
  49. return 0;
  50. }
  51. static int etx_open(struct inode *inode, struct file *file)
  52. {
  53. printk(KERN_INFO "Device File Opened...!!!\n");
  54. return 0;
  55. }
  56. static int etx_release(struct inode *inode, struct file *file)
  57. {
  58. printk(KERN_INFO "Device File Closed...!!!\n");
  59. return 0;
  60. }
  61. static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
  62. {
  63. printk(KERN_INFO "Read Function\n");
  64. wait_queue_flag = 1;
  65. wake_up_interruptible(&wait_queue_etx);
  66. return 0;
  67. }
  68. static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
  69. {
  70. printk(KERN_INFO "Write function\n");
  71. return 0;
  72. }
  73. static int __init etx_driver_init(void)
  74. {
  75. /*Allocating Major number*/
  76. if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0)
  77. {
  78. printk(KERN_INFO "Cannot allocate major number\n");
  79. return -1;
  80. }
  81. printk(KERN_INFO "Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
  82. /*Creating cdev structure*/
  83. cdev_init(&etx_cdev, &fops);
  84. etx_cdev.owner = THIS_MODULE;
  85. etx_cdev.ops = &fops;
  86. /*Adding character device to the system*/
  87. if ((cdev_add(&etx_cdev, dev, 1)) < 0)
  88. {
  89. printk(KERN_INFO "Cannot add the device to the system\n");
  90. goto r_class;
  91. }
  92. /*Creating struct class*/
  93. if ((dev_class = class_create(THIS_MODULE, "etx_class")) == NULL)
  94. {
  95. printk(KERN_INFO "Cannot create the struct class\n");
  96. goto r_class;
  97. }
  98. /*Creating device*/
  99. if ((device_create(dev_class, NULL, dev, NULL, "etx_device")) == NULL)
  100. {
  101. printk(KERN_INFO "Cannot create the Device 1\n");
  102. goto r_device;
  103. }
  104. //Initialize wait queue
  105. init_waitqueue_head(&wait_queue_etx);
  106. //Create the kernel thread with name 'mythread'
  107. wait_thread = kthread_create(wait_function, NULL, "WaitThread");
  108. if (wait_thread)
  109. {
  110. printk("Thread Created successfully\n");
  111. wake_up_process(wait_thread);
  112. }
  113. else
  114. printk(KERN_INFO "Thread creation failed\n");
  115. printk(KERN_INFO "Device Driver Insert...Done!!!\n");
  116. return 0;
  117. r_device:
  118. class_destroy(dev_class);
  119. r_class:
  120. unregister_chrdev_region(dev, 1);
  121. return -1;
  122. }
  123. void __exit etx_driver_exit(void)
  124. {
  125. wait_queue_flag = 2;
  126. wake_up_interruptible(&wait_queue_etx);
  127. device_destroy(dev_class, dev);
  128. class_destroy(dev_class);
  129. cdev_del(&etx_cdev);
  130. unregister_chrdev_region(dev, 1);
  131. printk(KERN_INFO "Device Driver Remove...Done!!!\n");
  132. }
  133. module_init(etx_driver_init);
  134. module_exit(etx_driver_exit);
  135. MODULE_LICENSE("GPL");
  136. MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
  137. MODULE_DESCRIPTION("A Sample Static Waitqueue Demo");
  138. MODULE_VERSION("2:1.0");

动态创建

  1. #include <linux/kernel.h>
  2. #include <linux/init.h>
  3. #include <linux/module.h>
  4. #include <linux/kdev_t.h>
  5. #include <linux/fs.h>
  6. #include <linux/cdev.h>
  7. #include <linux/device.h>
  8. #include <linux/slab.h> //kmalloc()
  9. #include <linux/uaccess.h> //copy_to/from_user()
  10. #include <linux/kthread.h>
  11. #include <linux/wait.h> // Required for the wait queues
  12. uint32_t read_count = 0;
  13. static struct task_struct *wait_thread;
  14. dev_t dev = 0;
  15. static struct class *dev_class;
  16. static struct cdev etx_cdev;
  17. wait_queue_head_t wait_queue_etx;
  18. int wait_queue_flag = 0;
  19. static int __init etx_driver_init(void);
  20. static void __exit etx_driver_exit(void);
  21. /*************** Driver Fuctions **********************/
  22. static int etx_open(struct inode *inode, struct file *file);
  23. static int etx_release(struct inode *inode, struct file *file);
  24. static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off);
  25. static ssize_t etx_write(struct file *filp, const char *buf, size_t len, loff_t *off);
  26. static struct file_operations fops =
  27. {
  28. .owner = THIS_MODULE,
  29. .read = etx_read,
  30. .write = etx_write,
  31. .open = etx_open,
  32. .release = etx_release,
  33. };
  34. static int wait_function(void *unused)
  35. {
  36. while (1)
  37. {
  38. printk(KERN_INFO "Waiting For Event...\n");
  39. wait_event_interruptible(wait_queue_etx, wait_queue_flag != 0);
  40. if (wait_queue_flag == 2)
  41. {
  42. printk(KERN_INFO "Event Came From Exit Function\n");
  43. return 0;
  44. }
  45. printk(KERN_INFO "Event Came From Read Function - %d\n", ++read_count);
  46. wait_queue_flag = 0;
  47. }
  48. return 0;
  49. }
  50. static int etx_open(struct inode *inode, struct file *file)
  51. {
  52. printk(KERN_INFO "Device File Opened...!!!\n");
  53. return 0;
  54. }
  55. static int etx_release(struct inode *inode, struct file *file)
  56. {
  57. printk(KERN_INFO "Device File Closed...!!!\n");
  58. return 0;
  59. }
  60. static ssize_t etx_read(struct file *filp, char __user *buf, size_t len, loff_t *off)
  61. {
  62. printk(KERN_INFO "Read Function\n");
  63. wait_queue_flag = 1;
  64. wake_up_interruptible(&wait_queue_etx);
  65. return 0;
  66. }
  67. static ssize_t etx_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)
  68. {
  69. printk(KERN_INFO "Write function\n");
  70. return 0;
  71. }
  72. static int __init etx_driver_init(void)
  73. {
  74. /*Allocating Major number*/
  75. if ((alloc_chrdev_region(&dev, 0, 1, "etx_Dev")) < 0)
  76. {
  77. printk(KERN_INFO "Cannot allocate major number\n");
  78. return -1;
  79. }
  80. printk(KERN_INFO "Major = %d Minor = %d \n", MAJOR(dev), MINOR(dev));
  81. /*Creating cdev structure*/
  82. cdev_init(&etx_cdev, &fops);
  83. /*Adding character device to the system*/
  84. if ((cdev_add(&etx_cdev, dev, 1)) < 0)
  85. {
  86. printk(KERN_INFO "Cannot add the device to the system\n");
  87. goto r_class;
  88. }
  89. /*Creating struct class*/
  90. if ((dev_class = class_create(THIS_MODULE, "etx_class")) == NULL)
  91. {
  92. printk(KERN_INFO "Cannot create the struct class\n");
  93. goto r_class;
  94. }
  95. /*Creating device*/
  96. if ((device_create(dev_class, NULL, dev, NULL, "etx_device")) == NULL)
  97. {
  98. printk(KERN_INFO "Cannot create the Device 1\n");
  99. goto r_device;
  100. }
  101. //Initialize wait queue
  102. init_waitqueue_head(&wait_queue_etx);
  103. //Create the kernel thread with name 'mythread'
  104. wait_thread = kthread_create(wait_function, NULL, "WaitThread");
  105. if (wait_thread)
  106. {
  107. printk("Thread Created successfully\n");
  108. wake_up_process(wait_thread);
  109. }
  110. else
  111. printk(KERN_INFO "Thread creation failed\n");
  112. printk(KERN_INFO "Device Driver Insert...Done!!!\n");
  113. return 0;
  114. r_device:
  115. class_destroy(dev_class);
  116. r_class:
  117. unregister_chrdev_region(dev, 1);
  118. return -1;
  119. }
  120. void __exit etx_driver_exit(void)
  121. {
  122. wait_queue_flag = 2;
  123. wake_up_interruptible(&wait_queue_etx);
  124. device_destroy(dev_class, dev);
  125. class_destroy(dev_class);
  126. cdev_del(&etx_cdev);
  127. unregister_chrdev_region(dev, 1);
  128. printk(KERN_INFO "Device Driver Remove...Done!!!\n");
  129. }
  130. module_init(etx_driver_init);
  131. module_exit(etx_driver_exit);
  132. MODULE_LICENSE("GPL");
  133. MODULE_AUTHOR("zhouchengzhu <1073355312@qq.com>");
  134. MODULE_DESCRIPTION("A Sample Dynamic Waitqueue Demo");
  135. MODULE_VERSION("2:1.0");

参考资料