wait_event and interrupts

Kalle Pokki kalle.pokki at iki.fi
Wed Sep 21 16:16:15 EST 2005


Rune Torgersen wrote:

>Hi
>I have a driver that roughly does something like:
>
>int driver_read(int cs, int addr, void *buf, int len)
>{
>    hw_done = 0;
>    /* init_hw */
>
>    if (!hw_done)
>    {
>        ret = wait_event_interruptible_timeout(inq, hw_done, TIMEOUT);
>        if (ret == 0)
>        {
>            if (hw_done)
>                goto hw_finished;
>			
>            return -EIO;
>        }
>    }
>hw_finished:
>    return len;
>}
>
>static irqreturn_t myinterrupt(int irq, void * dev_id, struct pt_regs *
>regs)
>{
>    hw_done = 1;
>    schedule_work(&tqueue);
>
>    return IRQ_HANDLED;
>}
>
>static void do_softint(void *private_)
>{
>    wake_up_interruptible(&inq);
>
>}
>
>I have a problem however with this, because in about 10% of my cases,
>the interrupt triggers very fast, and ends up being served between the
>check for hw_done and the wait_event call. This cause the wait to
>timeout instead of getting waked up.
>
>Is there a better way of doing this?
>I do not want to do a busy wait, because the hardware can take up to
>several 100's of ms to return, but most often returns within 20us.
>  
>
You seem to create an unnecessary race condition by checking the hw_done 
variable in the read function. You can avoid this by changing it to

int driver_read(int cs, int addr, void *buf, int len)
{
    hw_done = 0;
    /* init_hw */

    if (wait_event_interruptible_timeout(inq, hw_done, TIMEOUT))
	return -ERESTARTSYS;

    hw_done = 0;

    /* copy the data to user space here */

    return len;
}

The wait_event_interruptible_timeout() function checks the variable for 
you. You still must make sure the read function does the right thing if 
it is called simultaneously by more than one application.




More information about the Linuxppc-embedded mailing list