A new wait queue head may be defined by using the DECLARE_WAIT_QUEUE_HEAD(name) macro,
which statically declares a new wait queue head variable called name and initializes its lock and
task_list field. The init_waitqueue_head() function may be used to initialize a wait queue head variable
that was allocated dynamically.
The init_waitqueue_entry(q, p) function initializes a wait_queue_t structure q as floowing:
q->flags = 0; q->task = p; q->func = default_wake_function;
The nonexclusive process p will be awaken by default_wak_function(), which is a simple swapper for the
try_to_wake_up() function.
Alternatively, the DEFINE_WAIT macro declares a new wait_queue_t variable and initialize it with descriptor
of the process currently executing on the CPU and the address of autoremove_wake_function() wake up
function. This function invokes default_wake_function() to awaken the sleeping process, and then removes
the wait queue element from the wait queue list. Finally, a kernel developer can define a custom awakening
function by initializing the wait queue element with the init_waitqueue_func_entry() function.
Once the element is defined, it must be inserted into a wait queue. The add_wait_queue() function inserts
a nonexclusive process in the first position of a wait queue list. The add_wait_queue_exclusive() function
inserts an exclusive process in the last position of a wait queue list. The remove_wait_queue() function removes
a process from a wait queue list. The waitqueue_active() function checks whether a given wait queue list is
empty.
A process waishing to wait for a specific condition can invoke any of the functions shown in the following list.
The sleep_on() function operates on the current process:
void sleep_on(wait_queue_head_t *wq) { wait_queue_t wait; init_waitqueue_entry(&wait. current); current->state = TASK_UNINTERRUPTIBLE; add_wait_queue(wq, &wait); schedule(); remove_wait_queue(wq, &wait); }
The function sets the state of the current process to TASK_UNINTERRUPTIBLE and inserts it into the specified
wait queue. Then it invokes scheduler, which resumes the execution of another process. When the sleeping
process is awakened, the scheduler resumes execution of the sleep_on() function, which removes the process
from the wait queue.
The interruptible_sleep_on() function is identical to sleep_on(), except that it sets the state of the current
process to TASK_INTERRUPTIBLE instead of setting it to TASK_UNINTERRUPTIBLE, so that the process also can
be awaken up by receiving a signal.
The sleep_on_timeout() and interruptiblae_sleep_on_timeout() functions are similar to the previous ones, but
they also allow the caller to define a time interval after the process will be woken up by the kernel. To do this,
they invoke the schedule_timeout() function instrad of schedule().
The prepare_to_wait(), prepare_to_wait_exclusive(), and finish_wait() functions, introduced in Linux 2.6, offer
yet another way to put the current process to sleep in a wait queue,. Typically, they are used as follows:
DEFINE_WAIT(wait); prepare_to_wait_exclusive(&wq, &wait, TASK_INTERRUPTIBLE); ...... if (!condition) schedule(); finish_wait(&wq, &wait);
The prepare_to_wait() and prepare_to_wait_exclusive() functions set the process state to the value passed
as the third parameters, then set the exclusive flag in the wait queue element respectively to 0 (nonexclusive)
or 1 (exclusive), and finally insert the wait queue element wait into the list of the wait queue head wq.
As soon as the process is awakened, it executes the finish_wait() function, which sets again the process state
to TASK_RUNNING (just in case the awaking condition becomes true before invoking schedule()), and removes
the wait queue element from the wait queue list (unless this has already been done by the waking function).
The wait_event and wait_event_interruptible macro put the calling process to sleep on a wait queue until a
given condition is verified. For instance, the wait_event(wq, condition) macro essentialy yields the following
fragment:
DEFINE_WAIT(__wait); for(;;) { prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE); if (condition) break; schedule(); } finish_wait(&wq, &__wait); }
A few comments on the function mentioned in the above list: the sleep_on()- like functions cannot be used in the
common situation where one has to test a condition and atomically put the process to sleep when the condition
is not verified; therefore, because they are a well-known source of race condition, their use is discouraged.