Wait Queues and Blocking I/O
When writing device drivers, you often need a way to let user-space processes wait for events, such as data becoming available. In the kernel, wait queues provide a mechanism for blocking a process until a condition is met. When a process performs a blocking read and the data is not ready, it can be put to sleep on a wait queue, freeing up the CPU for other work until the desired event occurs.
blocking_read_example.c
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/wait.h> #include <linux/mutex.h> #define DEVICE_NAME "waitqdemo" #define BUF_SIZE 128 static int major; static char device_buffer[BUF_SIZE]; static int data_available = 0; static DECLARE_WAIT_QUEUE_HEAD(waitq); static DEFINE_MUTEX(buffer_mutex); ssize_t waitq_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int ret; // Block until data_available is set if (wait_event_interruptible(waitq, data_available)) return -ERESTARTSYS; mutex_lock(&buffer_mutex); ret = simple_read_from_buffer(buf, count, ppos, device_buffer, BUF_SIZE); data_available = 0; // Reset after reading mutex_unlock(&buffer_mutex); return ret; } ssize_t waitq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t ret; mutex_lock(&buffer_mutex); ret = simple_write_to_buffer(device_buffer, BUF_SIZE, ppos, buf, count); data_available = 1; mutex_unlock(&buffer_mutex); // Will notify reader in the write example below // wake_up_interruptible(&waitq); return ret; } struct file_operations waitq_fops = { .owner = THIS_MODULE, .read = waitq_read, .write = waitq_write, }; static int __init waitq_init(void) { major = register_chrdev(0, DEVICE_NAME, &waitq_fops); if (major < 0) return major; pr_info("waitqdemo: loaded with major %d\n", major); return 0; } static void __exit waitq_exit(void) { unregister_chrdev(major, DEVICE_NAME); pr_info("waitqdemo: unloaded\n"); } module_init(waitq_init); module_exit(waitq_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kernel Course"); MODULE_DESCRIPTION("Wait queue blocking read example");
The code above demonstrates a blocking read operation using a wait queue. The wait_event_interruptible macro puts the calling process to sleep until the data_available flag is set. Once another part of the driver sets this flag and calls wake_up_interruptible, the waiting process is woken up. This is how event notification is implemented in the kernel: after the write operation receives new data, it signals waiting readers by waking them up.
wakeup_write_example.c
12345678910111213141516171819202122232425262728// wakeup_write_example.c #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/wait.h> #include <linux/mutex.h> extern wait_queue_head_t waitq; extern int data_available; extern char device_buffer[]; #define BUF_SIZE 128 ssize_t waitq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t ret; mutex_lock(&buffer_mutex); ret = simple_write_to_buffer(device_buffer, BUF_SIZE, ppos, buf, count); data_available = 1; mutex_unlock(&buffer_mutex); // Notify any process waiting on the wait queue wake_up_interruptible(&waitq); return ret; }
Дякуємо за ваш відгук!
Запитати АІ
Запитати АІ
Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат
Чудово!
Completion показник покращився до 3.85
Wait Queues and Blocking I/O
Свайпніть щоб показати меню
When writing device drivers, you often need a way to let user-space processes wait for events, such as data becoming available. In the kernel, wait queues provide a mechanism for blocking a process until a condition is met. When a process performs a blocking read and the data is not ready, it can be put to sleep on a wait queue, freeing up the CPU for other work until the desired event occurs.
blocking_read_example.c
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/wait.h> #include <linux/mutex.h> #define DEVICE_NAME "waitqdemo" #define BUF_SIZE 128 static int major; static char device_buffer[BUF_SIZE]; static int data_available = 0; static DECLARE_WAIT_QUEUE_HEAD(waitq); static DEFINE_MUTEX(buffer_mutex); ssize_t waitq_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int ret; // Block until data_available is set if (wait_event_interruptible(waitq, data_available)) return -ERESTARTSYS; mutex_lock(&buffer_mutex); ret = simple_read_from_buffer(buf, count, ppos, device_buffer, BUF_SIZE); data_available = 0; // Reset after reading mutex_unlock(&buffer_mutex); return ret; } ssize_t waitq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t ret; mutex_lock(&buffer_mutex); ret = simple_write_to_buffer(device_buffer, BUF_SIZE, ppos, buf, count); data_available = 1; mutex_unlock(&buffer_mutex); // Will notify reader in the write example below // wake_up_interruptible(&waitq); return ret; } struct file_operations waitq_fops = { .owner = THIS_MODULE, .read = waitq_read, .write = waitq_write, }; static int __init waitq_init(void) { major = register_chrdev(0, DEVICE_NAME, &waitq_fops); if (major < 0) return major; pr_info("waitqdemo: loaded with major %d\n", major); return 0; } static void __exit waitq_exit(void) { unregister_chrdev(major, DEVICE_NAME); pr_info("waitqdemo: unloaded\n"); } module_init(waitq_init); module_exit(waitq_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kernel Course"); MODULE_DESCRIPTION("Wait queue blocking read example");
The code above demonstrates a blocking read operation using a wait queue. The wait_event_interruptible macro puts the calling process to sleep until the data_available flag is set. Once another part of the driver sets this flag and calls wake_up_interruptible, the waiting process is woken up. This is how event notification is implemented in the kernel: after the write operation receives new data, it signals waiting readers by waking them up.
wakeup_write_example.c
12345678910111213141516171819202122232425262728// wakeup_write_example.c #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/uaccess.h> #include <linux/wait.h> #include <linux/mutex.h> extern wait_queue_head_t waitq; extern int data_available; extern char device_buffer[]; #define BUF_SIZE 128 ssize_t waitq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { ssize_t ret; mutex_lock(&buffer_mutex); ret = simple_write_to_buffer(device_buffer, BUF_SIZE, ppos, buf, count); data_available = 1; mutex_unlock(&buffer_mutex); // Notify any process waiting on the wait queue wake_up_interruptible(&waitq); return ret; }
Дякуємо за ваш відгук!