Отметим, что событие, которое вы возвращаете, должно продолжать существовать даже после того, как будет освобожден стек ISR (потому что локальные переменные хранятся в стеке —
Активность прерываний по уровню и по фронту
Недостает еще одного фрагмента мозаики. Большинство контроллеров прерываний могут быть запрограммированы на чувствительность либо к уровню сигнала прерывания, либо к его фронту.
В режиме чувствительности по уровню считается, что сигнал прерывания выставлен, когда соответствующая линия шины находится в активном состоянии (это соответствует отметке «1» на рисунке ниже).
Выставление сигнала прерывания в режиме чувствительности по уровню.
Из рисунка видно, что работа с прерыванием контроллером дисковода в таком режиме привела бы к вышеупомянутой проблеме. Каждый раз при завершении ISR ядро сообщает контроллеру прерываний: «Порядок, это прерывание обработано. Сообщи мне, когда оно возникнет снова.» (отметка «2» на рисунке). Говоря техническим языком, ядро посылает контроллеру сигнал EOI (End Of Interrupt — «конец прерывания»). Контроллер PIC анализирует линию прерывания и если она все еще активна, он немедленно прерывает ядро заново (отметка «3»).
Мы могли бы обойти эту проблему, перепрограммировав контроллер прерываний в режим чувствительности по фронту.
В этом режиме прерывания распознаются контроллером только по переднему фронту сигнала.
Выставление сигнала прерывания в режиме чувствительности по фронту.
Здесь, даже если обработчик прерываний не очищает источник прерывания, после передачи ядром контроллеру сигнала EOI контроллер не может заново прервать ядро, потому что другого переднего фронта на линии прерывания после передачи EOI не будет. Для распознавания следующего прерывания на данной линии ее сначала будет необходимо деактивировать (отметка «4»), а затем активировать вновь (отметка «1»).
Похоже, что все наши проблемы решены! Будем использовать режим чувствительности по фронту и жить счастливо. Но, к сожалению, у режима чувствительности по фронту тоже есть свои проблемы.
Предположим, что ваш ISR не очистил источник прерывания. Когда ядро выдаст контроллеру сигнал EOI, аппаратные средства будут по-прежнему удерживать сигнал прерывания в активном состоянии. Однако, поскольку контроллер работает в режиме чувствительности по фронту, все последующие прерывания от этого устройства он не увидит.
Что же это за добрый парень, который так пишет ISR, чтобы тот забыл очистить источник прерывания? К сожалению, готовых рецептов здесь нет. Представьте себе ситуацию, когда два устройства (например адаптер SCSI и адаптер Ethernet), разделяющих одну и ту же линию прерывания на позволяющей это шине. (Сейчас вы скажете: «Да ну, какой придурок будет так делать?!» Ну, это иногда случается, особенно когда не хватает свободных прерываний...)
В этом случае одному и тому же вектору прерывания соответствовали бы два ISR (это, кстати, допустимо), и ядро при получении прерывания по этой линии вызывало бы их каждый раз поочередно.
Разделяемые прерывания без перекрытия.
В этом случае, поскольку только одно из аппаратных устройств (плата SCSI) было активно, когда отработал связанный с ним обработчик корректно очистил источник прерывания (этап 2.) Отметьте, что ядро вызывает ISR для платы Ethernet (этап 3) независимо ни от чего — оно просто не знает, какое конкретное устройство требовало обслуживания, поэтому всегда отрабатывает всю цепочку.
А теперь представьте себе другой случай:
Разделяемые прерывания с перекрытием.
Это как раз та самая проблемная ситуация.
Устройство Ethernet запрашивает прерывание первым. Это приводит к тому, что выставляется сигнал прерывания (передний фронт импульса распознается контроллером прерываний), и ядро вызывает первый в очереди обработчик прерывания (драйвер SCSI; этап 1). Обработчик драйвера SCSI смотрит на свои аппаратные средства и говорит: «Не, это не мое. Ладно, забудь» (этап 2). Затем ядро вызывает следующий обработчик прерывания в очереди, соответствующий плате Ethernet (этап 3). Обработчик драйвера Ethernet смотрит на свои аппаратные средства и восклицает: «О! Мои аппаратные средства запросили прерывание! Надо очистить источник». И тут, как назло, как раз в процессе очистки устройство SCSI генерирует прерывание (этап 4).