* Выяснить, что вызвало прерывание, и определить, надо ли
* потоку что-нибудь с этим делать.
* (Константы основаны на строении регистра
* идентификации прерывания 8250.)
*/
switch (iir) {
case IIR_MSR:
serial_msr = in8(base_reg + REG_MS);
/* Разбудить поток */
return (event);
break;
case IIR_THE:
/* Ничего не делать */
break;
case IIR_RX:
/* Считать символ */
serial_rx = in8(base_reg + REG_RX);
break;
case IIR_LSR:
/* Сохранить регистр состояния линии */
serial_lsr = in8(base_reg + REG_LS);
break;
default:
break;
}
/* Никого не беспокоить */
return (NULL);
}
Первое, что бросается в глаза, — что все переменные, к которым обращается ISR, должны быть объявлены как
volatile
. В с единственным процессором это делается не для блага обработчиков прерываний, а для облегчения жизни потокам, которые могут быть прерваны обработчиком прерывания в любой момент. Конечно, в многопроцессорной ЭВМ обработчики прерываний вполне могли бы выполняться одновременно с кодом потоков, и в таких случаях надо быть предельно осторожными с вещами подобного рода.
С помощью ключевого слова
volatile
мы указываем компилятору не кэшировать значения этих переменных, поскольку они могут быть изменены в любой точке выполнения программы.
Следующее, на что мы обращаем внимание — это прототип самого обработчика прерывания. Он обозначен как
const struct sigevent*
. Это говорит о том, что подпрограмма intHandler возвращает указатель на
struct sigevent
. Это стандарт для всех подпрограмм обработки прерываний.
Наконец, обратите внимание на то, что решение, передавать или не передавать событие потоку, принимает сам обработчик. Здесь мы генерируем событие только в случае прерывания по изменению регистра состояния модема (MSR) (событие определяется переменной event, которая передается обработчику прерывания в момент его подключения). Во всех других случаях мы игнорируем прерывание (и обновляем кое-какие глобальные переменные); однако, источник прерывания мы очищаем во всех случаях. Это выполняется считыванием порта ввода/вывода с помощью вызова in8.
Применение функции InterruptAttachEvent
Если бы мы должны были переписать вышеприведенную программу с применением функции InterruptAttachEvent, это бы выглядело так: