What you're looking for is a construct that's widely used in the kernel to
eliminate races with interrupts f:
struct wait_queue *my_wait_queue = NULL;
foo_irq()
{
wake_up_interruptible(&my_wait_queue);
}
foo_read()
{
struct wait_queue wait = { current, NULL };
current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&my_wait_queue, &wait);
/* now start the hardware. if the interrupt comes in before we
* enter schedule, the task is set back to TASK_RUNNING and the
* schedule becomes a no-op
*/
...
schedule();
if (signal_pending(current))
ret = -ERESTARTSYS;
...cleanup
remove_wait_queue(&my_wait_queue, &wait);
return ret;
}
Basically, a task puts it self onto the list for whatever it is waiting
before it starts the process that will lead to the wakeup. This solves
the problem with interrupts. interruptible_sleep_on can only really be
used if you're waiting on another task. For 2.3, the declaration for
my_wait_queue can become a wait_queue_head_t my_wait_queue;
init_wait_queue(&my_wait_queue_head_t) (there's a macro for use in
variable declarations), and use DECLARE_WAITQUEUE(wait, current); instead
of defining the structure. Of course, using macros and always writing the
2.3 form is easier. =) You may wish to make your driver trigger the data
acquesition and buffer results rather than starting from userland each
time to speed things up. Also, if latency is a concern rtlinux will be
worth investigating.
-ben
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/