Прерывание. Прерывания и исключения

§ 3.1.Системаобработкипрерываний

Обладая способностью переключаться от одного потока выполнения к другому,

ядро операционной системы должно к тому же реагировать на прерывания (interrupts) и

исключения (exceptions). Речь идет о сигналах, которые возникают в системе и застав-

ляют процессор прерывать свою работу и переключаться на обработку возникшей си-

туации. Рассмотрим эти два механизма более подробно.

Прерывания представляют собой механизм , позволяющий координировать парал-

лельное функционирование отдельных устройств вычислительной системы и реагиро-

вать на особые состояния, возникающие при работе процессора. Таким образом, преры-

вание-этопринудительнаяпередачауправленияотвыполняемойпрограммык

системе (а через нее - к соответствующей программе обработки прерывания), происхо-

дящая при возникновении определенного события.

Идея прерываний была предложена в середине 50-х годов и можно без преувели-

чения сказать, что она внесла наиболее весомый вклад в развитие вычислительной тех-

ники. Основная цель введения прерываний - реализация асинхронного режима работы и

распараллеливание работы отдельных устройств вычислительного комплекса.

Механизм прерываний реализуется аппаратно-программными средствами. Перво-

начально рассмотрим в общих чертах аппаратную часть системы прерываний. Сигналы

аппаратных прерываний, возникающие в устройствах, входящих в состав компьютера

или подключенных к нему, поступают в процессор не непосредственно, а через два кон-

троллера прерываний, один из которых называется ведущим, а второй ведомым

(рис.3.1). В прежних моделях машин контроллеры представляли собой отдельные мик-

росхемы; в современных компьютерах они входят в состав многофункциональной мик-

росхемы периферийного контроллера.

Рис.3.1. Аппаратная часть системы прерываний.

Два контроллера используются для увеличения допустимого числа внешних уст-

ройств. Дело в том, что каждый контроллер прерываний может обслуживать сигналы

лишь от восьми устройств. Для обслуживания большего количества устройств контрол-

леры можно объединять, образуя из них веерообразную структуру. В современных ма-

шинах устанавливают два контроллера, увеличивая тем самым возможное число вход-

ных устройств до 15 (7 у ведущего и 8 у ведомого контроллера).

К входным выводам IRQ1...IRQ7 и IRQ8...IRQ15 (IRQ - это сокращение от Interrupt

Request, запрос прерывания) подключаются выводы устройств, на которых возникают

сигналы прерываний. Выход ведущего контроллера подключается к входу INT микро-

процессора, а выход ведомого - к входу IRQ2 ведущего. Основная функция контролле-

ров - передача сигналов запросов прерываний от внешних устройств на единственный


вход прерываний процессора. При этом, кроме сигнала INT, контроллеры передают в

процессор по линиям данных номер вектора, который образуется в контроллере путем

сложения базового номера, записанного в одном из его регистров, с номером входной

линии, по которой поступил запрос прерывания. Номера базовых векторов заносятся в

контроллеры автоматически в процессе начальной загрузки компьютера. Очевидно, что

номера векторов аппаратных прерываний однозначно связаны с номерами линий, или

уровнями IRQ, а через них - с конкретными устройствами компьютера. На рис.3.1 обо-

значены основные устройства компьютера, работающие в режиме прерываний.

Процессор, получив по линии INT сигнал прерывания, выполняет последователь-

ность стандартных действий, которую можно назвать процедурой прерывания. Смысл

процедуры прерывания заключается в том, чтобы сохранить состояние текущей (преры-

ваемой) программы и передать управление обработчику, соответствующему возникше-

му прерыванию.

Структуры систем прерывания (в зависимости от аппаратной архитектуры) могут

быть самыми разными, но все они имеют одну общую особенность - прерывание непре-

менно влечет за собой изменение порядка выполнения команд процессором.

Механизм обработки прерываний независимо от архитектуры вычислительной

системы включает следующие элементы :

1. Установление факта прерывания (прием сигнала на прерывание) и идентифика-

ция прерывания (в операционных системах иногда осуществляется повторно, на

2. Запоминание состояния прерванного процесса. Состояние процесса определяется

прежде всего значением счетчика команд (адресом следующей команды, кото-

рый, например, в i80x86 определяется регистрами CS и IP - указателем команды),

содержимым регистров процессора и может включать также спецификацию ре-

жима (например, режим пользовательский или привилегированный) и другую

информацию.

3. Управление аппаратно передается подпрограмме обработки прерывания. В про-

стейшем случае в счетчик команд заносится начальный адрес подпрограммы об-

работки прерываний, а в соответствующие регистры - информация из слова со-

стояния. В более развитых процессорах, например в том же i80286 и

последующих 32-битовых микропроцессорах, начиная с i80386, осуществляется

достаточно сложная процедура определения начального адреса соответствующей

подпрограммы обработки прерывания и не менее сложная процедура инициали-

зации рабочих регистров процессора.

4. Сохранение информации о прерванной программе, которую не удалось спасти на

шаге 2 с помощью действий аппаратуры. В некоторых вычислительных системах

предусматривается запоминание довольно большого объема информации о со-

стоянии прерванного процесса.

5. Обработка прерывания. Эта работа может быть выполнена той же подпрограм-

мой, которой было передано управление на шаге 3, но в ОС чаще всего она реа-

лизуется путем последующего вызова соответствующей подпрограммы.

6. Восстановление информации, относящейся к прерванному процессу (этап, об-

ратный шагу 4).

7. Возврат в прерванную программу.

Шаги 1-3 реализуются аппаратно, а шаги 4-7 - программно. На рис.3.2 показано,

что при возникновении запроса на прерывание естественный ход вычислений нарушает-

ся и управление передается программе обработки возникшего прерывания. При этом

средствами аппаратуры сохраняется (как правило, с помощью механизмов стековой па-

мяти) адрес той команды, с которой следует продолжить выполнение прерванной про-

граммы. После выполнения программы обработки прерывания управление возвращается


прерванной ранее программе посредством занесения в указатель команд сохраненного

адреса команды. Однако такая схема используется только в самых простых программ-

ных средах. В мультипрограммных операционных системах обработка прерываний про-

исходит по более сложным схемам, о чем будет более подробно написано ниже.

Рис.3.2. Обработка прерывания

Итак, главныефункциимеханизмапрерываний :

Распознавание или классификация прерываний;

Передача управления соответственно обработчику прерываний;

Корректное возвращение к прерванной программе.

Переход от прерываемой программы к обработчику и обратно должен выполняться

как можно быстрей. Одним из быстрых методов является использование таблицы, со-

держащей перечень всех допустимых для компьютера прерываний и адреса соответст-

вующих обработчиков. Для корректного возвращения к прерванной программе перед

передачей управления обработчику прерываний содержимое регистров процессора за-

поминается либо в памяти с прямым доступом, либо в системном стеке - system stack.

Прерывания, возникающие при работе вычислительной системы, можно разделить

на два основных класса: внешние (их иногда называют асинхронными) и внутренние

(синхронные).

Внешниепрерывания вызываются асинхронными событиями, которые происходят

вне прерываемого процесса, например:

Прерывания от таймера;

Прерывания от внешних устройств (прерывания по вводу/выводу);

Прерывания по нарушению питания;

Прерывания с пульта оператора вычислительной системы;

Прерывания от другого процессора или другой вычислительной системы.

Внутренниепрерывания вызываются событиями, которые связаны с работой про-

цессора и являются синхронными с его операциями. Примерами являются следующие

запросы на прерывания:


При нарушении адресации (в адресной части выполняемой команды указан запре-

щенный или несуществующий адрес, обращение к отсутствующему сегменту или

странице при организации механизмов виртуальной памяти);

При наличии в поле кода операции незадействованной двоичной комбинации;

При делении на нуль;

При переполнении или исчезновении порядка;

При обнаружении ошибок четности, ошибок в работе различных устройств аппара-

туры средствами контроля.

Могут еще существовать прерывания при обращении к супервизору ОС - в некото-

рых компьютерах часть команд может использовать только ОС, а не пользователи. Со-

ответственно в аппаратуре предусмотрены различные режимы работы, и пользователь-

ские программы выполняются в режиме, в котором эти привилегированные команды не

исполняются. При попытке использовать команду, запрещенную в данном режиме, про-

исходит внутреннее прерывание и управление передается супервизору ОС. К привиле-

гированным командам относятся и команды переключения режима работа центрального

процессора.

Наконец, существуют собственно программныепрерывания . Эти прерывания

происходят по соответствующей команде прерывания, то есть по этой команде процес-

сор осуществляет практически те же действия, что и при обычных внутренних прерыва-

ниях. Данный механизм был специально введен для того, чтобы переключение на сис-

темные программные модули происходило не просто как переход в подпрограмму, а

точно таким же образом, как и обычное прерывание. Этим обеспечивается автоматиче-

ское переключение процессора в привилегированный режим с возможностью исполне-

ния любых команд.

Сигналы, вызывающие прерывания, формируются вне процессора или в самом

процессоре; они могут возникать одновременно. Выбор одного из них для обработки

осуществляется на основе приоритетов, приписанных каждому типу прерывания. Оче-

видно, что прерывания от схем контроля процессора должны обладать наивысшим при-

оритетом (если аппаратура работает неправильно, то не имеет смысла продолжать обра-

ботку информации). На рис.3.3 изображен обычный порядок (приоритеты) обработки

прерываний в зависимости от типа прерываний .

Рис.3.3. Распределение прерываний по уровням приоритета

Учет приоритета может быть встроен в технические средства, а также определяться

операционной системой, то есть кроме аппаратно реализованных приоритетов прерыва-

ния большинство вычислительных машин и комплексов допускают программно-


аппаратное управление порядком обработки сигналов прерывания. Второй способ, до-

полняя первый, позволяет применять различные дисциплиныобслуживанияпрерыва-

Наличие сигнала прерывания не обязательно должно вызывать прерывание испол-

няющейся программы. Процессор может обладать средствами защиты от прерываний:

отключение системы прерываний, маскирование (запрет) отдельных сигналов прерыва-

ния. Программное управление этими средствами (существуют специальные команда для

управления работой системы прерываний) позволяет операционной системе регулиро-

вать обработку сигналов прерывания, заставляя процессор обрабатывать их сразу по

приходу, откладывать их обработку на некоторое время или полностью игнорировать.

Обычно операция прерывания выполняется только после завершения выполнения теку-

щей команды. Поскольку сигналы прерывания возникают в произвольные моменты вре-

мени, то на момент прерывания может существовать несколько сигналов прерывания,

которые могут быть обработаны только последовательно. Чтобы обработать сигналы

прерывания в разумном порядке им присваиваются приоритеты. Сигнал с более высо-

ким приоритетом обрабатывается в первую очередь, обработка остальных сигналов пре-

рывания откладывается.

Программное управление специальными регистрами маски (маскирование сигна-

лов прерывания) позволяет реализовать различные дисциплины обслуживания :

С относительнымиприоритетами , то есть обслуживание не прерывается даже

при наличии запросов с более высокими приоритетами. После окончания обслу-

живания данного запроса обслуживается запрос с наивысшим приоритетом. Для

организации такой дисциплины необходимо в программе обслуживания данного

запроса наложить маски на все остальные сигналы прерывания или просто от-

ключить систему прерываний;

С абсолютнымиприоритетами , то есть всегда обслуживается прерывание с

наивысшим приоритетом. Для реализации этого режима необходимо на время

обработки прерывания замаскировать все запросы с более низким приоритетом.

При этом возможно многоуровневое прерывание, то есть прерывание программ

обработки прерываний. Число уровней прерывания в этом режиме изменяется и

зависит от приоритета запроса;

По принципустека , или, как иногда говорят, подисциплине LCFS (last come first

served - последним пришел - первым обслужен), то есть запросы с более низким

приоритетом могут прерывать обработку прерывания с более высоким приорите-

том. Дли этого необходимо не накладывать маски ни на один сигнал прерывания

и не выключать систему прерываний.

Следует особо отметить, что для правильной реализации последних двух дисцип-

лин нужно обеспечить полное маскирование системы прерываний при выполнении ша-

гов 1-4 и 6-7. Это необходимо для того, чтобы не потерять запрос и правильно его об-

служить. Многоуровневое прерывание должно происходить на этапе собственно

обработки прерывания, а не на этапе перехода с одного процесса на другой.

Управление ходом выполнения задач со стороны ОС заключается в организации

реакций на прерывания, в организации обмена информацией (данными и программами),

предоставлении необходимых ресурсов, в динамике выполнения задачи и в организации

сервиса. Причины прерываний определяет ОС (модуль, который называют супервизо-

ром прерываний), она же и выполняет действия, необходимые при данном прерывании и

в данной ситуации. Поэтому в состав любой ОС реального времени прежде всего входят

программы управления системой прерываний, контроля состояний задач и событий,

синхронизации задач, средства распределения памяти и управления ею, а уже потом

средства организации данных (с помощью файловых систем и т. д.). Следует, однако,

заметить, что современная ОС реального времени должна вносить в аппаратно-


программный комплекс нечто большее, нежели просто обеспечение быстрой реакции на

прерывания.

Как мы уже знаем, при появлении запроса на прерывание система прерываний

идентифицирует сигнал и, если прерывания разрешены, управление передается на соот-

ветствующую подпрограмму обработки. Из рис.3.2 видно, что в подпрограмме обработ-

ки прерывания имеются двеслужебныесекции . Это - первая секция, в которой осуще-

ствляется сохранение контекста прерванной задачи, который не смог быть сохранен на

2-м шаге, и последняя, заключительная секция, в которой, наоборот, осуществляется

восстановление контекста. Для того чтобы система прерываний не среагировала повтор-

но на сигнал запроса на прерывание, она обычно автоматически «закрывает» (отключа-

ет) прерывания, поэтому необходимо потом в подпрограмме обработки прерываний

вновь включать систему прерываний. Установка рассмотренных режимов обработки

прерываний (с относительными и абсолютными приоритетами, и по правилу LCFS)

осуществляется в конце первой секции подпрограммы обработки. Таким образом, на

время выполнения центральной секции (в случае работы в режимах с абсолютными при-

оритетами и по дисциплине LCFS) прерывания разрешены. На время работы заключи-

тельной секции подпрограммы обработки система прерываний должна быть отключена

и после восстановления контекста вновь включена. Поскольку эти действия необходимо

выполнять практически в каждой подпрограмме обработки прерываний, во многих опе-

рационных системах первые секции подпрограмм обработки прерываний выделяются в

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

Супервизорпрерываний прежде всего сохраняет в дескрипторе текущей задачи

рабочие регистры процессора, определяющие контекст прерываемого вычислительного

связанные с обслуживанием настоящего (текущего) запроса на прерывание. Наконец,

перед тем как передать управление этой подпрограмме, супервизор прерываний уста-

навливает необходимый режим обработки прерывания. После выполнения подпрограм-

мы обработки прерывания управление вновь передается супервизору, на этот раз уже на

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

очередь, в соответствии с принятым режимом распределения процессорного времени

(между выполняющимися процессами) восстановит контекст той задачи, которой будет

решено выделить процессор. Рассмотренная схема проиллюстрирована на рис.3.4 .

Как видно из рис.3.4, здесь нет непосредственного возврата в прерванную ранее

программу непосредственно из самой подпрограммы обработки прерывания. Для прямо-

го непосредственного возврата достаточно адрес возврата сохранить в стеке, что и дела-

ет аппаратура процессора. При этом стек легко обеспечивает возможность возврата в

случае вложенных прерываний, поскольку он всегда реализует дисциплину LCFS (last

come - first served).

Однако если бы контекст процессов сохранялся просто в стеке, как это обычно

реализуется аппаратурой, а не в дескрипторах задач, то не было бы возможности гибко

подходить к выбору той задачи, которой нужно передать процессору после завершения

работы подпрограммы обработки прерывания.

Рассмотрим как производится обработка прерываний в ОС Windows . В этой

операционной системе каждому прерыванию назначается определенный приоритет, на-

зываемый уровнемзапросапрерывания (interrupt request level, IRQL). IRQL назначается

источнику прерывания. Например, мышь имеет IRQL, который присваивается посту-

пающим от нее сигналам. Системный таймер также генерирует собственные прерыва-

ния, которым назначается другой IRQL.


Рис.3.4. Обработка прерывания при участии супервизоров ОС

Центральный процессор также имеет свой IRQL, который изменяется по мере ра-

боты системы. Изменение IRQL центрального процессора позволяет системе блокиро-

вать прерывания с более низким приоритетом. Приоритет процессора могут изменить

только системные сервисы, работающие на уровне ядра, например перехватчик. Потоки,

функционирующие на пользовательском уровне, не имеют таких привилегий. Заблоки-

рованным прерываниям внимание не уделяется до тех пор, пока какой-нибудь поток яв-

ным образом не понизит уровень прерывания центрального процессора. Если процессор

работает при самом низком значении IRQL, происходит нормальное выполнение потока

и разрешается обработка всех прерываний. Когда перехватчик вызывает процедуруоб-

служиванияпрерывания (interrupt service routine, ISR), он сначала назначает централь-

ному процессору тот же IRQL, который имеет перехваченный сигнал. На время выпол-

нения ISR прерывания более низкого уровня, например сигналы от устройств ввода

данных, блокируются, чтобы не отвлекать систему от выполнения критических опера-

ций, таких как процедуры восстановления при отключении питания. При понижении

IRQL процессора заблокированные прерывания разблокируются и начинают поочередно

обрабатываться обычным образом. Время от времени центральный процессор переклю-

чается на самый низкий IRQL, чтобы возобновить выполнение прерванных потоков.

Прежде чем приступить к обработке прерывания, перехватчик должен найти в сис-

теме соответствующую подпрограмму. Он ищет такие подпрограммы в таблицерас-

пределенияпрерываний (interrupt dispatch table, IDT). Указанная таблица содержит 32

записи, по одной для каждого уровня запроса прерывания. Каждая из таких записей ука-

зывает на подпрограмму обработки прерывания или на последовательную цепочку таких

подпрограмм - в том случае, если несколько устройств используют один и тот же IRQL.

При загрузке в систему новый драйвер устройства записывает в IDT собственный

обработчик. Драйверы делают это путем создания и подключения объекта-прерывания ,

т.е. структуры, содержащей всю информацию, необходимую ядру для дополнения IDT.

С помощью объекта-прерывания драйверы получают возможность зарегистрировать

свои обработчики прерываний, ничего не зная ни об аппаратном устройстве, ни о струк-

туре таблицы распределения прерываний.


§ 3.2.Общиепринципыобработкиисключений

По мере выполнения программы ее нормальная работа по различным причинам

может нарушаться. В частности, это может быть связано с тем, что центральный процес-

сор наталкивается на недопустимый адрес памяти, пользователь прерывает выполнение

программы комбинацией "горячих" клавиш , отладчик произвольным образом

останавливает программу и запускает ее вновь; ошибка может быть связана и с вводом

неправильного значения при выполнении операции с плавающей запятой. Эти и другие

исключительные ситуации способны возникать как на пользовательском уровне, так и

на уровне ядра операционной системы, как в RISC-процессорах, так и в процессорах

Intel. О возникновении подобных ситуаций может сигнализировать и аппаратное, и про-

граммное обеспечение. Любой язык программирования должен содержать средства об-

работки исключений для унификации процесса обработки, выполняемой в различных

ситуациях. Windows включает встроенные низкоуровневые механизмы структурирован-

ной обработки исключений .

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

тем, что оба сигнала заставляют центральный процессор передать управление специаль-

ной части операционной системы. Однако исключения и прерывания - это не одно и то

же. Прерывания происходят асинхронно, часто в результате определенных аппаратных

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

порт. Программа не имеет возможности контролировать такие прерывания, и они могут

происходить в любой момент. С другой стороны, исключения возникают синхронно, как

результат выполнения определенных операторов программы. Исключения часто служат

сигналом, свидетельствующим о наличии ошибочных условий. Обычно они воспроиз-

водятся путем повторного запуска программы с тем же контекстом.

Исключения часто генерируются в том случае, если какая-то часть программы об-

наруживает ошибку, но не может обработать ее самостоятельно. Так, система генериру-

ет исключение в ответ на ошибки доступа к памяти и ошибки типа деления на ноль. Од-

нако не все исключения порождаются ошибочными ситуациями. Windows генерирует

специальное исключение для вызова определенного системного сервиса. При обработке

этого исключения ядро передает управление той части операционной системы, которая

предоставляет запрашиваемый сервис.

Любое порожденное исключение должно быть обработано если не самой програм-

мой, то операционной системой, а точнее, должна откликнуться определенная подпро-

грамма, которая обработает и снимет исключение. Следовательно, обработка исключе-

ний заключается в создании специальных блоков программного кода, которые

запускаются при возникновении исключительных ситуаций. Каждое приложение долж-

граммы от всевозможных исключений.

В процессе поиска соответствующего блока программного кода, предназначенного

для конкретной исключительной ситуации, система сначала просматривает текущую

процедуру, затем возвращается назад по стеку вызовов, просматривает другие активные

отложенные процедуры того же процесса и, наконец, переходит к системным обработ-

чикам исключений. Если процесс, породивший исключение, находится под защитой от-

ладчика, последний также получает шанс обработать исключение.

Средства обработки ошибок в различных подсистемах и языках программирования

несколько отличаются друг от друга. Например, WOW-подсистема (Windows on Win32 -

защищенная подсистема, выполняющаяся внутри процесса виртуальной DOS-машины)

должна обрабатывать все исключения непосредственно, поскольку клиенты Winl6 не

имеют возможности делать это самостоятельно. Кроме того, в различных языках про-


граммирования может сильно различаться синтаксис операторов обработки исключений.

Термин структурированнаяобработкаисключений подразумевает, что язык содержит

определенную управляющую структуру, связанную с исключениями.

Программисты, впервые столкнувшиеся с проблемой структурированной обработ-

ки исключений, часто ошибочно полагают, что больше нет необходимости проверять

код завершения каждой команды. На самом деле, ошибка - это далеко не то же самое,

что исключение. Функция может завершиться без генерации исключения. Рассмотрим в

качестве примера следующие строки программного кода, реализованного на API-

функциях для ОС Windows:

hBrush = CreateSolidBrush(RGB(255, 0, 0)) ;

hOldBrush = SelectObject(hDC, hBrush);

Rectangle (hDC, 0, 0, 100, 100);

Если первая команда выполняется некорректно и возвращает для создаваемой кис-

ти значение NULL, то функция SelectObject() также не может быть выполнена. Третья

команда все же рисует прямоугольник, однако закрашивает его не тем цветом, который

нужен. Исключения при этом не генерируются. Единственный способ защиты от подоб-

ных ошибок заключается в проверке возвращаемого значения. Вот еще один пример:

hMemory =GlobalAlloc(GHND, 1000);

pData = (char *)GlobalLock(hMemory);

В случае возникновения ошибки, связанной с выделением памяти, переменная

hMemory принимает значение NULL, функция GlobalLock() не выполняется и перемен-

ная pData также получает значение NULL. Однако ни одна из этих ошибок не порождает

исключения. Но следующая строка программного кода при попытке произвести запись

по неправильному адресу генерирует исключение:



// порождает исключение, если pData = NULL


Исключение представляет собой разновидность ошибки, которая не может быть

обработана самой командой. Если функция GlobalAlloc не обнаруживает достаточно

места, для своего выполнения, она просто возвращает значение NULL. Но если операто-

ру присваивания некуда передавать значение, он не выполняет никаких действий и даже

не возвращает код ошибки. При этом порождается исключение, и если процесс не может

его обработать, операционная система должна закрыть данный процесс.

Часто бывает трудно провести черту между ошибками и исключениями. Различие

между ними порой зависит от конкретной реализации. Для того чтобы распознавать ко-

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

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

операции могут их породить. Например, ошибка в операторе присваивания приводит к

исключению типа нарушениеправдоступа . Список возможных исключений обычно

изменяется в зависимости от конкретною компьютера, однако имеется ряд исключений,

которые определяются на уровне ядра Windows :

Несоответствие типов данных (data-type misalignment);

Прерывание отладчика (debugger breakpoint);

Пошаговая отладка (debugger single-step);

Деление на ноль в операции с плавающей запятой (floating-point divide by zero);

Нарушение прав доступа к памяти (memory-access violation);

Ошибка чтения страницы (page-read error);

Превышение квоты страничного файла (paging file quota exceeded);

Привилегированный оператор (privileged instruction).

Тип возникшего исключения можно определить, используя функцию DWORD Ge-

tExceptionCode(void). Функция возвращает код исключения. В таблице 3.1 приведены

наименования основных кодов.

Таблица 3.1


EXCEPTION_ACCESS_VIOLATION

EXCEPTION_FLT_DIVIDE_BY_ZERO

EXCEPTION_INT_DIVIDE_BY_ZERO

EXCEPTION_INT_OVERFLOW

EXCEPTION_PRIV_INSTRUCTION


Попытка обращения к ячейке памяти,

доступ к которой запрещен (например,

память не выделена)

Деление на ноль с плавающей точкой

Деление на ноль с фиксированной точкой

Целочисленное переполнение

Попытка исполнения привилегированной


§ 3.3.Средстваобработкиисключенийв Visual C++

Блок программного кода на языке С++ всегда должен начинаться ключевыми сло-

вами try и catch. Блок try помечает фрагмент программы, который может породить ис-

ключение, а блок catch содержит программу, запускающуюся при наличии исключения.

С точки зрения программиста, подобные синтаксические структуры удобны для отделе-

ния программного кода, предназначенного для обработки исключительных ситуаций, от

кода, выполняющего обычные задачи. В Visual C++ реализован механизм обработки

исключений, который основан на схеме, предложенной ANSI-комитетом по стандарти-

зации языка C++. В соответствии с этой схемой, перед вызовом функции, которая может

стать причиной возникновения исключительной ситуации, должен быть инициирован

обработчик исключений. Если функция приводит к возникновению ненормальной си-

туации, генерируется исключение и управление передается обработчику.

В среде Visual C++ обработка исключений поддерживается с помощью нескольких

механизмов:

Функций, обеспечивающих структурированную обработку исключений;

Классов, отвечающих за обработку определенных типов исключений;

Макрокоманд, позволяющих осуществить структуризацию обработчиков исключений

приложения;

Функций, предназначенных для генерации исключений различных типов.

Все эти механизмы позволяют генерировать исключения нужных типов и при не-

обходимости прекращать выполнение программы.

Как уже было сказано выше, основу любого механизма обработки исключений в

среде Visual C++ составляют операторы try и catch. Структура try/catch отделяет подпро-


©2015-2019 сайт
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-04-02

При работе микропроцессорной системы часто возникают ситуации, когда требуется прервать выполнение текущей программы и перейти к подпрограмме, обеспечивающей необходимую реакцию системы на создавшиеся обстоятельства. Такие ситуации называются прерываниями (илиисключениями) в зависимости от причин, вызывающих их возникновение. В данной главе мы рассмотрим механизмы возникновения и обработки прерываний на примере процессоров семействаix86, поскольку именно здесь реализованы многие из этих механизмов. В конце главы упомянуты особенности, характерные для других типов процессоров.

$.1. Виды прерываний и исключений, реализация их обслуживания

Прерываниями (interruption) являются штатные ситуации, возникающие при поступлении соответствующих инструкций (программные прерывания) или внешних сигналов (аппаратные прерывания). Исключениями (exception) являются нештатные ситуации (ошибки), возникающие при работе процессора. При выявлении таких ошибок соответствующие блоки, контролирующие работу процессора, вырабатывают внутренние сигналы запроса, обеспечивающие вызов необходимой подпрограммы обслуживания. Процессор способен обеспечить обслуживание 256 различных типов исключений и прерываний. Соответствующая обработка информации при возникновении таких ситуаций выполняется с помощью специальных подпрограмм (обработчиков) обслуживания (interrupthandlers), указатели на обработчики (вектора прерываний) хранятся в таблице, размещаемой в памяти системы.

По типу возникновения прерывания делятся на программные, аппаратные и прерывания от внутренних блоков процессора.

Программные прерывания – это своеобразный способ вызова процедур, как правило, системных. Осуществляется по инструкциямINTn , INTO , INT 3, BOUND .

Запросы на выполнение аппаратных прерываний поступают от внешних устройств на входыLINT 0/ INTR ,LINT 1/ NMI процессора. В мультипроцессорной системе, когда включен внутренний контроллер локальных прерыванийAPIC(см. раздел $.4), сигналыLINT 1-0 на этих входах определяют номер запроса, поступающего от других устройств (процессоров) системы. В однопроцессорной системе, когда функционирование контроллера APIC запрещено, эти входы служат, соответственно, для подачи маскируемыхINTR и немаскируемыхNMI запросов прерывания от различных внешних устройств.

Маскируемые прерывания вызываются активизацией входаINTR (InterruptRequest). Их обслуживание может быть запрещено (замаскировано) путем установке значения признакаIF=1 в регистре состоянийEFLAGS. Обычно такой запрос поступает от внешнего устройства через специальный контроллер прерываний, который собирает запросы от различных внешних устройств и передает их для обработки процессору, указав для них также номерn определяющий вид прерывания (INTRn). На входNMI поступает запрос на немаскируемое прерывание, процедура обслуживания которого имеет фиксированный номерn=2 (см. табл.$.1). Значение признакаIFв регистреEFLAGSне влияет на обслуживание процессором немаскируемого запроса прерывания NMI. При работе процессора в мультипроцессорной системе, когда функционирует контроллер локальных прерыванийAPIC, запросы аппаратных прерывания (маскируемые и немаскируемые) поступают по специальной APIC-шине (см. разд.$.4).

Для исключений зарезервированы первые 32 вектора в таблице прерываний. Каждый тип исключения имеет мнемоническое обозначение. Исключения делятся на ошибки (Faults ), ловушки (Traps ) иотказы (Aborts ). В табл. $.1 указан их список для защищенного режима. В реальном режиме некоторые прерывания (например, #TSили #PF) имеют несколько другой смысл, но эти случаи здесь не рассматриваются. Пояснение столбца «класс» будет дано при описании отказа #DFв разделе $.2.

Ошибки выявляются и обслуживаются до выполнения инструкции, которая является причиной их возникновения. Примером ошибки может служить ситуация, возникающая при обращении очередной инструкции к странице или сегменту, отсутствующим в адресуемой оперативной памяти (обращение к сегменту или странице, для которых бит присутствияP=0, см. разд. 7.3). При ошибке в качестве адреса возврата к прерванной программе сохраняется адрес инструкции, выполнение которой вызвало данное исключение.

11 ответов

Перехват - это сигнал ЦП, генерируемый аппаратным обеспечением, или конкретные инструкции ЦП. Это вызывает выполнение обработчиков interupt. Такие вещи, как сигналы ввода-вывода от оборудования ввода/вывода, генерируют прерывания.

Исключение можно рассматривать как программную версию interupt, которая влияет только на ее процесс.

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

В вашем процессоре будет несколько внешних контактов прерываний. Обычно эти контакты подключаются к аппаратным средствам и используются для указания того, когда происходит какое-то внешнее событие. Например, если вы используете последовательный порт, UART будет поднимать рейк, который подключен к одному из выводов прерывания на процессоре, чтобы указать, что байт получен.

Другие периферийные устройства, такие как таймеры, контроллеры usb и т.д., также будут генерировать прерывания на основе некоторого внешнего события.

Когда процессор получает сигнал на одном из внешних контактов прерываний, он сразу же переходит в какое-то назначенное место в памяти и начинает выполнение. Выполненный код обычно называется ISR или программой обслуживания прерываний. Если вы не внедряете драйверы или не выполняете встроенное программное обеспечение, вряд ли вы столкнетесь с ISR.

К сожалению, ответ на вопрос об исключениях немного менее ясен - в других ответах на этой странице было три разных значения.

Ответ Ron Savage относится к конструкции программного обеспечения. Это чисто исключение на уровне приложения, где часть кода может указывать на ошибку, которая может быть обнаружена каким-либо другим фрагментом кода. Здесь вообще нет участия в оборудовании.

Затем возникает исключение, рассматриваемое задачей. Это конструкция уровня операционной системы, которая используется для уничтожения задачи, когда она делает что-то незаконное - например, деление на 0, незаконный доступ к памяти и т.д.

И, в-третьих, есть аппаратное исключение. С точки зрения поведения он идентичен прерыванию в том, что процессор немедленно перейдет в некоторую назначенную ячейку памяти и начнет выполнение. Если исключение отличается от прерывания, это исключение вызвано некоторой незаконной деятельностью, обнаруженной процессором. Например, MMU на процессоре обнаружит незаконный доступ к памяти и вызовет исключение. Эти аппаратные исключения являются начальным триггером для операционной системы для выполнения задач очистки (как описано в параграфе выше).

Прерывания генерируются устройствами, внешними по отношению к ЦП (тик таймера, завершение работы диска, прибытие сетевого пакета и т.д.) и асинхронный с выполнением программы. Исключения составляют синхронно с выполнением программы (например, деление на ноль, обращение к недопустимому адресу).

Если ваша программа не работает без операционной системы (или вы разрабатываете ОС), она никогда не увидит необработанное исключение/прерывание. Они попадают под ОС и обрабатываются им (прерывания) или преобразуются в какую-либо другую форму перед отражением обратно в пользовательскую программу (например, сигналы в UNIX, обработка структурированных исключений (SEH) в Windows), где у нее есть возможность обработки он.

Прерывания указывают на то, что что-то внешнее по отношению к ядру процессора требует внимания. Он прерывает нормальный поток программы, выполняет процедуру обслуживания прерываний (ISR) и обычно возвращается туда, где он был до того, как произошло прерывание.

Существует множество вариантов этой основной темы: прерывания могут быть сгенерированы программным обеспечением, другая задача может получить процессор после ISR и т.д. Ключевым моментом является то, что прерывания могут возникать в любое время по причине кода/У CPU нет контроля над .

Исключение немного сложнее определить, поскольку оно имеет потенциально три уровня значения:

Исключения оборудования

Некоторые процессоры (например, PowerPC) определяют исключения, указывающие на то, что произошло какое-то необычное условие: System Reset, Invalid Address, некоторая ошибка кэширования перевода виртуального адреса и т.д.

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

Исключения ОС

Некоторые из аппаратных исключений будут обрабатываться ОС. Например, ваша программа обращается к недопустимой памяти. Это вызовет аппаратное исключение. У ОС есть обработчик для этого исключения, и вероятность того, что ОС отправит в ваше приложение сигнал (например, SIGSEGV), отметив, что есть проблема.

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

Я бы рассматривал window Structured Exception Handlers (SEH) как исключение этого типа.

Исключения программного обеспечения

Некоторые языки, такие как Java, С++ и С#, имеют концепцию программных исключений, где язык обеспечивает обработку непредвиденных или необычных условий, связанных с работой программы. В этом случае исключение возникает в какой-то момент кода, а некоторый код выше в стеке выполнения программы "ломает" исключение и выполняет. Это то, что делают блоки try/catch.

Исключением является то, что процессор выполняет код, который не находится на его обычном пути. Это "исключение" для нормальной работы, которое по существу является линейным движением через кодовые и управляющие структуры. Различные языки поддерживают различные типы исключений, обычно используемые для обработки ошибок во время работы программы.

Прерывание

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

Прерывание всегда является исключением, даже если оно предназначено. Прерывания могут указывать:

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

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

Ловушки

В терминах прерываний общие ошибки являются условиями гонки. Например, у вас может быть прерывание, которое периодически увеличивает глобальные часы реального времени. Часы могут быть 64 бит на 32-битной машине.

Если программа считывает часы и получает первое 32-битное слово, то прерывание происходит, как только обработчик прерывания выходит из процесса, получает второе 32-битное слово, и данные будут некогерентными - эти два слова могут быть не синхронизировано. Если вы попытаетесь использовать мьютекс или семафор, чтобы заблокировать переменную в этом процессе, прерывание остановится в ожидании блокировки и остановит систему (тупик), если только обработчик и процессы, которые используют данные, написаны очень тщательно. Легко попасть в неприятности при записи прерываний.

Функции повторного входа также являются еще одной проблемой. Если вы выполняете funcA в программном коде, выполняйте прерывание, которое также выполняет funcA, вы можете получить непредвиденные последствия из-за общих переменных (статические или переменные кучи, классы и т.д.). Обычно вы выполняете как можно меньше кода в обработчике прерываний и часто устанавливаете флаг, чтобы процесс мог выполнять настоящую работу позже, не беспокоясь о конфликтах.

В некотором роде это похоже на разработку для многопроцессора и является одной из причин, по которым программирование ядра по-прежнему считается черной магией.

Я расскажу о том, что такое прерывание, потому что есть один критический тип прерывания, с которым никто еще не справился: таймер.

Но сначала позвольте мне вернуться. Когда вы получаете прерывание, выполняется ваш обработчик прерываний (который живет в kernelspace), который обычно отключает прерывания, видит любой ожидающий бизнес (обрабатывает только что поступивший пакет, обрабатывая нажатие клавиши и т.д.), А затем (помните, что мы "все еще в ядре на данный момент) определяет, какой процесс должен запускаться следующим (может быть одним и тем же, может быть другим, зависит от планировщика), а затем запускать его.

Только один процесс выполняется на процессоре в любой момент времени. И когда вы используете многозадачную ОС, способ переключения между ними называется контекстным переключателем - в основном, регистры процессора выгружаются в память, поток переходит к новому процессу, и когда процесс выполняется, вы переключаете контекст на что-то иначе.

Итак, скажем, я пишу простую программу на С, которая подсчитывает все числа или последовательность Фибоначчи или что-то еще без остановки. Или еще лучше: ничего не происходит, кроме спины внутри (1) цикла. Как другие процессы в системе получают возможность запускать? Что делать, если ничего не происходит, чтобы вызвать прерывание?

Ответ заключается в том, что у вас есть устройство таймера, которое постоянно прерывается. И это то, что удерживает процесс прядения от снятия всей системы. Хотя я буду замечать, что обработчики прерываний отключают прерывания, поэтому, если вы делаете что-то, что блокирует неограниченное время, вы можете удалить всю систему.

Ожидается, что прерывания будут происходить регулярно (хотя иногда они не являются регулярными). Они прерывают процессор, потому что что-то важное произошло, и об этом нужно немедленно позаботиться.

Исключения должны быть исключениями к правилу; они брошены программным обеспечением, потому что произошло что-то неожиданное, и это ваш шанс попытаться что-то сделать, или, по крайней мере, сбой изящно.

Сохранение простых вещей...

Когда вы закончите обработку прерывания, вы (обычно) возвращаетесь к тому, что делали до того, как прервались.

Обработка исключения включает в себя отбрасывание последовательных уровней того, над которым вы в настоящее время работаете, до тех пор, пока вы не достигнете уровня, в котором исключение можно обработать (поймать).

При обработке прерывания вы можете решить исключение, но это не значит, что вы должны рассматривать прерывание как исключение. Исключения не "прерывают" (так как это подразумевает возможность возврата к тому, что вы делали непосредственно перед тем, как вас прервали); скорее, они "прерывают" (некоторые подмножества) вашу текущую деятельность.

И, как уже отмечалось несколько раз, прерывания обычно запускаются внешними объектами, такими как аппаратные средства или пользователи (например, щелчок мышью или нажатие клавиши, например CTRL-C), в то время как исключения генерируются (выбрасываются) синхронно с помощью программного обеспечения, обнаруживающего "проблему" "или" исключительное условие ".

Прерывания и исключения – это состояния в ОС, переключающие процессор на код, лежащий вне нормального потока команд. Они обнаруживаются аппаратно и программно. При обнаружении прерывания или исключения процессор прекращает выполнять текущее действие и передает управление в особое место памяти – по адресу кода, обрабатывающего возникшее состояние. В NT этот код называется обработчиком ловушки (trap handler ).

Ядро NT различает прерывания и исключения . Прерывание (interrupt ) – это асинхронное событие, которое может произойти в любой момент времени, независимо от того, чем занят процессор. Прерывания генерируются устройствами ввода/вывода и таймерами процессора и могут быть разрешены (включены) или запрещены (отключены).

Исключение (exception ) – это синхронное состояние, возникшее в результате выполнения некоторой инструкции. Исключения воспроизводятся посредством повторного выполнения той же программы, с теми же данными и в тех же условиях. Примеры исключений – нарушение защиты памяти, некоторые отладочные команды и ошибки деления на ноль. Ядро NT рассматривает как исключения вызовы системных сервисов (хотя технически это системные ловушки).

Обработчик ловушки . Термином ловушка (trap ) обозначается механизм, используемый процессором (при возникновении в исполняющем потоке прерывания или исключения) для перехвата управления, переключения из пользовательского режима в режим ядра и передачи управления в фиксированную точку ОС. В Windows NT процессор передает управление обработчику ловушки ядра NT . Этот модуль играет роль коммутационной панели; он принимает исключения и прерывания, генерируемые процессором, и передает управление коду обработки соответствующей ситуации.

Прерывание генерируются как устройством ввода/вывода, так и ядро может вызвать программное прерывание. На рис. 2.13 показаны условия, приводящие к активизации обработчика ловушки, и модули, которые он вызывает для обработки этих условий. В момент своего вызова обработчик ловушки запрещает прерывания и сохраняет состояние машины. Он создает кадр ловушки (trap frame ), в который помещает информацию о состоянии исполнения прерванного потока. Эта информация позволит ядру возобновить исполнение потока после обработки прерывания или исключения. Кадр ловушки является подмножеством полного контекста потока.

Если произошло прерывание от устройства, то управление передается процедуре обработки прерывания (interrupt service routine , ISR ), предоставляемой драйвером данного устройства. Если прерывание возникло в результате вызова системного сервиса, то обработчик ловушки передает управление коду системного сервиса в исполнительной системе NT . Остальные исключения обрабатываются собственным диспетчером исключений ядра.



Распределение прерываний. Прерывания, сгенерированные аппаратно, исходят от устройств ввода/вывода, которые должны уведомлять процессор о необходимости их обслуживания. Устройства, способные генерировать прерывания, позволяют ОС обеспечить максимальную загрузку процессора путем совмещения во времени вычислений и операций ввода/вывода. Процессор запускает операцию ввода/вывода на устройстве и выполняет другие потоки, пока осуществляется пересылка данных. Когда устройство закончило обмен, оно генерирует прерывание для выполнения обслуживания. Координатные устройства, принтеры, клавиатуры, диски и сетевые карты обычно генерируют прерывания. Системное программное обеспечение также может генерировать прерывания.

На прерывания реагирует подмодуль обработчика ловушки ядра, диспетчер прерываний. Он определяет источник прерывания и передает управление либо внешней процедуре обработки прерываний (ISR ), либо внутренней процедуре ядра. Драйверы устройств предоставляют ISR для обслуживания прерываний от устройств, а ядро содержит процедуры обслуживания других типов прерываний.

Типы и приоритеты прерываний. Разные процессоры могут распознавать разное количество и разные типы прерываний. Диспетчер прерываний отображает аппаратные уровни прерываний в стандартный набор уровней прерываний (interrupt request level , IRQL ), распознаваемых ОС. Уровни IRQL ранжируют прерывания по приоритетности. Если приоритет планирования – это атрибут потока, то IRQL – атрибут источника прерываний. Кроме того, каждый процессор имеет текущий IRQL , который изменяется в процессе работы ОС. Поток, работающий в режиме ядра, может повышать или понижать текущий IRQL процессора, на котором выполняется, чтобы замаскировать или демаскировать прерывания нижних уровней.

Ядро определяет набор переносимых IRQL , который может модифицироваться, если у данного процессора есть особые возможности, связанные с прерываниями (например, второй таймер). Прерывания обслуживаются в порядке приоритета. Уровни IRQL с самого старшего по первый IRQL устройства зарезервированы для аппаратных прерываний; прерывания уровней диспетчерский/DPC и АРС – это программные прерывания, генерируемые ядром. Низший IRQL на самом деле не является уровнем прерываний – он относится к нормальному выполнению потока, при котором все прерывания разрешены.

Текущий IRQL процессора определяет, какие прерывания получает данный процессор. В процессе выполнения поток режима ядра повышает или понижает процессорный IRQL. Как показано на рис. 2.14, источники прерываний, уровень которых выше текущего, прерывают работу процессора, в то время как прерывания от источников с IRQL , равным или меньшим, чем текущий, блокируются или маскируются (masked ), пока выполняющийся поток не понизит IRQL .


Рис. 2.14. Маскирование прерываний

Поток режима ядра повышает IRQL процессора, на котором он исполняется, в зависимости от того, что он в данный момент пытается сделать. Например, когда происходит прерывание, обработчик ловушки (или, возможно, процессор) понижает IRQL процессора до уровня, назначенного источнику прерывания. Это блокирует все прерывания данного и низших уровней (только на этом процессоре) и гарантирует, что обслуживающий прерывание процессор не будет перехвачен менее важным прерыванием. Замаскированные прерывания либо обслуживаются другим процессором, либо задерживаются, пока IRQL не снизится. Изменение IRQL процессора – это мощная операция, которую следует выполнять с большой осторожностью. Потоки пользовательского режима не могут изменять IRQL процессора.

Каждый уровень прерываний имеет особое назначение. Ядро генерирует межпроцессорное прерывание (IPI ), чтобы запросить у другого процессора выполнение действия, например, чтобы направить некоторый поток на исполнение или обновить кэш справочного буфера трансляции (TLB ). Системный таймер генерирует прерывания через заданные интервалы времени, и ядро обрабатывает их, обновляя текущее значение часов и замеряя время выполнения потока. Если процессор поддерживает два таймера, то ядро добавляет еще один уровень таймерных прерываний для измерения производительности. Ядро определяет уровни прерывания устройствам, число которых зависит от процессора и конфигурации системы. Программные прерывания уровней IRQL диспетчерский/DPC и АРС используются ядром для инициирования планирования потоков и асинхронного вмешательства в процесс исполнения потока.

Обработка прерываний. При возникновении прерывания обработчик ловушки сохраняет состояние машины и вызывает диспетчера прерываний. Последний немедленно повышает IRQL процессора до уровня источника прерывания, чтобы замаскировать прерывания этого и низших уровней на время обработки.

NT использует для поиска обработчика данного прерывания таблицу распределения прерываний (interrupt dispatch table , IDT ). Индексом таблицы служит IRQL источника прерывания, а входы таблицы указывают на процедуры обработки прерываний (рис. 2.15).

После выполнения процедуры обработки прерывания диспетчер прерываний понижает IRQL процессора до отметки, на которой он находился перед возникновением прерывания, после чего загружает сохраненное состояние машины. Прерванный поток возобновляет исполнение с точки, в которой произошло прерывание. При снижении ядром IRQL могут вскрыться замаскированные прерывания нижних уровней.

Большинство процедур обработки прерываний находится в ядре. Ядро обновляет системное время и выполняет останов системы по сбою питания. Многие прерывания генерируются внешними устройствами, а драйверы сообщают ядру, какую процедуру следует вызвать при возникновении прерываний от соответствующих устройств.

Ядро предоставляет переносимый механизм – объект-прерывание (interrupt object ), который позволяет драйверам регистрировать ISR для своих устройств, содержащий всю информацию, необходимую ядру для того, чтобы связать ISR устройства с некоторым уровнем прерываний. Она включает адрес ISR , IRQL устройства и вход IDT – ядра, с которым должна быть связана ISR . Связывание процедуры обработки прерываний с некоторым уровнем прерываний называется подключением объекта-прерывания (connecting an interrupt object ), a отсоединение от входа IDT – отключением объекта-прерывания (disconnecting an interrupt object ). Эти операции, выполняемые с помощью вызова функции ядра, позволяют драйверу устройства "включать" ISR при его загрузке в систему и снова "отключать" ее, если он выгружается.

Использование объекта-прерывания для регистрации ISR позволяет драйверам не работать непосредственно с аппаратурой прерываний, которая различается для разных архитектур процессоров, и избавляет от необходимости знать подробности таблицы распределения прерываний. Это средство ядра помогает создавать переносимые драйверы устройств, так как устраняет необходимость программирования на ассемблере или отражения в драйвере устройства различий между процессорами.

При помощи объекта-прерывания ядро может синхронизировать исполнение ISR с другими частями драйвера, возможно – используя общие данные. Более того, объекты-прерывания позволяют ядру легко вызывать более одной ISR для данного уровня прерываний. Если несколько драйверов устройств подсоединяют созданные ими объекты-прерывания к одному и тому же входу IDT , то при возникновении прерывания на данном уровне диспетчер прерываний вызывает каждую из процедур. Это позволяет ядру легко поддерживать "цепочечные" конфигурации, в которых несколько устройств генерируют прерывания на одном уровне.

Программные прерывания. Хотя большинство прерываний генерируется аппаратурой, ядро NT также генерирует программные прерывания в своих целях. Это:

· инициирование планирования потоков;

· обработка истечения интервала таймера;

· асинхронное выполнение процедуры в контексте заданного потока;

· поддержка асинхронного ввода/вывода.

Ниже следуют описания соответствующих задач.

Диспетчерские прерывания . Одно из мест, где ядро использует программные прерывания – в диспетчере потоков. Когда поток не может более выполняться, ядро вызывает диспетчер, чтобы немедленно переключить контекст. Однако иногда ядро обнаруживает необходимость перепланировки, когда оно находится глубоко под несколькими слоями кода. В этой ситуации идеальным решением будет запросить планирование, но отложить его выполнение до того момента, когда ядро завершит текущие действия. Удобный способ реализации – использование программного прерывания.

Для целей синхронизации ядро на время своей работы всегда повышает IRQL процессора до уровня диспетчерский/DPC или выше, что маскирует программные прерывания (и отключает планирование потоков). Когда ядро определяет, что требуется перепланирование потоков, оно запрашивает прерывание уровня диспетчерский/DPC , но, поскольку текущий IRQL находится на этом же уровне или выше, то процессор только запоминает данное прерывание. Завершив свою текущую работу, ядро понижает IRQL ниже уровня диспетчерский/DPC , и диспетчерское прерывание демаскируется.

Прерывания отложенного вызова процедуры (DPC ). Активизация диспетчера с использованием программного прерывания – это способ отложить переключение потоков до наступления подходящих условий. NT также использует программные прерывания, чтобы отложить выполнение других типов обработки.

Переключение потоков проходит на IRQL диспетчерский/DPC . Прерывания этого уровня поступают через обработчик ловушки к диспетчеру, который выполняет планирование потоков. "По дороге" ядро обрабатывает также отложенные вызовы процедур (DPC ). DPC – это функция, выполняющая системную задачу, менее важную, чем та, которая выполняется в данный момент. Такие функции называются "отложенными", так как они могут не выполняться сразу. DPC выполняются после того, как ядро (или часто система ввода/вывода) закончит выполнение более важной задачи и опустит IRQL процессора ниже отметки диспетчерский/DPC .

DPC дают ОС возможность генерировать прерывание и исполнять системную функцию в режиме ядра. Ядро использует DPC для обработки истечения интервала таймера (и освобождения потоков, ждущих таймеров) и для перепланировки процессора после истечения кванта времени потока. Драйверы устройств используют DPC для завершения обработки запросов ввода/вывода.

Представлением DPC является объект-DPC (DPC object ) – управляющий объект ядра, который невидим программам пользовательского режима, но видим драйверам устройств и другому системному коду. Самая важная часть информации, хранящейся в объекте-DPC , – адрес системной функции, которая вызывается ядром при обработке данного прерывания DPC . Ожидающие выполнения процедуры DPC хранятся в управляемой ядром очереди, называемой очередью DP C. Чтобы запросить DPC , системный код обращается к ядру для инициализации объекта-DPC , после чего помещает его в эту очередь.

Помещение DPC в очередь DPC служит указанием ядру запросить программное прерывание уровня диспетчерский/DPC . Так как обычно DPC помещаются в очередь кодом, исполняющимся на более высоком IRQL , то запрошенное прерывание не возникает до тех пор, пока IRQL не снизится до уровня АРС или нижнего уровня.

Так как прерывание DPC имеет более низкий приоритет, чем прерывания от устройств, то все ожидающие прерывания от устройств, которые будут демаскированы, обрабатываются до того, как произойдет прерывание DPC .

Прерывания асинхронного вызова процедуры (АРС ). Когда ядро помещает в очередь объект-DPC , генерируемое в результате этого прерывание DPC вмешивается в выполнение любого потока. Для прервания выполнение заданного потока и для выполнения заданной процедуры ядро предоставляет механизм асинхронного вызова процедуры (АРС ). АРС могут помещаться в очередь как системным кодом, так и кодом пользовательского режима, хотя АРС режима ядра мощнее. Как и DPC , APC выполняется асинхронно при наступлении соответствующих условий. Для пользовательских АРС такими условиями являются следующие:

· текущим потоком должен быть тот, который переназначен для выполнения данного АРС ;

· IRQL процессора должен быть на низшем уровне;

· целевой поток АРС пользовательского режима должен объявить себя оповещенным;

· АРС режим ядра, в отличие от АРС пользовательского режима, не требуют для своего выполнения "разрешения" от целевого потока. Они прерывают поток и выполняют процедуру без его участия или согласия.

Программа помещает в очередь АРС для некоторого потока, вызывая ядро либо непосредственно (для системного кода), либо косвенно (для кода пользовательского режима). Ядро запрашивает программное прерывание уровня АРС , и при выполнении всех вышеперечисленных условий целевой поток прерывается и выполняет данный АРС . Как и DPC , АРС описываются управляющим объектом ядра – объектом-АРС . АРС , ждущие своего выполнения, находятся в управляемой ядром очереди АРС (АРС queue ). В отличие от очереди DPC , являющейся общесистемной, очередь АРС специфична для потока – у каждого потока имеется собственная очередь АРС . При получении запроса на постановку АРС в очередь, ядро ставит его в очередь того потока, который выполняет процедуру данного АРС . АРС исполняется в контексте заданного потока и на более низком IRQL , и к нему не применяются ограничения, налагаемые на DPC . Oн запрашивает ресурсы (объекты), ждет у описателей объектов, генерирует страничные ошибки и вызывает системные сервисы. Это делает АРС полезными даже для кода пользовательского режима.

Исполнительная система NT использует АРС режима ядра для выполнения некоторой задачи ОС, которое должно происходить в адресном пространстве (в контексте) определенного потока. Она может использовать АРС режима ядра, чтобы заставить поток прекратить выполнение системного сервиса. Подсистемы среды применяют АРС режима ядра, чтобы заставить поток приостановить свое выполнение или завершиться, а также для считывания или установки контекста исполнения пользовательского режима.

Распределение исключений. В отличие от прерываний, которые могут возникать непредсказуемо, исключения – это прямой результат выполнения программы. Microsoft С определяет архитектуру программирования, известную как структурная обработка исключений, которая обеспечивает приложениям унифицированную реакцию на исключения. Все исключения, кроме тех, которые достаточно просты и обрабатываются непосредственно обработчиком ловушки, обслуживаются модулем ядра, диспетчерам исключений (exception dispatcher ) (рис. 2.13). Этот модуль зависит от архитектуры процессора, но написан на С . Задача диспетчера исключений состоит в том, чтобы найти обработчик исключений, который может данное исключение "устранить". Ниже приведен список машинно-независимых исключений, определенных ядром:

Некоторые из этих исключений перехватываются и обрабатываются ядром незаметно для пользовательских программ. Другие исключения ядро обрабатывает, возвращая вызывающей программе код ошибки. Некоторым исключениям позволено "нетронутыми" выходить обратно в пользовательский режим. Для таких исключений подсистема среды или приложение могут задать при помощи специальных конструкций языка высокого уровня блочные обработчики исключений (frame based exception handlers ). Microsoft С – это первый компилятор Microsoft , поддерживающий структурную обработку исключений, однако средства обработки исключений Windows NT не зависят от языка программирования.

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

При возникновении исключения, возбужденого программой или неявно оборудованием, в ядре происходит цепочка событий. Управление передается обработчику ловушки, который создает кадр ловушки (также, как это делается при обработке прерывания). Этот кадр позволяет ОС возобновить выполнение с места возникновения исключения, если последнее было успешно обработано. Кроме того, обработчик ловушки создает запись исключения, которая содержит причину исключения и привходящую информацию.

Если исключение произошло в режиме ядра, диспетчер исключений вызывает процедуру для поиска блочного обработчика, который будет обслуживать данное исключение. Подсистема среды может установить для созданного ею процесса порт отладки и порт исключений. Они используются ядром при обычной обработке исключений, как показано на рис. 2.16. Часто источниками исключений являются отладочные точки останова. Действием диспетчера исключений становится посылка сообщения (через LPC ) в порт отладки, связанный с процессом, где произошло исключение. Это дает пользователю возможность манипулировать структурами данных и вводить команды отладчика.

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

Распределение вызовов системных сервисов. Обработчик ловушки ядра NT (рис. 2.13) распределяет прерывания, исключения и вызовы системных сервисов. Вызовы системных сервисов, генерирующие ловушки, – которые в Windows NT рассматриваются как исключения – интересны с точки зрения расширяемости системы. Способ реализации системных сервисов ядром позволяет динамически добавлять к ОС новые сервисы в будущих версиях.

Когда поток пользовательского режима вызывает системный сервис, ему вдруг разрешается выполнять привилегированный код ОС. По этой причине процессоры предоставляют команду syscall на процессорах MIPS и Intel х 86, если поток пользовательского режима вызывает системный сервис. Аппаратура генерирует ловушку и переключается из пользовательского режима в режим ядра. Когда это происходит, ядро копирует значения параметров сервиса из стека пользовательского режима в стек режима ядра потока (чтобы пользователь никак не мог их изменить) и затем выполняет системный сервис.

Для поиска системных сервисов (рис. 2.17) ядро использует таблицу распределения системных сервисов. Эта таблица похожа на таблицу распределения прерываний, только каждый элемент ее содержит указатель на системный сервис, а не на процедуру обработки.

Использование таблицы распределения системных сервисов делает базовые сервисы NT расширяемыми. Поддержка сервисов добавляется в ядро путем расширения этой таблицы, без изменений в ОС или в приложениях. После создания кода нового сервиса системный администратор запускает утилиту, которая создает таблицу распределения с дополнительным элементом, указывающим на новый системный сервис.

Многопроцессорная синхронизация. Концепция взаимного исключения (mutual exclusion ) является критической при разработке ОС, т.е. в любой момент времени доступ к данному ресурсу может иметь один и только один поток. Взаимное исключение необходимо, когда ресурс не поддерживает совместный доступ или когда совместное использование дает непредсказуемые результаты. На рис. 2.18 показано, что происходит, когда два потока, выполняющиеся на разных процессорах, выполняют запись в циклическую очередь.

Второй поток получает указатель на конец очереди до того, как первый поток его обновит, второй поток поместит данные на то же место, что и первый – затерев его данные и оставив одно место в очереди пустым. Участки кода, в которых выполняется доступ к ресурсу, не поддерживающему совместное использование, называются критическими секциями (critical sections ). Чтобы гарантировать корректную работу, в критической секции выполняют не более одного потока. Пока поток записывает данные в файл, обновляет базу данных или модифицирует совместно используемую переменную, никакому другому потоку не разрешен доступ к тому же ресурсу. Код на рис. 2.18 – критическая секция, в которой некорректно, без взаимного исключения, осуществляется доступ к совместно используемым данным.

Взаимное исключение важно для тесно связанных (tightly -coupled ) ОС с симметричной мультипроцессорной обработкой (symmetric multiprocessing ), таких как Windows NT , где один и тот же системный код выполняется на нескольких процессорах, совместно используя структуры данных в глобальной памяти. В Windows NT предоставление механизмов, которые системный код использует для предотвращения одновременной модификации структуры данных двумя потоками –задача ядра. Ядро обеспечивает примитивы взаимного исключения; оно и другие компоненты исполнительной системы используют их для синхронизации доступа к глобальным структурам данных.

Синхронизация на уровне ядра. На различных стадиях работы ядро должно гарантировать, что в каждый момент времени в критической секции исполняется один и только один процессор. Критические секции ядра – это сегменты кода, модифицирующие глобальные структуры данных, например, базу данных диспетчера ядра или очередь DPC . ОС не будет работать нормально, если ядро не гарантирует, что потоки осуществляют доступ к этим данным в режиме взаимного исключения.

В момент изменения ядром глобальной структуры данных может возникнуть прерывание, обработчик которого также изменяет эту структуру. Простые однопроцессорные ОС предотвращают эти случаи, запрещая прерывания на время доступа к глобальным данным, но ядро NT прежде чем использовать глобальный ресурс, временно маскирует те прерывания, обработчики которых также используют этот ресурс. Это делается путем повышения IRQL процессора до самого высокого уровня. Прерывание уровня диспетчерский/DPC вызывает использование диспетчера, который обращается к базе данных диспетчера. Любая другая часть ядра, использующая эту базу данных, повышает IRQL до отметки диспетчерский/DPC , маскируя прерывания этого уровня перед использованием базы данных. Такая стратегия подходит для однопроцессорной системы, но неадекватна в многопроцессорной конфигурации. Повышение IROL на одном процессоре не предотвращает прерываний на других. Ядру необходимо обеспечить взаимоисключающий доступ для нескольких процессоров.

Механизм, используемый ядром для достижения многопроцессорного взаимного исключения, называется спин-блокировкой (spin lock ), связанный с глобальной структурой данных, например очередью DPC (рис. 2.19). Прежде чем войти в критическую секцию, ядро должно получить спин-блокировку, связанную с защищенной очередью DPC . Если блокировка не свободна, то ядро пытается получить ее, пока это не увенчается успехом. Спин-блокировка названа так потому, что ядро изолировано и "вращается само по себе", пока не получит блокировку. Спин-блокировки, как и защищаемые ими структуры данных, располагаются в глобальной памяти. Код получения и освобождения спин-блокировки написан на языке ассемблера, чтобы повысить скорость работы и использовать механизм блокировки, предоставляемый данной архитектурой процессора. Во многих архитектурах спин-блокировка реализована при помощи команды "проверить и установить", которая одной операцией проверяет значение переменной блокировки и захватывает блокировку, что предотвращает захват блокировки вторым потоком (в интервале времени между проверкой значения переменной и захватом блокировки первым потоком).

Когда поток пытается получить спин-блокировку, вся другая активность на этом процессоре приостанавливается. Поэтому поток, получивший такую блокировку, никогда не вытесняется и имеет возможность продолжать выполнение, чтобы быстрее освободить ее. Ядро использует спин-блокировки с осторожностью, минимизируя количество команд, выполняемых во время обладания ими. Спин-блокировки доступны другим частям исполнительной системы через набор санкций ядра.

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

· доступ к защищенному ресурсу должен осуществляться быстро и без сложного взаимодействия с другим кодом;

· критическая секция не может откачиваться из памяти, не может обращаться к нерезидентным данным, не может вызывать внешние процедуры (включая системные сервисы) и не может генерировать прерывания и исключения.

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

Поток не может возобновить выполнение, пока ядро не изменит его состояние с "ожидающий" на "готовый". Такое изменение происходит, когда состояние диспетчерского объекта, у описателя которого ждет поток, изменится с "занят" на "свободен". Ядро отвечает за оба типа переходов между состояниями.

Каждый тип диспетчерского объекта предоставляет особый тип синхронизации. Так, объект-мьютекс обеспечивает взаимное исключение; семафор работает как шлюз, через который может проходить переменное число потоков. События могут использоваться либо для уведомления о том, что было выполнено некоторое действие, либо для реализации взаимного исключения. Пары событий – это средство поддержки ядром быстрого LPC , оптимизированной формы передачи сообщений в подсистеме Win 32. Таймеры "срабатывают" по истечении заданного интервала времени. Поток может ждать завершения другого потока, что бывает полезно для координации действий между взаимодействующими потоками. Все вместе, диспетчерские объекты ядра предоставляют исполнительной системе большую гибкость в синхронизации исполнения.

Синхронизационные объекты, доступные в пользовательском режиме, получают свои возможности синхронизации от диспетчерских объектов ядра. Каждый синхронизационный объект, видимый пользовательскому режиму, инкапсулирует в себе по крайней мере один диспетчерский объект ядра.

Восстановление после сбоя питания. Для сбоя питания в ядре NT зарезервировано второе по старшинству приоритета прерывание. Оно уведомляет о проблеме в источнике питания, чтобы система могла выполнить останов корректно. При этом остается время на то, чтобы начать процедуру останова. Если компьютер оборудован резервными батареями для памяти, данные можно восстановить, когда питание будет подано вновь. Выполнявшиеся задачи могут быть перезапущены либо продолжены, в зависимости от их состояния на момент сбоя.

Перезагрузки регистров и возобновления исполнения недостаточно для полного восстановления системы. Так как устройства ввода/вывода работают независимо от остальной ОС, для восстановления после сбоя питания им требуется следующая поддержка со стороны ядра:

· они переинициализируются, когда питание восстановится;

· они должны уметь определять, имел ли место сбой питания.

Эти средства предоставляются двумя управляющими объектами ядра. Объекты – уведомления питания (power notify objects ) позволяют драйверам устройств зарегистрировать процедуру восстановления, которую ядро будет вызывать при возобновлении питания. Драйвер устройства определяет, что должна делать эта процедура; в общем случае она выполняет повторную инициализацию устройства и перезапуск прерванных операций ввода/вывода. Чтобы зарегистрировать процедуру восстановления после сбоя питания, драйвер создает объект-уведомление питания, вызывает ядро для инициализации объекта указателем на процедуру, после чего снова вызывает ядро для добавления объекта в очередь, контролируемую ядром. При восстановлении питания ядро просматривает эту очередь и вызывает все процедуры по порядку.

Ядро предоставляет еще один управляющий объект, используемый драйверами устройств, объект-состояние питания (power status object ). Создав такой объект и добавив его в другую очередь ядра, драйвер определяет перед началом операции, которую нельзя прервать (например, запись данных в регистр устройства), не произошел ли сбой питания. Если он произошел, драйвер не выполняет операцию.

Процесс выборки и выполнения последовательности команд может быть прерван для выполнения обслуживания одного из событий, возникшего во время выполнения программы. Это связано с выполнением микропроцессором специальной аппаратной функции - прерывания.

Прерывание - это аппаратная функция микропроцессора, позволяющая ему во время выполнения программы, единым образом реагировать на различные внутренние и внешние асинхронные события, которые возникают в процессе работы компьютера. За счет выполнения процедуры прерывания, процессор прерывает выполнение текущей программы и переходит к выполнению другой программы, которая обслужит событие, вызвавшее данное прерывание. Возврат из программы обслуживания осуществляется за счет выполнения в конце этой программы команды процессора IRET (возврат из прерывания).

События, вызывающие прерывания, - это:

  • аппаратные ошибки, определяемые схемами контроля устройств: ошибка четности; ошибка ввода-вывода (немаскируемые прерывания NMI);
  • внутренние ошибки МП (ошибка деления на 0, нарушение прав доступа к сегменту памяти и др.);
  • выполнение команд INT (программные прерывания);
  • запросы на обслуживание от внешних устройств (маскируемые прерывания по сигналам IRQ);
  • запрос на переход в режим управления системой (SMI) и др.

Все события, вызывающие прерывания, пронумерованы от 0 через единицу до FF (256 событий). За каждым событием жестко закреплен вектор прерывания (в режиме реального адреса - четыре байта ОЗУ). В векторе прерывания хранится программный адрес (базовый адрес сегмента памяти и смещение) начала программы обслуживания данного события.

Под векторы прерывания в режиме реального адреса (в этом режиме работают все микропроцессоры от 80286 до Pentium 4 после включения электропитания) отводится область ОЗУ с 0 до 400h (256 векторов х 4 байта = 1024 байта). Адрес вектора прерывания (АВП ) - это адрес младшего из четырех байтов вектора прерывания. АВП = (номер события вызывающего прерывание) х 4. Для обслуживания прерываний выделяется и используется небольшая область оперативной памяти, которую называют стек.

Стек - это область оперативной памяти, предназначенная для хранения данных, имеющих временную ценность, например, сохраняется текущее состояние микропроцессора, необходимое для возврата по команде IRET в прерванную ранее программу. Запись в стек выполняется с авто-уменьшением адресов, а чтение с авто-увеличением адресов (принцип: «первым пришел - последним ушел»). Физический адрес для обращения в стек формируется из содержимого регистров процессора (SS: SP). При выполнении записи в стек содержимое регистра SP автоматически уменьшается на 2, а затем используется в качестве смещения при вычислении физического адреса. При обращении по чтению в стек содержимое регистра SP используется в качестве смещения при вычислении физического адреса, а затем к регистру SP автоматически прибавляется 2. Обращение в стек может быть выполнено во время выполнения микропроцессором аппаратной функции (например, прерывание) и по командам микропроцессора (например, PUSH , POP).

Сигналы IRQ n

Сигналы IRQ n (Interrupt ReQuest - запрос прерывания) - сигнал от одного из узлов компьютера, требующий внимания процессора к этом узлу. Сигнал генерируется при наступлении какого-либо события (например, нажатии клавиши, завершении операции чтения/записи на диске и т.п.). Например, в однопроцессорном варианте ПК предусмотрено 15 линий IRQ, часть которых используется внутренними контроллерами системной платы, а остальные заняты стандартными адаптерами либо не используются:

0 - системный таймер (канал 0)

1 - контроллер клавиатуры

2 - сигнал с выхода починенного контроллера прерываний

3 - обычно COM2/COM4

4 - обычно COM1/COM3

5 - параллельный порт LPT2

6 - контроллер FDD

7 - параллельный порт LPT1

8 - часы реального времени с автономным питанием (RTC)

9 - параллельна IRQ 2

10 - резерв для устройств

11 - резерв для устройств

12 - обычно контроллер мыши типа PS/2

13 - математический сопроцессор

14 - обычно контроллер Primary IDE HDD (первый канал)

15 - обычно контроллер Secondary IDE HDD (второй канал)

Прерывания и исключения.

Процессор управляет внешними устройствами, выполняя соответствующую программу ввода/вывода, где он с помощью команд IN,OUT (чтение порта, запись в порт) имеет доступ к программно-доступным регистрам контроллера. В регистр управления процессор записывает команду, из регистра состояния читает информацию о состоянии устройства и контроллера, в регистр данных записывает выводимые на устройство данные, или читает из регистра данных считываемую с устройства информацию. Возможны два способа организации программного обмена с внешними устройствами:

1) обмен с опросом готовности устройства.

Выполняя программу ввода-вывода, процессор, запустив в контроллере операцию, циклически читает регистр состояния контроллера. Он ожидает появления (в соответствующем разряде регистра состояния) признака готовности к обмену данными с процессором. При появлении этого признака в регистре состояния, процессор, с помощью команды OUT, осуществляет запись в регистр данных (при выводе на устройство), или выполняет чтение информации из регистра данных контроллера с помощью команды IN (при вводе с устройства). После чего запускает в контроллере следующую операцию в контроллере и т. д.;

2) обмен по запросам на обслуживание устройства (запросам на маскируемое прерывание).

При обслуживании внешних устройств через прерывания, процессор, выполняющий программу ввода-вывода, запускает в контроллере операцию и не ожидает готовности контролера к обмену данными. Он продолжает выполнять полезную программу. Контроллер внешнего устройства в случае полной готовности к обмену данными с процессором выдает на соответствующую линию IRQ сигнал запроса на обслуживание. Процессор, через выполнение процедуры прерывания по сигналу IRQ (в ее выполнении участвуют контроллер прерываний и контроллер шины), переходит на выполнение программы ввода/вывода для данного устройства. Эта программа осуществляет обмен данными через регистр данных контроллера и запускает в контроллере следующую операцию и т. д. Процессор возвращается к выполнению прерванной программы через выполнение команды IRET (возврат из прерывания, которой заканчивается программа ввода/вывода) и т. д.

Прерывания и исключения нарушают нормальный ход выполнения программы для обработки внешних событий или сообщения о возникновении особых усло-вий или ошибок. Прерывания подразделяются на аппаратные (маскируемые и немаскируе-мые), вызываемые электрическими сигналами на входах процессора, и програм-мные, выполняемые по команде INT хх. Программные прерывания процессором обрабатываются как разновидность исключений. Аппаратные прерывания подразделяются на маскируемые и немаскируемые. Процессор может воспринимать прерывания после выполнения каждой коман-ды, длинные строковые команды имеют для восприятия прерываний специаль-ные окна.

Маскируемые прерывания вызываются переходом в высокий уровень сигна-ла на входе INTR (Interrupt Request) при установленном флаге разрешения (IF=1). В этом случае процессор вырабатывает два следующих друг за другом (back to back) цикла подтверждения прерывания, в которых контроллером шины генерируются управляющие сигналы INТА# (Interrupt Acknowledge). Высокий уровень сигнала INTR должен сох-раняться по крайней мере до подтверждения прерывания. Первый цикл под-тверждения прерывания обеспечивает выполнение контроллером прерываний процедуры арбитража запросов на прерывание и формирование номера прерывания. По второму импульсу INТА# внешний контроллер прерываний передает по системной шине в процессор сформированный им номер прерывания, обслуживающего данный тип аппаратного прерывания. Прерывание с полученным номером вектора выполняется процес-сором так же, как и программное (свое текущее состояние (IP, CS, F) процессор сохраняет в стеке, из номера прерывания формирует АВП, читает из вектора прерывания программный адрес (IP:CS) первой исполняемой команды программы обслуживания прерывания, формирует из IP:CS физический адрес и читает команду по этому адресу). Обработка текущего прерывания может быть в свою очередь прервана немаскируемым прерыванием, а если программа-обработчик уста-новит флаг IF, то и другим маскируемым аппаратным прерыванием.

Немаскируемые прерывания выполняются независимо от состояния флага IF по сигналу NMI (Non Mascable Interrupt). Вход NMI процессора асинхронный с запуском по фронту сигнала (переход от низкого уровня к высокому), который вызовет прерывание с типом (номером) 2. Немаскируемое прерывание выполняется так же, как и маскируемое. Его обработка не может прерываться под действием сигнала на входе NMI до выполнения команды IRET.

Исключения (Exceptions) подразделяются на отказы, ловушки и аварийные завершения. Отказ (fault) - это исключение, которое обнаруживается и обслуживается до выполнения инструкции, вызывающей ошибку. После обслуживания этого ис-ключения управление возвращается снова на ту же инструкцию (включая все префиксы), которая вызвала отказ. Отказы, использующиеся в системе вирту-альной памяти, позволяют, например, подкачать с диска в оперативную память затребованную страницу или сегмент. Ловушка (trap) - это исключение, которое обнаруживается и обслуживается после выполнения инструкции, его вызывающей. После обслуживания этого исключения управление возвращается на инструкцию, следующую за вызвавшей ловушку. К классу ловушек относятся и программные прерывания по командам INT xx. Аварийное завершение (abort) - это исключение, которое не позволяет точно установить инструкцию, его вызвавшую. Оно используется для сообщения о серьезной ошибке, такой как аппаратная ошибка или повреждение системных таблиц. Набор и обработка исключений реального и защищенного режимов различ-ны. Под исключения Intel резервирует векторы 0-31 в таблице прерываний, однако в персональных компьютерах часть из них перекрывается системными прерываниями BIOS и DOS. Процедура, обслуживающая прерывание или исключение, определяется по таблице с помощью номера прерывания. Для программных прерываний номер задается командой (или во втором байте команды INT xx), а исключения генерируют и передают номер прерывания внутри процессора. Каждому номеру (0-255) прерывания или исключения в защищенном режиме соответствует эле-мент в таблице дескрипторов прерываний IDT (Interrupt Descriptor Table). В реальном режиме таблица прерываний содержит двойные слова - программные адреса обслуживающих процедур и после сброса располагается, начиная с нуле-вых адресов. Командой LIDT можно изменять ее положение в пределах первого мегабайта, а размер (03FFh) может быть уменьшен до 007Fh. При попытке обслуживания прерывания с номером, выходящим за заданный размер таблицы, генерируется исключение типа 8. В защищенном режиме таблица IDT содержит 8-байтные дескрипторы прерываний, может иметь размер от 32 до 256 дескрип-торов и располагаться в любом месте физической памяти. Анализ условий обслуживания прерываний и исключений выполняется в следующем порядке (по убыванию приоритета):

  • проверка на исключение (ловушка) отладки (типа 1) по выполненной ин- струкции (пошаговый режим через флаг TF или точка останова по данным через регистры отладки);
  • проверка на исключение (отказ) отладки (типа 1) по последующей инструкции (точка останова по инструкции через регистр отладки);
  • немаскируемое прерывание (аппаратное по входу NMI);
  • маскируемое прерывание (аппаратное по входу INTR при IF=l);
  • проверка на исключение (отказ) сегментации (типа 11 или 13) при выбор-ке следующей инструкции;
  • проверка на исключение (отказ) страницы (типа 14) при выборке следующей инструкции;
  • проверка на отказ декодирования следующей инструкции (типа 6 или 13);
  • для операции WAIT проверка TS и МР (исключение 7, если TS=4 и МР=1);
  • для операции ESCAPE (к мат. сопроцессору) проверка ЕМ и TS (исклю-чение 7, если EM=l или TS=1);
  • для операции WAIT или ESCAPE проверка на исключение 16 от сопро-цессора;
  • проверка на отказ сегментации (11, 12, 13) и страницы (14) для операндов, используемых в инструкции.

Двойной отказ (Double Fault) - исключение 8 - возникает, когда при обра-ботке исключения, связанного с сегментацией (10, 11, 12 или 13), процессор обнаруживает исключение, отличное от отказа страницы (14). Также двойной отказ возникает, если при отработке исключения отказа страницы (типа 14) обнаруживается исключение другого типа. В этом случае тоже исполняется исключение 8. Если во время обслуживания исключения отказа страницы произойдет еще один отказ страницы, то происходит отключение (Shutdown) процессора. Во время отключения никакие новые инструкции не выполняются. Из этого состо-яния процессор можно вывести только аппаратно сигналом NMI, оставляя его в защищенном режиме, или сигналом RESET, переводящим процессор в реальный режим. Прерывания и исключения процессора, работающего в защищенном режиме, приведены в табл. 1. Исключения реального режима, отличающиеся от защи-щенного, приведены в табл. 2.

Таблица 1. Прерывания и исключения защищенного режима

Номер

Функция

Переполнение при делении на 0

Исключение отладки

Немаскируемое прерывание (NMI)

Прерывание отладки (INT 3)

Прерывание по переполнению (INTO)

Прерывание по контролю диапазона (BOUND)

Недопустимый код операции

Сопроцессор недоступен или переключалась задача

Двойной отказ

Нарушение границы сегмента сопроцессором (только 386/387)

Недопустимый сегмент состояния задачи

Сегмент отсутствует

Нарушение границы сегмента стека или сегмент стека отсутствует

Общее нарушение защиты

Отказ страницы

Зарезервирован

Исключение сопроцессора

Контроль выравнивания (486+)

Зарезервированы

Программные прерывания INT n

*в реальном режиме имеют другое назначение (см. табл. 2).

** В реальном режиме не возникают, но возможны в V86.

Таблица 2. Исключения реального режима

При отработке исключения в защищенном режиме процессор сохраняет в стеке слово кода ошибки (Error Code). Если оно отлично от нуля, то оно содержит селектор дескриптора, с которым связана ошибка.