Hi Tim.
Thanks very much for the example. Being paranoid, it raises
one more question, though:
You say
priv->wakeupTask=current;
set_current_state(TASK_INTERRUPTIBLE);
schedule();
but is it not necessary to take a raw_spin_lock_irqsave()
around storing the task pointer and changing the task
state? To be more precise: around starting the device
and setting the task state. I would have thought I would
have to code like this:
priv->wakeupTask = current;
raw_spin_lock_irqsave(...)
start_device();
/* What happens if a fast device would interrupt here
* without the raw spinlock? Would I not sleep forever?
*/
set_current_state(TASK_INTERRUPTIBLE);
raw_spin_unlock_irqrestore(...)
schedule();
Assuming that an IRQ could happen any time once the device
is started - don't I have to avoid giving the the hard-isr the
chance of executing wake_up_process() before
set_current_state(TASK_INTERRUPTIBLE) has finished?
Thanks again
- Till
On 11/09/2012 08:18 AM, Tim Sander wrote:
Hi Till
What *is* the recommended mechanism to wake up a thread from
a hard-isr?
I think its the waitqueue mechanism with the drawbacks you mentioned.
I thought I can't wake_up() from a hard-isr so that can hardly be
the recommended mechanism (unless you mean I *should* go
via the 'irq_thread' (kernel/irq/management.c) and wake my
user-land thread from there).
For multiple waiters i don't know any other solution than the irq-thread
mechanism with the additional delay.
The IRQ management code must use something to let the
hard-isr unblock the irq-handler kthread - I'd like to use the same
(or a similar) method to let the hard-isr unblock a user-land
thread.
If you only want to wake up *one* usermode thread there is a hack
possible to save the context switch times to the bottom half interrupt
thread?
What would such a hack be?
Credits go to Thomas Gleixner for this hack (Keep in mind it only works
for a *single* waiter, so your driver should probably only allow exclusive
opens of this device.)
Define a structure:
struct task_struct *wakeupTask;
In the read routine which should wait for the interrupt pulse:
priv->wakeupTask=current;
set_current_state(TASK_INTERRUPTIBLE);
schedule();
//i'll be back :-)
retval = copy_to_user(...);
__set_current_state(TASK_RUNNING);
And in isr context just do a:
wake_up_process(current_instance->wakeupTask);
Best regards
Tim
--
To unsubscribe from this list: send the line "unsubscribe linux-rt-users" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html