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; }
Tak for dine kommentarer!
Spørg AI
Spørg AI
Spørg om hvad som helst eller prøv et af de foreslåede spørgsmål for at starte vores chat
Fantastisk!
Completion rate forbedret til 3.85
Wait Queues and Blocking I/O
Stryg for at vise menuen
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; }
Tak for dine kommentarer!