Подключить обработчик прерывания
#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 );
NULL
, если такая область не нужна.0
, если область NULL
. InterruptAttach() игнорирует этот аргумент.libc
Системные вызовы InterruptAttach() и InterruptAttach_r() подключают обработчик прерывания handler к аппаратному прерыванию intr. Прерывание при этом автоматически включается (размаскируется).
Функции идентичны за исключением способа возврата ошибок.
Перед вызовом любой из этих функций поток должен запросить привилегии ввода-вывода, вызвав:
ThreadCtl( _NTO_TCTL_IO, 0 );
Если поток этого не сделает, будет возвращена ошибка с кодом EPERM
.
В многоядерной системе обработчик прерывания работает на ядре, принимающем прерывание.
Номера векторов прерывания
Номер прерывания intr — логический номер вектора прерывания, обычно соответствующего конкретной линии прерывания процессора. Прерывания сгруппированы в связанные классы прерываний:
_NTO_INTR_SPARE
обычно единственное используемое синтетическое прерывание _NTO_INTR_CLASS_SYNTHETIC
; _NTO_INTR_SPARE
гарантированно не соответствует ни одному допустимому логическому номеру прерывания.
Могут быть определены дополнительные классы прерываний для определенных процессоров или встраиваемых систем. Распределение прерываний для конкретных систем см. в примерах файлов построения ${KPDA_TARGET}/${PROCESSOR}/boot/build.
Прерывания и стартовый модуль (startup)
Распределение логических номеров векторов прерываний полностью зависит от реализации стартового модуля ( startup).
Драйверы устройств должны следовать следующим рекомендациям:
unsigned int
; не предполагать, что номер прерывания помещается в байт. Типичные номера векторов прерываний 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 | Вторичный дисковый контроллер |
Распределение прерываний для других систем отличается. |
Функция обработчика прерываний
Функция обработчика задаётся аргументом handler. Эта функция работает в окружении процесса, аргументы area и size задают область данных для обмена с процессом. Обычно это структура, содержащая буферы и информацию, необходимую обработчику handler и процессу во время работы.
Аргумент area может быть NULL , если область данных не требуется. Если area - NULL , размер size должен быть равен 0 . |
Прототип функции-обработчика handler:
const struct sigevent * handler( void *area, int id );
Где area — это указатель на area, заданную вызовом InterruptAttach(), а id — это идентификатор, возвращаемый InterruptAttach().
При написании обработчика придерживайтесь следующих рекомендаций:
200
байт стека.
volatile
и изменяться с отключенными прерываниями или с использованием функций atomic*() в любом потоке и обработчике прерывания.
Обработчик может вызывать функцию TraceEvent(), но не все её команды допустимы.
Возвращаемое значение функции-обработчика handler должно быть NULL
или указателем на событие struct sigevent, доставляемое ядром. События определены в <signal.h>
.
При выборе типа события учитывайте следующее:
SIGEV_PULSE
для срабатывания отправки пульса.
SIGEV_INTR
в качестве типа события и InterruptWait() в качестве блокирующего вызова.
SIGEV_SIGNAL
, SIGEV_SIGNAL_CODE
, SIGEV_SIGNAL_THREAD
или SIGEV_THREAD
не рекомендуется. Это менее эффективно, чем другие механизмы доставки событий. Флаги
Аргумент flags представляет собой либо 0
, либо побитовое ИЛИ следующих значений:
Поместить новый обработчик в конец списка существующих обработчиков (для разделяемых прерываний) вместо начала.
Аппаратное прерывание может быть разделяемым (один номер прерывания для нескольких устройств). Например, если два процесса берут на себя обработку одного и того же физического прерывания, оба обработчика вызываются последовательно. Когда подключается новый обработчик, он помещается перед любыми существующими обработчиками для этого прерывания и вызывается первым. Можно изменить это поведение, установив флаг _NTO_INTR_FLAGS_END
в аргументе flags, в таком случае обработчик будет добавлен в конец списка после всех существующих обработчиков. Хотя микроядро допускает разделяемые прерывания, оборудование может не поддерживать этого. Например, шина ISA не поддерживает совместное использование прерываний, шина PCI поддерживает.
Во время выполнения обработчика другие прерывания процессора разрешены. Не пытайтесь самостоятельно управлять контроллером прерываний, операционная система сама обработает завершение выполнения всех обработчиков для данного прерывания.
Первый процесс, подключившийся к прерыванию, размаскирует прерывание. Когда последний процесс отключается от прерывания, система маскирует его.
Если поток, подключивший обработчик прерывания, завершается не отсоединив обработчик, ядро делает это автоматически.
Связать обработчик с процессом, а не потоком.
Добавление _NTO_INTR_FLAGS_PROCESS к флагам flags связывает обработчик прерывания с процессом, а не потоком. Обработчик прерывания удаляется при выходе из процесса, вместо потока.
Отслеживать количество вызовов InterruptMask() и InterruptUnmask(), чтобы сделать отключение обработчика прерываний более безопасным.
Флаг _NTO_INTR_FLAGS_TRK_MSK
и аргумент id для InterruptMask() и InterruptUnmask() указывают ядру отслеживать, сколько раз было замаскировано конкретное прерывание. Затем, когда происходит отключение от прерывания, ядро выполняет необходимое количество размаскирований, чтобы гарантировать нормальную работу прерывания. Это важно для разделяемых прерываний.
Следует всегда устанавливать _NTO_INTR_FLAGS_TRK_MSK . |
Данный вызов неблокирующий.
-1
, код ошибки записывается в errno.Используйте полученный идентификатор в качестве аргумента функции InterruptDetach(), чтобы отключить обработчик прерывания.
ЗОСРВ «Нейтрино»
Если в менеджере ресурсов функции 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 системной библиотеки