Введение в QNX/Neutrino 2. Руководство по программированию приложений реального времени в QNX Realtime Platform
Шрифт:
• InterruptMask;
• InterruptUnmask;
• InterruptLock;
• InterruptUnlock;
• InterruptDisable;
• InterruptEnable;
• in* и out*.
Основное эмпирическое правило формулируется примерно так: «Не используйте ничего, что требует большого объема стека или больших затрат времени, и не используйте ничего, что делает системные вызовы». Требование по стековому пространству проистекает из того факта, что ISR имеют очень ограниченный
Список функций, безопасных для применения в 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
Не используйте эти функции в новых проектах. Исторически, эти функции применялись для вызова инструкций
С тех пор функции были модернизированы для работы со всеми типами процессоров, но чтобы не огорчать SMP-системы, используйте лучше функции InterruptLock и InterruptUnlock.
Еще
Резюме
При работе с прерываниями принимайте во внимание следующие положения:
• Не оставайтесь в обработчике прерывания слишком долго — выполняйте в нем минимальный объем работы. Это поможет сократить время реакции на прерывание и упростить отладку.
• Применяйте функцию InterruptAttach только тогда, когда нужно обращаться к аппаратным средствам непосредственно после прерывания, в противном случае избегайте ее.
• Применяйте функцию InterruptAttachEvent во всех других случаях. Ядро запланирует поток (на основе события, которое вы передадите) для обработки возникшего прерывания.
• Защищайте переменные, используемые как в обработчиках прерываний (при использовании InterruptAttach), так и в потоках, путем вызова InterruptLock и InterruptUnlock.
• Объявляйте переменные, используемые в качестве посредников между потоками и обработчиками прерывании, как
Глава 5
Администраторы ресурсов
Что такое администратор ресурсов?
В данной главе мы рассмотрим все, что вы должны знать для самостоятельного написания администратора ресурса.
Администратор ресурса — это просто программа с рядом четко определенных характеристик. Эта программа по-разному называется в различных операционных системах — «драйвер», «устройство», «драйвер устройства», «администратор ввода/вывода», «файловая система», и т.п. Однако, во всех случаях предназначение этой программы (мы будем называть ее просто «администратором ресурса») заключается в том, чтобы предоставить абстрактную форму некоего сервиса.
Также, поскольку QNX/Neutrino является POSIX-совместимой ОС, основу предоставляемой абстракции составляют спецификации POSIX.
Примеры администраторов ресурсов
Прежде чем уйти в тонкости проблемы, давайте проанализируем пару примеров и увидим, как в них «абстрагируются» сервисы. Рассмотрим реальный аппаратный блок (последовательный порт) и кое-что более абстрактное (файловую систему).
В типовой системе обычно существует какой-нибудь способ программирования обмена информацией по последовательному интерфейсу типа RS-232. Этот интерфейс составляют ряд аппаратных устройств, включая микросхему UART (Universal Asynchronous Receiver Transmitter — универсальный асинхронный приемопередатчик), которая умеет преобразовывать параллельные данные от центрального процессора в последовательный поток и обратно.
В этом случае сервисом, предоставляемым соответствующим администратором ресурса, будет возможность передачи и приема символьных данных через последовательный порт.
Мы говорим, что имеет место «абстрагирование» сервиса, потому что клиентская программа (та, которая непосредственно использует сервис) не знает (да и незачем ей) о микросхеме UART и ее реализации. Все, что знает клиентская программа, — что для передачи символа она должна вызвать функцию fprintf а для приема символов — функцию fgets. Обратите внимание, что взаимодействия с последовательным портом мы использовали стандартные функции POSIX.