/proc/interrupts
Файловая система procfs — это виртуальная файловая система, которая существует только в памяти ядра и обычно монтируется на каталог /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 реализовано семейство интерфейсов для управления состояниями прерываний в машине. Эти интерфейсы позволяют запрещать прерывания для текущего процессора или маскировать линию прерывания для всей машины. Эти функции очень сильно зависят от аппаратной платформы и находятся в файлах <asm/system.h>
и <asm/irq.h>
. В табл. 6.2 приведен полный список этих интерфейсов.
Причины, по которым необходимо управлять системой обработки прерываний, в основном, сводятся к необходимости обеспечения синхронизации. Путем запрещения прерываний можно гарантировать, что обработчик прерывания не вытеснит текущий исполняемый код. Более того, запрещение прерываний также запрещает и вытеснение кода ядра. Однако ни запрещение доставки прерываний, ни запрещение преемптивности ядра не дают никакой защиты от конкурентного обращения других процессоров. Так как операционная система Linux поддерживает многопроцессорные системы, в большинстве случаев код ядра должен захватить некоторую блокировку, чтобы предотвратить доступ другого процессора к совместно используемым данным. Эти блокировки обычно захватываются в комбинации с запрещением прерываний на текущем процессоре. Блокировка предоставляет защиту от доступа другого процессора, а запрещение прерываний обеспечивает защиту от конкурентного доступа из возможного обработчика прерывания. В главах 8 и 9 обсуждаются различные аспекты проблем синхронизации и решения этих проблем.
Тем не менее понимание интерфейсов ядра для управления прерываниями является важным.
Запрещение и разрешение прерываний
Для локального запрещения прерываний на текущем процессоре (и только на текущем процессоре) и последующего разрешения можно использовать следующий код.
local_irq_disable();
/* прерывания запрещены ... */
local_irq_enable();
Эти функции обычно реализуются в виде одной инструкции на языке ассемблера (что, конечно, зависит от аппаратной платформы). Для платформы x86 функция local_irq_disable()
— это просто машинная инструкция cli
, а функция local_irq_enable()
— просто инструкция sti
. Для хакеров, не знакомых с платформой x86, sti
и cli
— это ассемблерные вызовы, которые соответственно позволяют установить (set) или очистить (clear) флаг разрешения прерываний (allow interrupt flag). Другими словами, они разрешают или запрещают доставку прерываний на вызвавшем их процессоре.
Функция local_irq_disable()
является опасной в случае, когда перед ее вызовом прерывания уже были запрещены. При этом соответствующий ей вызов функции local_irq_enable()
разрешит прерывания независимо от того, были они запрещены первоначально (до вызова local_irq_disable()
) или нет. Для того чтобы избежать такой ситуации, необходим механизм, который позволяет восстанавливать состояние системы обработки прерывании в первоначальное значение. Это требование имеет общий характер, потому что некоторый участок кода ядра в одном случае может выполняться при разрешенных прерываниях, а в другом случае— при запрещенных, в зависимости от последовательности вызовов функций. Например, пусть показанный фрагмент кода является частью функции. Эта функция вызывается двумя другими функциями, и в первом случае перед вызовом прерывания запрещаются, а во втором — нет. Так как при увеличении объема кода ядра становится сложно отслеживать все возможные варианты вызова функции, значительно безопаснее сохранять состояние системы прерываний перед тем, как запрещать прерывания. Вместо разрешения прерываний просто восстанавливается первоначальное состояние системы обработки прерываний следующим образом.
unsigned long flags;
local_irq_save(flags);
/* прерывания запрещены . . */
local_irq_restore(flags);
/* состояние системы прерываний восстановлено
в первоначальное значение ... */
Нужно заметить, что эти функции являются макросами, поэтому передача параметра flags
выглядит как передача по значению. Этот параметр содержит зависящие от аппаратной платформы данные, которые в свою очередь содержат состояние системы прерываний. Так как, по крайней мере для одной аппаратной платформы (SPARC), в этой переменной хранится информация о стеке, то параметр flags
нельзя передавать в другие функции (другими словами, он должен оставаться в одном и том же стековом фрейме). По этой причине вызовы функций сохранения и восстановления должны выполняться в теле одной функции.
Все описанные функции могут вызываться как из обработчика прерываний, так и из контекста процесса.
cli()
32
После прочтения главы 10, "Таймеры и управление временем", можно ли сказать, сколько времени (в единицах HZ) машина работала без перегрузки исходя из числа прерываний таймера?