ULK --- Chap3 Processes: Handling Wait Queues

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.

 

posted on 2015-11-10 12:39  Persistence  阅读(168)  评论(0编辑  收藏  举报

导航