Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Название:Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
- Автор:
- Жанр:
- Издательство:Петрополис
- Год:2001
- Город:Санкт-Петербург
- ISBN:5-94656-025-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роб Кёртен - Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform краткое содержание
Книга "Введение в QNX/Neutrino 2» откроет перед вами в мельчайших подробностях все секреты ОСРВ нового поколения от компании QNX Software Systems Ltd (QSSL) — QNX/Neutrino 2. Книга написана в непринужденной манере, легким для чтения и понимания стилем, и поможет любому, от начинающих программистов до опытных системотехников, получить необходимые начальные знания для проектирования надежных систем реального времени, от встраиваемых управляющих приложений до распределенных сетевых вычислительных систем
В книге подробно описаны основные составляющие ОС QNX/Neutrino и их взаимосвязи. В частности, уделено особое внимание следующим темам:
• обмен сообщениями: принципы функционирования и основы применения;
• процессы и потоки: базовые концепции, предостережения и рекомендации;
• таймеры: организация периодических событий в программах;
• администраторы ресурсов: все, что относится к программированию драйверов устройств;
• прерывания: рекомендации по эффективной обработке.
В книге представлено множество проверенных примеров кода, подробных разъяснений и рисунков, которые помогут вам детально вникнуть в и излагаемый материал. Примеры кода и обновления к ним также можно найти на веб-сайте автора данной книги, www.parse.com.
Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Когда вы закончили с обработчиком прерывания, вы можете пожелать уничтожить связь между ним и вектором:
int InterruptDetach(int id);
Я сказал «можете», потому что обрабатывающие прерывания потоки, как правило, используются в серверах, а серверы обычно не завершаются. Это часто ведет к предрассудку, что хорошо организованному серверу никогда не понадобится самостоятельно вызывать InterruptDetach() . К тому же, при смерти потока или процесса ОС автоматически отключит все связанные с ним обработчики прерываний. Таким образом, если программа просто дойдет до конца main() , вызовет exit() или завершится по SIGSEGV, все ее ISR будут автоматически отключены от соответствующих векторов прерываний. (Впрочем, вы, вероятно, пожелаете сделать это несколько изящнее, запретив соответствующему устройству генерацию прерываний. Если же прерывание разделяемое, и его используют другие устройства, то здесь двух вариантов быть не может вообще — вы просто обязаны «убрать за собой», иначе у вас либо больше не будет прерываний (в режиме чувствительности по фронту), либо пойдет постоянный поток запросов на прерывание (в режиме чувствительности по уровню).
Продолжая вышеприведенный пример, если бы мы захотели отключиться от прерывания, то мы использовали бы следующий код:
void terminateInterrupts(void) {
InterruptDetach(interruptID);
}
Если это последний ISR, связанный с данным вектором прерывания, то ядро автоматически произведет маскирование источника прерывания на уровне контроллера, чтобы таких прерываний больше не возникало.
Параметр flags
Последний параметр, flags , управляет различными дополнительными опциями:
_NTO_INTR_FLAGS_END
Указывает, что данный обработчик должен сработать после всех других обработчиков данного прерывания (если они есть).
_NTO_INTR_FLAGS_PROCESS
Указывает на то, что данный обработчик связан с процессом, а не с потоком. Что из этого вытекает, так это условие автоматического отключения обработчика. Если вы определяете этот флаг, обработчик будет автоматически отключен от источника прерывания при завершении процесса. Если этот флаг не определен, обработчик прерывания будет отключен от источника, когда завершится поток, подключивший его.
_NTO_INTR_FLAGS_TRK_MSK
Указывает, что ядро должно отследить, сколько раз данное прерывание было маскировано. Это приводит к несколько большей загрузке ядра, но это необходимо для корректного демаскирования источника прерываний при завершении потока или процесса.
Обработчик прерывания
Давайте рассмотрим собственно обработчик прерывания. В первом примере применим InterruptAttach() , а затем рассмотрим аналогичный случай, только с применением функции InterruptAttachEvent() .
В продолжение примера приведем функцию intHandler() — наш обработчик прерывания. Она отвечает за микросхему последовательного порта 8250 (допустим, что она генерирует прерывание HW_SERIAL_IRQ).
/*
* int1.c
*/
#include
#include
#define REG_RX 0
#define REG_II 2
#define REG_LS 5
#define REG_MS 6
#define IIR_MASK 0x07
#define IIR_MSR 0x00
#define IIR_THE 0x02
#define IIR_RX 0x04
#define IIR_LSR 0x06
#define IIR_MASK 0x07
volatile int serial_msr; // Сохраненное значение
// регистра состояния модема
volatile int serial_rx; // Сохраненное значение
// регистра приема
volatile int serial_lsr; // Сохраненное значение
// регистра состояния линии
static int base_reg = 0x2f8;
const struct sigevent* intHandler(void *arg, int id) {
int iir;
struct sigevent *event = (struct sigevent*)arg;
/*
* Определить (и очистить) источник прерывания
* чтением регистра идентификации прерывания
*/
iir = in8(base_reg + REG_II) & IIR_MASK;
/* Нет прерывания? */
if (iir & 1) {
/* Значит, нет и события */
return (NULL);
}
/*
* Выяснить, что вызвало прерывание, и определить, надо ли
* потоку что-нибудь с этим делать.
* (Константы основаны на строении регистра
* идентификации прерывания 8250.)
*/
switch (iir) {
case IIR_MSR:
serial_msr = in8(base_reg + REG_MS);
/* Разбудить поток */
return (event);
break;
case IIR_THE:
/* Ничего не делать */
break;
case IIR_RX:
/* Считать символ */
serial_rx = in8(base_reg + REG_RX);
break;
case IIR_LSR:
/* Сохранить регистр состояния линии */
serial_lsr = in8(base_reg + REG_LS);
break;
default:
break;
}
/* Никого не беспокоить */
return (NULL);
}
Первое, что бросается в глаза, — что все переменные, к которым обращается ISR, должны быть объявлены как volatile
. В с единственным процессором это делается не для блага обработчиков прерываний, а для облегчения жизни потокам, которые могут быть прерваны обработчиком прерывания в любой момент. Конечно, в многопроцессорной ЭВМ обработчики прерываний вполне могли бы выполняться одновременно с кодом потоков, и в таких случаях надо быть предельно осторожными с вещами подобного рода.
С помощью ключевого слова volatile
мы указываем компилятору не кэшировать значения этих переменных, поскольку они могут быть изменены в любой точке выполнения программы.
Следующее, на что мы обращаем внимание — это прототип самого обработчика прерывания. Он обозначен как const struct sigevent*
. Это говорит о том, что подпрограмма intHandler() возвращает указатель на struct sigevent
. Это стандарт для всех подпрограмм обработки прерываний.
Наконец, обратите внимание на то, что решение, передавать или не передавать событие потоку, принимает сам обработчик. Здесь мы генерируем событие только в случае прерывания по изменению регистра состояния модема (MSR) (событие определяется переменной event , которая передается обработчику прерывания в момент его подключения). Во всех других случаях мы игнорируем прерывание (и обновляем кое-какие глобальные переменные); однако, источник прерывания мы очищаем во всех случаях. Это выполняется считыванием порта ввода/вывода с помощью вызова in8() .
Если бы мы должны были переписать вышеприведенную программу с применением функции InterruptAttachEvent() , это бы выглядело так:
/*
* Фрагмент int2.c
*/
#include
#include
#define HW_SERIAL_IRQ 3
#define REG_RX 0
#define REG_II 2
#define REG_LS 5
#define REG_MS 6
#define IIR_MASK 0x07
#define IIR_MSR 0x00
#define IIR_THE 0x02
#define IIR_RX 0x04
Интервал:
Закладка: