Ядро Linux в комментариях

Нижние половины


Нижняя половина обработчика прерывания — та его часть, которую не нужно выполнять немедленно. Для некоторых прерываний может вообще не потребоваться ее выполнять.

Следует отметить, что каждый обработчик прерывания делится на верхнюю и нижнюю половины; верхняя половина вычислений выполняется немедленно в момент прерывания, в то время как нижняя половина (если она существует) откладывается. Это достигается путем реализации верхней и нижней половины отдельными функциями и путем различной их обработки. В целом, верхняя половина принимает решение о необходимости выполнения нижней половины. Очевидно, что все что не может быть отложено, не входит в нижнюю половину, но все, что может быть отложено, является кандидатом для включения в нее.

Читателей может интересовать вопрос, почему Linux утруждает себя этим разделением — зачем нужна эта задержка? Одной из причин является стремление минимизировать общую продолжительность прерываний. Ядро Linux определяет два вида прерываний: быстрый и медленный, и одно из различий между ними состоит в том, что медленные прерывания сами могут быть прерваны, а быстрые — нет. Следовательно, во время обработки быстрых прерываний все остальные поступающие прерывания — как медленные, так и быстрые — должны просто дожидаться своей очереди. Чтобы обработать эти прерывания как можно раньше, ядро откладывает как можно больше вычислений в нижние половины.

Другая причина заключается в том, что на самом нижнем уровне чипу контроллера прерываний указывается отключать конкретный IRQ, подлежащий обработке, пока ядро выполняет верхнюю половину (Это отличается от отключения на уровне центрального процессора, которое не различает быстрые и медленные прерывания). Нежелательно, чтобы эта ситуация продолжалась дольше, чем необходимо, поэтому только наиболее критичная в смысле времени часть выполняется в верхней половине, а все остальное переносится в нижнюю половину.

Еще она причина разделения верхней и нижней половин в том, что нижняя половина обработчика состоит из процедур, которые не обязательно должны выполняться для каждого отдельного прерывания, а только тогда, когда ядро доберется до них в определенный момент после выполнения каждого пакета прерываний, поступающего от устройства. В подобном случае выполнение нижней половины обработки для каждого прерывания, в то время, как она может быть отложена на некоторое время и затем выполнена только один раз — явное расточительство.


Следует упомянуть об одном выводе, вытекающем из предшествующего абзаца: нижняя половина не обязательно вызывается один раз для каждого прерывания. Вместо этого, верхняя половина (или, иногда, какая-либо другая часть кода) просто «помечает» нижнюю половину, устанавливая разряд, который указывает на необходимость выполнения нижней половины. Если нижняя половина помечается снова, будучи уже помеченной, она просто остается такой; ядро обслуживает ее, когда может это сделать. Если для данного устройства 100 прерываний произойдут прежде, чем ядро получит возможность выполнить нижнюю половину, верхняя половина будет выполнена 100 раз, а нижняя — 1 раз.

Иногда нижние половины называются в ядре «мягкими IRQ» или «обработчиками мягких прерываний», что помогает пояснить некоторые имена файлов и другие термины, с которыми вы встретитесь.

В остальной части этого раздела представление о нижних половинах останется достаточно абстрактным. В следующем разделе прерывание таймера исследуется несколько глубже, включая обработку его нижней половины; кроме того в ней показано интересное неверное употребление — имеется в виду интересное обобщение — представления о нижних половинах.


Содержание раздела