Для платформы x86, подпрограммы, написанные на языке ассемблера, находятся в файле arch/i386/kernel/entry.S
, а соответствующие функции на языке С — в файле arch/i386/kernel/irq.с
. Для других поддерживаемых аппаратных платформ имеются аналогичные файлы.
/proc/interrupts
Файловая система /proc
. Чтение или запись файлов на файловой системе procfs приводит к вызовам функций ядра, которые имитируют чтение или запись обычных файлов. Важный пример — это файл /proc/interrupts
, который содержит статистику, связанную с прерываниями в системе, Ниже приведен пример вывода из этого файла на однопроцессорном персональном компьютере.
CPU0
0: 3602371 XT-PIC timer
1: 3048 XT-PIC i8042
2: 0 XT-PIC cascade
4: 2689466 XT-PIC uhci-hcd, eth0
5: 0 XT-PIC EMU10K1
12: 85077 XT-PIC uhci-hcd
15: 24571 XT-PIC aic7xxx
NMI: 0
LOC: 3602236
ERR: 0
Первая колонка содержит названия линий прерывания. В показанной системе присутствуют линии прерываний с номерами 0–2, 4, 5, 12 и 15. Линии, для которых не инсталлирован обработчик, не показываются. Вторая колонка — это количество запросов на прерывания с данным номером. В действительности такая колонка является отдельной для каждого процессора, но в данной машине только один процессор.
Как легко видеть, обработчик прерываний таймера получил 3.602.371
[32] запрос на прерывание, в то время как обработчик прерываний звукового адаптера (EMU10K1
) не получил ни одного прерывания (это говорит о том, что он не использовался с того момента, как машина была загружена). Третья колонка— это контроллер прерываний, который обслуживает данное прерывание. Значение XT-PIC
соответствует программируемому контроллеру прерываний PC (PC programmable interrupt controller). Для систем с устройством I/О APIC для большинства прерываний в качестве контроллера прерываний будет указано значение IO-APIC-level
или IO-APIC-edge
. И наконец, последняя колонка — это устройство, которое связано с прерыванием. Имя устройства указывается в параметре dev_name
при вызове функции request_irq()
, как обсуждалось ранее. Если прерывание используется совместно, как в случае прерывания номер 4 в этом примере, то перечисляются все устройства, зарегистрированные на данной линии прерывания.
Для любопытствующих, код, связанный с файловой системой procfs
, находится в файле fs/proc
. Функция, которая обеспечивает работу интерфейса /proc/interrupts
, называется show_interrupts()
и является зависимой от аппаратной платформы.
Управление прерываниями
В ядре Linux реализовано семейство интерфейсов для управления состояниями прерываний в машине. Эти интерфейсы позволяют запрещать прерывания для текущего процессора или маскировать линию прерывания для всей машины. Эти функции очень сильно зависят от аппаратной платформы и находятся в файлах
и
. В табл. 6.2 приведен полный список этих интерфейсов.
Причины, по которым необходимо управлять системой обработки прерываний, в основном, сводятся к необходимости обеспечения синхронизации. Путем запрещения прерываний можно гарантировать, что обработчик прерывания не вытеснит текущий исполняемый код. Более того, запрещение прерываний также запрещает и вытеснение кода ядра. Однако ни запрещение доставки прерываний, ни запрещение преемптивности ядра не дают никакой защиты от конкурентного обращения других процессоров. Так как операционная система Linux поддерживает многопроцессорные системы, в большинстве случаев код ядра должен захватить некоторую блокировку, чтобы предотвратить доступ другого процессора к совместно используемым данным. Эти блокировки обычно захватываются в комбинации с запрещением прерываний на текущем процессоре. Блокировка предоставляет защиту от доступа другого процессора, а запрещение прерываний обеспечивает защиту от конкурентного доступа из возможного обработчика прерывания. В главах 8 и 9 обсуждаются различные аспекты проблем синхронизации и решения этих проблем.
Тем не менее понимание интерфейсов ядра для управления прерываниями является важным.
Запрещение и разрешение прерываний
Для локального запрещения прерываний на текущем процессоре (и
local_irq_disable();
/* прерывания запрещены ... */
local_irq_enable();