Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn Wait Queues and Blocking I/O | Interrupts, Timing, and Concurrency
C Device Drivers Basics

bookWait 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

blocking_read_example.c

copy
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

wakeup_write_example.c

copy
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; }
question mark

What is the purpose of the wait_event function in kernel code?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 4. ChapterΒ 4

Ask AI

expand

Ask AI

ChatGPT

Ask anything or try one of the suggested questions to begin our chat

Suggested prompts:

Can you explain how wait queues differ from other synchronization mechanisms in the kernel?

What happens if the process is interrupted while waiting on the wait queue?

Can you provide an example of how to implement a wait queue in a device driver?

bookWait Queues and Blocking I/O

Swipe to show menu

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

blocking_read_example.c

copy
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

wakeup_write_example.c

copy
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; }
question mark

What is the purpose of the wait_event function in kernel code?

Select the correct answer

Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 4. ChapterΒ 4
some-alt