Чтение онлайн

ЖАНРЫ

Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform

Кёртен Роб

Шрифт:

 /*

* Определить (и очистить) источник прерывания

* чтением регистра идентификации прерывания

 */

 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

Если бы мы должны были переписать вышеприведенную программу с применением функции InterruptAttachEvent, это бы выглядело так:

/*

 * Фрагмент int2.c

*/

#include <stdio.h>

#include <sys/neutrino.h>

#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

#define IIR_LSR 0x06

#define IIR_MASK 0x07

static int base_reg = 0x2f8;

int main(int arcgc, char **argv) {

 int intId; // Идентификатор прерывания

 int iir; // Регистр идентификации

// прерывания

 int serial_msr; // Сохраненное значение

// регистра состояния модема

 int serial_rx; // Сохраненное значение регистра

// приема

 int serial_lsr; // Сохраненное значение

// регистра состояния линии

 struct sigevent event;

 // Обычная настройка main...

 // Настроить событие

 intId = InterruptAttachEvent(HW_SERIAL_IRQ, &event, 0);

 for (;;) {

// Ждать события от прерывания

// (можно было использовать MsgReceive)

InterruptWait(0, NULL);

/*

* Определить (и очистить) источник прерывания

* чтением регистра идентификации прерывания

*/

iir = in8(base_reg + REG_II) & IIR_MASK;

// Демаскировать прерывание, чтобы оно

// могло сработать снова

InterruptUnmask(HW_SERIAL_IRQ, intId);

/* Нет прерывания? */

if (iir & 1) {

/* Ждать нового */

continue;

}

Поделиться с друзьями: