Нужно ли защищать мой обработчик прерываний, вызываемый много раз для одного и того же прерывания?
Учитывая следующий код, я не уверен в системных вызовах, которые я должен сделать. Я получаю редкие, случайные тупики с этой текущей реализацией: -
void interrupt_handler(void)
{
down_interruptible(&sem); // or use a lock here ?
clear_intr(); // clear interrupt source on H/W
wake_up_interruptible(...);
up(&sem); // unlock?
return IRQ_HANDLED;
}
void set/clear_intr()
{
spin_lock_irq(&lock);
RMW(x); // set/clear a bit by read/modify/write the H/W interrupt routing register
spin_unlock_irq(&lock);
}
void read()
{
set_intr(); // same as clear_intr, but sets a bit
wait_event_interruptible(...);
}
- Должно ли
interrupt_handler
: down_interruptible
быть spin_lock_irq
/ spin_lock_irqsave
/ local_irq_disable
?
- Должно ли
set/clear_intr
: spin_lock_irq
быть spin_lock_irqsave
/ local_irq_disable
?
- Может ли он (H / W -> kernel -> обработчик драйвера) продолжать генерировать / получать прерывания, пока он не будет очищен? Может ли
interrupt_handler
продолжать звонить, находясь внутри него?
- Если, как в настоящее время реализовано, обработчик прерываний является реентерабельным, то он будет блокироваться на
down_interruptible
?
От LDD3: -
должен быть reentrant - он должен быть способен работать в более чем одном контексте одновременно.
Редактировать 1) после небольшой помощи, предложения: -
- удалить
down_interruptible
изнутри interrupt_handler
- Переместить
spin_lock_irq
за пределы методов set / clear (не нужно spin_lock_irqsave
говорите?) Я действительно не вижу в этом пользы?!
Код: -
void interrupt_handler(void)
{
read_reg(y); // eg of other stuff in the handler
spin_lock_irq(&lock);
clear_intr(); // clear interrupt source on H/W
spin_unlock_irq(&lock);
wake_up_interruptible(...);
return IRQ_HANDLED;
}
void set/clear_intr()
{
RMW(x);
}
void read()
{
error_checks(); // eg of some other stuff in the read method
spin_lock_irq(&lock);
set_intr(); // same as clear_intr, but sets a bit
spin_unlock_irq(&lock);
wait_event_interruptible(...);
// more code here...
}
Edit2) После прочтения еще нескольких SO-сообщений: чтение Почему код / поток ядра, выполняющийся в контексте прерываний, не может спать? , который ссылается на Роберта Лавса статья , я прочитал это:
некоторые обработчики прерываний (известные в
Linux как быстрые обработчики прерываний)
со всеми прерываниями на местном
процессор отключен. Это сделано для
убедитесь, что обработчик прерываний работает
без перерыва, так быстро, как
возможный. Более того, все прерывают
обработчики бегут со своим текущим
линия прерывания отключена на всех
процессоры. Это гарантирует, что два
обработчики прерываний для того же
линия прерывания не запускается
одновременно. Это также предотвращает устройство
писатели драйвера от необходимости справляться
рекурсивные прерывания, которые усложняют
программирования.
И у меня включены быстрые прерывания (SA_INTERRUPT)! Так что нет необходимости в мьютексе / замках / семафорах / вращениях / ожиданиях / снах и т. Д. / И т. Д.