InterruptAttach(), InterruptAttach_r()

Подключить обработчик прерывания

Прототип:

#include <sys/neutrino.h>
int InterruptAttach( int intr,
const struct sigevent * (*handler)( void *, int ),
const void *area,
int size,
unsigned flags );
int InterruptAttach_r( int intr,
const struct sigevent * (*handler)( void *, int ),
const void *area,
int size,
unsigned flags );

Аргументы:

intr
Номер прерывания к которому необходимо подключить обработчик; см. “Номера векторов прерывания”.
handler
Указатель на функцию-обработчик; см. “Функция обработчика прерываний”.
area
Указатель на область данных для обмена с основным процессом или NULL, если такая область не нужна.
size
Размер области данных; должен быть 0, если область NULL. InterruptAttach() игнорирует этот аргумент.
flags
Флаги, указывающие каким образом требуется подключить обработчик прерывания. См. “Флаги”.

Библиотека:

libc

Описание:

Системные вызовы InterruptAttach() и InterruptAttach_r() подключают обработчик прерывания handler к аппаратному прерыванию intr. Прерывание при этом автоматически включается (размаскируется).

Функции идентичны за исключением способа возврата ошибок.

Перед вызовом любой из этих функций поток должен запросить привилегии ввода-вывода, вызвав:

ThreadCtl( _NTO_TCTL_IO, 0 );

Если поток этого не сделает, будет возвращена ошибка с кодом EPERM.

В многоядерной системе обработчик прерывания работает на ядре, принимающем прерывание.

Номера векторов прерывания

Номер прерывания intr — логический номер вектора прерывания, обычно соответствующего конкретной линии прерывания процессора. Прерывания сгруппированы в связанные классы прерываний:

_NTO_INTR_CLASS_EXTERNAL
Обычные внешние прерывания, например, генерируемые выводом INTR на процессорах x86.
_NTO_INTR_CLASS_SYNTHETIC
Синтетические прерывания, генерируемые ядром.

_NTO_INTR_SPARE обычно единственное используемое синтетическое прерывание _NTO_INTR_CLASS_SYNTHETIC; _NTO_INTR_SPARE гарантированно не соответствует ни одному допустимому логическому номеру прерывания.

Могут быть определены дополнительные классы прерываний для определенных процессоров или встраиваемых систем. Распределение прерываний для конкретных систем см. в примерах файлов построения ${KPDA_TARGET}/${PROCESSOR}/boot/build.

Прерывания и стартовый модуль (startup)

Распределение логических номеров векторов прерываний полностью зависит от реализации стартового модуля ( startup).

Драйверы устройств должны следовать следующим рекомендациям:

Типичные номера векторов прерываний x86

Пример типичного списка распределения 16 аппаратных прерываний для ПК с архитектурой x86 при использовании startup-bios:

Прерывание intr Описание
0 Системный таймер, частота устанавливается ClockPeriod()
1 Клавиатура
2 Slave 8259 — к этому прерыванию нельзя подключиться.
3 COM2
4 COM1
5 Сетевая карта/звуковая карта/другое
6 Дисковод
7 Принтер с подключением по параллельному порту/звуковая карта/другое
8
9 Перераспределённое прерывание 2
10
11
12
13 Сопроцессор
14 Первичный дисковый контроллер
15 Вторичный дисковый контроллер


Note: Распределение прерываний для других систем отличается.

Функция обработчика прерываний

Функция обработчика задаётся аргументом handler. Эта функция работает в окружении процесса, аргументы area и size задают область данных для обмена с процессом. Обычно это структура, содержащая буферы и информацию, необходимую обработчику handler и процессу во время работы.


Note: Аргумент area может быть NULL, если область данных не требуется. Если area - NULL, размер size должен быть равен 0.

Прототип функции-обработчика handler:

const struct sigevent * handler( void *area, int id );

Где area — это указатель на area, заданную вызовом InterruptAttach(), а id — это идентификатор, возвращаемый InterruptAttach().

При написании обработчика придерживайтесь следующих рекомендаций:

Возвращаемое значение функции-обработчика handler должно быть NULL или указателем на событие struct sigevent, доставляемое ядром. События определены в <signal.h>.

