Нужно ли мне защищать обработчик прерываний, вызываемый много раз за одно и то же прерывание?
Учитывая следующий код, я не уверен в системных вызовах, которые я должен сделать. Я получаю редкие случайные блокировки с этой текущей реализацией: -
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: -
должен быть реентерабельным - он должен быть способен работать в нескольких контекстах одновременно.
Изменить 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: чтение Почему код ядра/поток, выполняемый в контексте прерывания, не может спать?, который ссылается на Robert Loves article, я прочел следующее:
некоторые обработчики прерываний (известные в Linux как быстрые обработчики прерываний) со всеми прерываниями на местном процессор отключен. Это делается для убедитесь, что выполняется обработчик прерываний без перерыва, так же быстро, как возможное. Более того, все прерывания обработчики работают с их текущими прерывание отключено на всех процессоры. Это гарантирует, что два обработчики прерываний для одного и того же строка прерывания не запускается одновременно. Он также предотвращает авторам драйверов от необходимости обращаться рекурсивных прерываний, которые усложняют программирование.
И у меня есть быстрые прерывания (SA_INTERRUPT)! Поэтому нет необходимости в mutex/locks/semafhores/spins/waits/sleeps/etc/etc!