[Begin by giving a general description of how sleeping is used and what it does. This should mention things like all processes sleeping on an event are woken at once, and then they contend for the event again, etc...]
Perhaps the best way to try to understand the sleep-wakeup mechanism is to read the source for the __sleep_on() function, used to implement both the sleep_on() and interruptible_sleep_on() calls.
A wait_queue is a circular list of pointers to task structures, defined in <linux/wait.h> to be
state is either TASK_INTERRUPTIBLE or TASK_UNINTERUPTIBLE, depending on whether or not the sleep should be interruptable by such things as system calls. In general, the sleep should be interruptible if the device is a slow one; one which can block indefinitely, including terminals and network devices or pseudodevices.
add_wait_queue() turns off interrupts, if they were enabled, and adds the new struct wait_queue declared at the beginning of the function to the list p. It then recovers the original interrupt state (enabled or disabled), and returns.
save_flags() is a macro which saves the process flags in its argument. This is done to preserve the previous state of the interrupt enable flag. This way, the restore_flags() later can restore the interrupt state, whether it was enabled or disabled. sti() then allows interrupts to occur, and schedule() finds a new process to run, and switches to it. Schedule will not choose this process to run again until the state is changed to TASK_RUNNING by wake_up() called on the same wait queue, p, or conceivably by something else.
The process then removes itself from the wait_queue, restores the orginal interrupt condition with restore_flags(), and returns.
Whenever contention for a resource might occur, there needs to be a pointer to a wait_queue associated with that resource. Then, whenever contention does occur, each process that finds itself locked out of access to the resource sleeps on that resource's wait_queue. When any process is finished using a resource for which there is a wait_queue, it should wake up and processes that might be sleeping on that wait_queue, probably by calling wake_up(), or possibly wake_up_interruptible().
If you don't understand why a process might want to sleep, or want more details on when and how to structure this sleeping, I urge you to buy one of the operating systems textbooks listed in Appendix and look up mutual exclusion and deadlock.
[This is a cop-out. I should take the time to explain and give examples, but I am not trying to write an OS text, and I want to keep this under 1000 pages...]