/*
 * No available requests for this queue, unplug the device and wait for some
 * requests to become available.
 *
 * Called with q->queue_lock held, and returns with it unlocked.
 */
static struct request *get_request_wait(struct request_queue *q, int rw_flags,
                                        struct bio *bio)
{
        const int rw = rw_flags & 0x01;
        struct request *rq;

        rq = get_request(q, rw_flags, bio, GFP_NOIO);
        while (!rq) {
                DEFINE_WAIT(wait);
                struct io_context *ioc;
                struct request_list *rl = &q->rq;

                prepare_to_wait_exclusive(&rl->wait[rw], &wait,
                                TASK_UNINTERRUPTIBLE);

                blk_add_trace_generic(q, bio, rw, BLK_TA_SLEEPRQ);

                __generic_unplug_device(q);
                spin_unlock_irq(q->queue_lock);
                io_schedule();

                /*
                 * After sleeping, we become a "batching" process and
                 * will be able to allocate at least one request, and
                 * up to a big batch of them for a small period time.
                 * See ioc_batching, ioc_set_batching
                 */
                ioc = current_io_context(GFP_NOIO, q->node);
                ioc_set_batching(q, ioc);

                spin_lock_irq(q->queue_lock);
                finish_wait(&rl->wait[rw], &wait);

                rq = get_request(q, rw_flags, bio, GFP_NOIO);
        };

        return rq;
}




From: Rik van Riel <[EMAIL PROTECTED]>

On Tue, 2 Sep 2008 11:40:59 +0530
"Venky Shankar" <[EMAIL PROTECTED]> wrote:

> up(&semaphore);
> ---
> ---
> ---
> prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
> if(condition())
>     schedule();
> finish_wait(queue, &wait);
> ---
> ---
> ---
> down_interruptible(&semaphore);

>  1. The above code can get preempted just after the call to
> prepare_to_wait(), In that case it would not be run again by the scheduler
> since it
>  is in the TASK_INTERRUPTIBLE state. After that when someone wake's it up,
> then the check is made (if condition) and then the normal flow of code.

This is correct.

>  2. If the code does not get preempted after the call to prepare_to_wait(),
> it will still execute the if condition while in TASK_INTERRUPTIBLE state -->
> but a  TASK_INTERRUPTIBLE state is not runnable - i feel this is valid after
> the call to schedule() is made. (i.e. it would not run again after it has
> given up the CPU)

The task continues to run after it has set its state to TASK_INTERRUPTIBLE.
Once it enters schedule() it will be taken off the runqueue and stop
being runnable.

This is ok, because by now it is on a wait queue and eventually it
should get woken up.

So yes, you understand this code correctly :)





-- 
Regards,
Peter Teoh

Reply via email to