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; }
Kiitos palautteestasi!
Kysy tekoälyä
Kysy tekoälyä
Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme
Mahtavaa!
Completion arvosana parantunut arvoon 3.85
Wait Queues and Blocking I/O
Pyyhkäise näyttääksesi valikon
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; }
Kiitos palautteestasi!