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

ЖАНРЫ

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

Кёртен Роб

Шрифт:

Список функций, безопасных для применения в ISR, имеет реальный смысл — например, если вам потребуется скопировать область памяти, хорошим выбором будет применение функций типа mem* и str*. Скорее всего, вам потребуется читать регистры аппаратных средств (например, чтобы сохранить какие-либо значения или очистить источник прерывания), тогда вам пригодятся функции ввода/вывода из семейств in* и out*.

А как насчет ошарашивающего выбора функций семейства Interrupt*? Давайте рассмотрим их попарно.

InterruptMask и InterruptUnmask

Эти функции ответственны за маскирование источника прерывания на уровне контроллера; это предохраняет прерывания

от передачи процессору. Обычно эти функции применяются, когда вы хотите доделать работу в потоке, но не можете очистить источник прерывании непосредственно в теле ISR. В этом случае ISR должен вызвать InterruptMask, а поток, после завершения работы, — InterruptUnmask.

Имейте в виду, что число вызовов InterruptUnmask должно соответствовать числу вызовов InterruptMask — чтобы прерывание продолжало работать, вы обязаны демаскировать его ровно столько раз, сколько раз оно было маскировано.

Заметьте, между прочим, что функция InterruptAttachEvent выполняет InterruptMask автоматически (в ядре), поэтому ваш обрабатывающий прерывание поток должен вызывать InterruptUnmask.

InterruptLock и InterruptUnlock

Эти функции используются для блокировки (InterruptLock) и деблокировки (InterruptUnlock) прерываний в одно- или многопроцессорной системе. Вам может понадобиться заблокировать прерывания, например, чтобы защитить поток от ISR (или, дополнительно, в SMP-системе — защитить ISR от потока). Когда вы сделаете нужные манипуляции с критическими данными, вы сможете деблокировать прерывания обратно. Отметьте, что данные функции рекомендованы к применению вместо известных вам функций InterruptDisable и InterruptEnable, потому что корректно работают в SMP-системах. По сравнению со «старыми» функциями, проверка на многопроцессорность вносит дополнительные издержки, но в однопроцессорной системе ими можно пренебречь, поэтому я рекомендую вам всегда использовать InterruptLock и InterruptUnlock.

InterruptDisable и InterruptEnable

Не используйте эти функции в новых проектах. Исторически, эти функции применялись для вызова инструкций

cli
и
sti
в процессорах серии x86, когда QNX/Neutrino еще не была многоплатформенной ОС.

С тех пор функции были модернизированы для работы со всеми типами процессоров, но чтобы не огорчать SMP-системы, используйте лучше функции InterruptLock и InterruptUnlock.

Еще одна вещь, которую не вредно будет повторить, заключается в том, что в SMP-системе возможно одновременное выполнение ISR и другого потока.

Резюме

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

• Не оставайтесь в обработчике прерывания слишком долго — выполняйте в нем минимальный объем работы. Это поможет сократить время реакции на прерывание и упростить отладку.

• Применяйте функцию InterruptAttach только тогда, когда нужно обращаться к аппаратным средствам непосредственно после прерывания, в противном случае избегайте ее.

• Применяйте функцию InterruptAttachEvent во всех других случаях. Ядро запланирует поток (на основе события, которое вы передадите) для обработки возникшего прерывания.

• Защищайте переменные, используемые как в обработчиках прерываний (при использовании InterruptAttach), так и в потоках, путем вызова InterruptLock и InterruptUnlock.

• Объявляйте переменные, используемые в качестве посредников между потоками и обработчиками прерывании, как

volatile
, чтобы компилятор не кэшировал их «просроченные» значения, уже измененные обработчиком прерывания.

Глава 5

Администраторы ресурсов

Что

такое администратор ресурсов?

В данной главе мы рассмотрим все, что вы должны знать для самостоятельного написания администратора ресурса.

Администратор ресурса — это просто программа с рядом четко определенных характеристик. Эта программа по-разному называется в различных операционных системах — «драйвер», «устройство», «драйвер устройства», «администратор ввода/вывода», «файловая система», и т.п. Однако, во всех случаях предназначение этой программы (мы будем называть ее просто «администратором ресурса») заключается в том, чтобы предоставить абстрактную форму некоего сервиса.

Также, поскольку QNX/Neutrino является POSIX-совместимой ОС, основу предоставляемой абстракции составляют спецификации POSIX.

Примеры администраторов ресурсов

Прежде чем уйти в тонкости проблемы, давайте проанализируем пару примеров и увидим, как в них «абстрагируются» сервисы. Рассмотрим реальный аппаратный блок (последовательный порт) и кое-что более абстрактное (файловую систему).

Последовательный порт

В типовой системе обычно существует какой-нибудь способ программирования обмена информацией по последовательному интерфейсу типа RS-232. Этот интерфейс составляют ряд аппаратных устройств, включая микросхему UART (Universal Asynchronous Receiver Transmitter — универсальный асинхронный приемопередатчик), которая умеет преобразовывать параллельные данные от центрального процессора в последовательный поток и обратно.

В этом случае сервисом, предоставляемым соответствующим администратором ресурса, будет возможность передачи и приема символьных данных через последовательный порт.

Мы говорим, что имеет место «абстрагирование» сервиса, потому что клиентская программа (та, которая непосредственно использует сервис) не знает (да и незачем ей) о микросхеме UART и ее реализации. Все, что знает клиентская программа, — что для передачи символа она должна вызвать функцию fprintf а для приема символов — функцию fgets. Обратите внимание, что взаимодействия с последовательным портом мы использовали стандартные функции POSIX.

Файловая система

В качестве другого примера администратора ресурса рассмотрим файловую систему. Она состоит из ряда взаимодействующих модулей: собственно файловой системы, драйвера блочного ввода/вывода и дискового драйвера.

Предлагаемый здесь сервис состоит в способности считывать и записывать символы на некоторый носитель. Абстракция здесь та же самая, что и в предыдущем примере с последовательным портом — клиентская программа по-прежнему может использовать те же самые вызовы функций (например, fprintf и fgets) для доступа к носителю. Фактически, клиент действительно не знает или даже не должен знать, с каким конкретно администратором ресурсов он имеет дело.

Характеристики администраторов ресурсов

Как мы увидели в приведенных выше примерах, ключом к универсальности администраторов ресурсов является возможность использования стандартных функций POSIX — мы ведь не использовали никакие «специальные» функции, когда общались с последовательным портом. А если вам понадобится сделать нечто «особенное», характерное только для применяемого вами устройства? Например, операция настройки скорости обмена по последовательному порту в бодах специфична для администратора последовательного порта, но абсолютно бессмысленна для администратора файловой системы. Аналогично, операция по позиционированию в файле с помощью функции lseek имеет смысл для файловой системы, но является несодержательной для последовательного порта. В POSIX эта проблема решается просто. Некоторые функции — например, lseek — при попытке применить их к устройству, которое их не поддерживает, просто возвращают код ошибки. Для реализации функций, специфичных для каждого устройства, в POSIX предусмотрена функция управления устройствами, devctl. Если устройство не понимает команду, передаваемую ему посредством devctl, оно просто возвращают код ошибки, аналогично устройствам, которые не понимают функцию lseek.

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