При выборе типа события учитывайте следующее:

Флаги

Аргумент flags представляет собой либо 0, либо побитовое ИЛИ следующих значений:

_NTO_INTR_FLAGS_END
_NTO_INTR_FLAGS_PROCESS
_NTO_INTR_FLAGS_TRK_MSK

_NTO_INTR_FLAGS_END

Поместить новый обработчик в конец списка существующих обработчиков (для разделяемых прерываний) вместо начала.

Аппаратное прерывание может быть разделяемым (один номер прерывания для нескольких устройств). Например, если два процесса берут на себя обработку одного и того же физического прерывания, оба обработчика вызываются последовательно. Когда подключается новый обработчик, он помещается перед любыми существующими обработчиками для этого прерывания и вызывается первым. Можно изменить это поведение, установив флаг _NTO_INTR_FLAGS_END в аргументе flags, в таком случае обработчик будет добавлен в конец списка после всех существующих обработчиков. Хотя микроядро допускает разделяемые прерывания, оборудование может не поддерживать этого. Например, шина ISA не поддерживает совместное использование прерываний, шина PCI поддерживает.

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

Первый процесс, подключившийся к прерыванию, размаскирует прерывание. Когда последний процесс отключается от прерывания, система маскирует его.

Если поток, подключивший обработчик прерывания, завершается не отсоединив обработчик, ядро делает это автоматически.

_NTO_INTR_FLAGS_PROCESS

Связать обработчик с процессом, а не потоком.

Добавление _NTO_INTR_FLAGS_PROCESS к флагам flags связывает обработчик прерывания с процессом, а не потоком. Обработчик прерывания удаляется при выходе из процесса, вместо потока.

_NTO_INTR_FLAGS_TRK_MSK

Отслеживать количество вызовов InterruptMask() и InterruptUnmask(), чтобы сделать отключение обработчика прерываний более безопасным.

Флаг _NTO_INTR_FLAGS_TRK_MSK и аргумент id для InterruptMask() и InterruptUnmask() указывают ядру отслеживать, сколько раз было замаскировано конкретное прерывание. Затем, когда происходит отключение от прерывания, ядро выполняет необходимое количество размаскирований, чтобы гарантировать нормальную работу прерывания. Это важно для разделяемых прерываний.


Note: Следует всегда устанавливать _NTO_INTR_FLAGS_TRK_MSK.

Состояния блокировки:

Данный вызов неблокирующий.

Возвращаемое значение:

Возвращаемое значение:

InterruptAttach()
Идентификатор обработчика прерываний. Если возникла ошибка, функция возвращает -1, код ошибки записывается в errno.
InterruptAttach_r()
Идентификатор обработчика прерываний. Функция НЕ устанавливает errno. При возникновении ошибки функция возвращает один из перечисленных ниже кодов.

Используйте полученный идентификатор в качестве аргумента функции InterruptDetach(), чтобы отключить обработчик прерывания.

Коды ошибок:

EAGAIN
Использованы все записи ядра о прерываниях.
EFAULT
Ошибка при попытке ядра обратиться к предоставленным буферам.
EINVAL
Недопустимый номер прерывания intr.
EPERM
У процесса нет привилегий ввода-вывода.

Классификация:

ЗОСРВ «Нейтрино»

Безопасность использования
Точка остановки потока
Нет
Обработчик прерываний
Нет
Обработчик сигналов
Да
В потоке
Да

Предостережения:

Если в менеджере ресурсов функции resmgr_*() используются в нескольких потоках, подключающийся к прерыванию поток должен использовать флаг _NTO_INTR_FLAGS_PROCESS в аргументе flags при вызове InterruptAttach().

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

ThreadCtl( _NTO_TCTL_RUNMASK, ... );

Тематические ссылки:

atomic_add(), atomic_clr(), atomic_set(), atomic_sub(), atomic_toggle(), InterruptAttachEvent(), InterruptDetach(), InterruptDisable(), InterruptEnable(), InterruptLock(), InterruptMask(), InterruptUnlock(), InterruptUnmask(), InterruptWait(), mlock(), struct sigevent, ThreadCtl(), TraceEvent()




Предыдущий раздел: Описание API системной библиотеки