To use this API in our code, we should include the header file <linux/wait.h>.
First we declare and init our wait queue by calling a dedicated macro in our code:
DECLARE_WAIT_QUEUE_HEAD(name);This is called a static initialization, we can also do a dynamic initialization by using the following code:
wait_queue_head_t my_queue;Now for sleeping our code, we use one of these functions:
init_waitqueue_head(&my_queue);
wait_event(queue, condition)So while condition is false, the process continue to sleep.
wait_event_interruptible(queue, condition)
wait_event_timeout(queue, condition, timeout)
wait_event_interruptible_timeout(queue, condition, timeout)
If we use wait_event, our process is put into an uninterruptible sleep. The preferred alternative is wait_event_interruptible, which can be interrupted by signals. This version returns an integer value that we should check; a nonzero value means our sleep was inter-rupted by some sort of signal, and our driver should probably return -ERESTARTSYS.
The final versions (wait_event_timeout and wait_event_interruptible_timeout) wait for a limited time; after that time period (expressed in jiffies) expires, the macros return with a value of 0 regardless of how condition evaluates.
Now to wake up all process in a given queue we should call:
void wake_up(wait_queue_head_t *queue);The last function restricts itself to processes performing an interruptible sleep.
void wake_up_interruptible(wait_queue_head_t *queue);
We now know enough to look at a simple example of sleeping and waking up. In the sample source, you can find a module called sleepy. It implements a device with simple behavior: any process that attempts to read from the device is put to sleep. Whenever a process writes to the device, all sleeping processes are awakened. This behavior is implemented with the following read and write methods:
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int flag = 0;
ssize_t sleepy_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) going to sleep\n",
current->pid, current->comm);
wait_event_interruptible(wq, flag != 0);
flag = 0;
printk(KERN_DEBUG "awoken %i (%s)\n", current->pid, current->comm);
return 0; /* EOF */
}
ssize_t sleepy_write (struct file *filp, const char __user *buf, size_t count,loff_t *pos)
{
printk(KERN_DEBUG "process %i (%s) awakening the readers...\n",
current->pid, current->comm);
flag = 1;
wake_up_interruptible(&wq);
return count; /* succeed, to avoid retrial */
}
Source: Linux Device Drivers, 3rd Edition
No comments:
Post a Comment