wait_event_interruptible() seems non-atomic

From: Jan Engelhardt
Date: Sat Nov 20 2004 - 10:37:00 EST


Hi list,


upon reviewing some of my code for a device driver, I've come across:


static ssize_t uif_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
// Nothing read, nothing done
if(count == 0) { return 0; }

// Must sleep as long as there is no data
if(down_interruptible(&Buffer_lock)) { return -ERESTARTSYS; }
while(BufRP == BufWP) {
up(&Buffer_lock);
if(filp->f_flags & O_NONBLOCK) { return -EAGAIN; }

// hm, the condition is not atomic or locked...
if(wait_event_interruptible(Pull_queue, (BufRP != BufWP))) {
return -ERESTARTSYS;
}
if(down_interruptible(&Buffer_lock)) { return -ERESTARTSYS; }
}

// Data is available, so give it to the user
...
}

As you can see, I lock Buffer_lock and then check BufRP == BufWP. I do that
because in an SMP environment, either of BufRP or BufWP might have been
updated. (I.e. one CPU currently does "mov BufRP to eax; mov BufWP to ebx; cmp
eax, ebx" while another does "inc BufWP")

I would like to also lock Buffer_lock around BufRP != BufWP, but don't see a
way on how to accomplish this.

Does anybody know a way how this could be achieved?



Jan Engelhardt
--
Gesellschaft fÃr Wissenschaftliche Datenverarbeitung
Am Fassberg, 37077 GÃttingen, www.gwdg.de
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/