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

При работе микропроцессорной системы часто возникают ситуации, когда требуется прервать выполнение текущей программы и перейти к подпрограмме, обеспечивающей необходимую реакцию системы на создавшиеся обстоятельства. Такие ситуации называются прерываниями (илиисключениями) в зависимости от причин, вызывающих их возникновение. В данной главе мы рассмотрим механизмы возникновения и обработки прерываний на примере процессоров семейства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). При ошибке в качестве адреса возврата к прерванной программе сохраняется адрес инструкции, выполнение которой вызвало данное исключение.

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

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

Прерывания подразделяются на аппаратные, вызываемые электрическими сигналами на входах процессора, и программные, выполняемые по команде INTxx.

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

По прерыванию или исключению процессор сохраняет в стеке регистр (E)FLAGS и указатель CS:(E)IP на ту инструкцию, которую он должен будет выполнить после обработки прерывания. Этой инструкцией будет следующая за той, во время исполнения которой произошло прерывание. В защищенном режиме при возникновении ряда исключений в стеке сохраняется еще и код ошибки. После сохранения этих значений процессор переходит к исполнению программы обработки данного прерывания (исключения), определяя точку входа в него через номер (0-255) по таблице прерываний. Последней командой обработчика прерывания должна быть инструкция возврата IRET, по которой из стека восстанавливается указатель CS:(E)IP и прежнее значение флагов. Таким образом, процессор по команде прерываний выполняет следующие действия:

1. записывает в стек, по адресу SS:SP-2, содержимое регистра флагов;

2. записывает в стек по адресу SS:SP-4, содержимое сегментного регистра команд.

3. записывает в стек SS по адресу SS:SP-6 содержимое регистра указателя команд IP;

5. вычисляет адрес вектора прерываний (содержимое регистра АН умножает на 4 и получает адрес вектора, где хранятся CS и IP программы обрабатывающей данное прерывание). Область векторов прерываний находится в памяти с адреса 000H по 3FFH. Причем в каждом векторе, длинной в 4 байта, в двух байтах, по младшим адресам, находится IP, а двух байтах старших адресов CS;

6. выставляет вычисленный адрес на шину адресов и загружает из памяти в регистры CS и IP содержимое вектора;

7. разрешает внешние прерывания, IF: = 1;

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

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

Маскируемые прерывания выполняютсяпри установленном флаге разрешения (IF=1).

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

Исключения (Exceptions), или особые случаи, подразделяются на отказы, ловушки и аварийные завершения. Различия заключаются в сохраняемых значениях CS:(E)IP.

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

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

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

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

хорошую работу на сайт">

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

Размещено на http://www.allbest.ru

Министерство образования Республики Беларусь

УЧРЕЖДЕНИЕ ОБРАЗОВАНИЯ «ГРОДНЕНСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ ИМЕНИ ЯНКИ КУПАЛА»

Кафедра теоретической физики.

Реферат на тему:

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

Студента 5 курса физико-технического факультета

Пецевича Андрея Ивановича

Гродно 2014

  • 1. Прерывания
    • 1.1 Oбрабoтка прерываний
    • 1. Внешние
    • 2. Внутренние
    • 3. Программные
    • 1.2 Векторы прерываний
    • 1.4 Типы прерываний
  • 2. Исключения
    • 2.3 Обработчики исключений

1. Прерывания

1.1 Oбрабoтка прерываний

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

1. Внешние;

2. Внутренние;

3. Программные.

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

Например прерывание с номером 9 - прерывание от клавиатуры, которое генерируется при нажатии и при отжатии клавиши. Используется для чтения данных с клавиатуры. Обозначается в ОС как IRQ1, где IRQ - обозначение прерывания, а 1 - приоритет прерывания.

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

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

1.2 Векторы прерываний

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

Таблица векторов прерываний занимает первый килобайт оперативной памяти - адреса от 0000:0000 до 0000:03FF. Таблица состоит из 256 элементов - FАR-адресов обработчиков прерываний. Эти элементы называются векторами прерываний. В первом слове элемента таблицы записано смещение, а во втором - адрес сегмента обработчика прерывания. Векторами являются просто полные адреса памяти программы (в сегментированной форме), которая должна быть активизирована в случае возникновения прерывания.

Прерыванию с номером 0 соответствует адрес 0000:0000, прерыванию с номером 1 - 0000:0004 и т.д. Адрес такой состоит из пары 2-байтовых слов, поэтому каждый из векторов занимает четыре байта.

Можно просмотреть таблицу векторов прерываний в компьютере, если воспользоваться программой DЕBUG. Используйте команду D для вывода содержимого начала памяти: D 0:0. Программа DЕBUG покажет вам первые 128 байтов или 32 вектора, которые могут иметь вид наподобие следующего:

1.3 Механизм обработки прерываний

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

· Восприятие запроса на прерывание: прием сигнала и идентификация прерывания.

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

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

· Обработка прерывания.

· Восстановление прерванного процесса и возврат в прерванную программу.

Главные функции механизма прерывания:

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

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

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

1.4 Типы прерываний

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

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

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

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

· Прерывание, которое информирует систему о том, что требуемый сектор диска уже прочитан, его содержимое доступно программе.

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

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

· Нормальное завершение некоторой операции ввода-вывода (нажатие клавиши на клавиатуре).

· Прерывание по таймеру.

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

Маскируемые и немаскируемые внешние прерывания

Существуют два специальных внешних сигнала среди входных сигналов процессора, при помощи которых можно прервать выполнение текущей программы и тем самым переключить работу центрального процессора. Это сигналы NMI (Nоn Mаsсаblе Intеrrupt, немаскируемое прерывани)INTR (intеrrupt rеquеst, запрос на прерывание).

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

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

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

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

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

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

· при делении на нуль.

· при переполнении или исчезновении порядка.

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

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

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

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

2. Исключения

Обработка исключительных ситуаций (exception handling) -- механизм языков программирования, предназначенный для описания реакции программы на ошибки времени выполнения и другие возможные проблемы (исключения), которые могут возникнуть при выполнении программы и приводят к невозможности (бессмысленности) дальнейшей отработки программой её базового алгоритма. В русском языке также применяется более короткая форма термина: «обработка исключений».

прерывание исключение программа ошибка

2.1 Общее понятие исключительной ситуации

Во время выполнения программы могут возникать ситуации, когда состояние данных, устройств ввода-вывода или компьютерной системы в целом делает дальнейшие вычисления в соответствии с базовым алгоритмом невозможным или бессмысленными. Классические примеры подобных ситуаций приведены ниже Нулевое значение знаменателя при выполнении операции целочисленного деления. Результата у операции быть не может, поэтому ни дальнейшие вычисления, ни попытка использования результата деления не приведут к решению задачи. Ошибка при попытке считать данные с внешнего устройства. Если данные не удаётся ввести, любые дальнейшие запланированные операции с ними бессмысленны. Исчерпание доступной памяти. Если в какой-то момент система оказывается не в состоянии выделить достаточный для прикладной программы объём оперативной памяти, программа не сможет работать нормально. Появление сигнала аварийного отключения электропитания системы. Прикладную задачу, по всей видимости, решить не удастся, в лучшем случае (при наличии какого-то резерва питания) прикладная программа может озаботиться сохранением данных.Появление на входе коммуникационного канала данных, требующих немедленного считывания. Чем бы ни занималась в этот момент программа, она должна перейти к чтению данных, чтобы не потерять поступившую информацию.

2.2 Виды исключительных ситуаций

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

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

В отсутствие собственного механизма обработки исключений для прикладных программ наиболее общей реакцией на любую исключительную ситуацию является немедленное прекращение выполнения с выдачей пользователю сообщения о характере исключения. Можно сказать, что в подобных случаях единственным и универсальным обработчиком исключений становится операционная система. Например, в операционную систему Windows встроена утилита Dr. Watson, которая занимается сбором информации об необработанном исключении и ее отправкой на специальный сервер компании Microsoft. Возможно игнорирование исключительной ситуации и продолжение работы, но такая тактика опасна, так как приводит к ошибочным результатам работы программ или возникновению ошибок впоследствии. Например, проигнорировав ошибку чтения из файла блока данных, программа получит в своё распоряжение не те данные, которые она должна была считать, а какие-то другие. Результаты их использования предугадать невозможно. Обработка исключительных ситуаций самой программой заключается в том, что при возникновении исключительной ситуации, управление передаётся некоторому заранее определённому обработчику -- блоку кода, процедуре, функции, которые выполняют необходимые действия. Существует два принципиально разных механизма функционирования обработчиков исключений.

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

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

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

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

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

Размещено на Allbest.ru

Подобные документы

    Предотвращение или выявление ошибочных ситуаций в ходе выполнения программы. Стандартная обработка исключений, программные средства. Назначение программных блоков try, catch, final. Главные особенности конфигурирования исключений с помощью флажков.

    лекция , добавлен 09.12.2013

    Принципы и алгоритмы обработки прерываний. Набор действий по реализации этапов обработки прерываний микропроцессора. Разработка структуры и алгоритма резидентной программы. Реализация программы на языке Ассемблер, методы её отладки и тестирования.

    курсовая работа , добавлен 22.12.2014

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

    реферат , добавлен 22.06.2011

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

    доклад , добавлен 22.09.2008

    Проектирование механизма обработки прерываний. Контроллер прерываний Intel 82C59A. Ввод-вывод по прерыванию. Программируемый контроллер интерфейса Intel 82C55A. Роль процессора в обработке прерывания ввода-вывода. Обзор алгоритма обработки прерывания.

    контрольная работа , добавлен 19.05.2010

    Виртуальные функции, статические и абстрактные классы, шаблоны: элементы и члены класса, их роль в объектно-ориентированном программировании; механизм осуществления виртуального вызова при выполнении программы; обработка исключительных ситуаций в C++.

    реферат , добавлен 06.12.2010

    Фаза "избавления" программы от ошибок. Задача обработки ошибок в коде программы. Ошибки с невозможностью автоматического восстановления, оператор отключения. Прекращение выполнения программы. Возврат недопустимого значения. Директивы РНР контроля ошибок.

    учебное пособие , добавлен 27.04.2009

    Написание алгоритма приема 10 пакетов по 12 байт из последовательного порта и размещение их в памяти PRAM. Создание управляющего блока PTSCB для режима блоковой передачи данных. Аппаратная обработка прерываний в режима аналого-цифрового сканирования.

    практическая работа , добавлен 25.04.2012

    Коды, обрабатывающие исключения, информация о причине их возникновения. Способы обработки исключений. Механизмы обработки исключений. Инициализация ссылки на объект. Конструкторы стандартных исключений. Автоматическая и программная генерации исключений.

    презентация , добавлен 21.06.2014

    Принципы организации и особенности обработки прерываний на основе контроллера 8259A. Общая характеристика аппаратных средств системы прерываний PIC (Programmable Interrupt Controller). История разработки и порядок работы с технологией Plag and Play.

Прерывания и исключения нарушают нормальный ход выполнения программы для обработки внешних событий или сигнализации о возникновении особых условий или ошибок. По прерыванию или исключению процессор сохраняет в стеке регистр (E)FLAGS и указатель CS:(E)IP на ту инструкцию, которую он должен будет выполнить после обработки прерывания. Этой инструкцией будет следующая за той, во время исполнения которой произошло прерывание, или та же самая (в защищенном режиме при возникновении ряда исключений в стеке сохраняется еще и код ошибки). После сохранения этих значений процессор переходит к исполнению кода обработчика данного прерывания (исключения), определяя точку входа в него через номер (0-255) по таблице прерываний. Номер элемента в таблице прерываний называется вектором прерывания, он определяется источником прерывания (исключения). Обработчик прерывания (исключения) должен заканчиваться специальной инструкцией возврата IRET, по которой из стека восстанавливается указатель CS:(E)IP и прежнее значение флагов. Для исключений, в которых сохраняется и код ошибки, обработчик до выполнения инструкции IRET должен извлечь из стека код ошибки. Различают четыре источника прерываний.

  1. Внутренние прерывания (исключения) процессора и сопроцессора; вектор определяется типом произошедшего события.
  2. Немаскируемые внешние прерывания по входу NMI; вектор фиксирован (01).
  3. Маскируемые внешние прерывания по входу INT (или по шине APIC); вектор передается контроллером прерываний.
  4. Программно-вызываемые прерывания; вектор определяется в команде.
Последние из этого списка в прямом смысле прерываниями не являются, поскольку представляют собой лишь специфический способ вызова процедур – не по адресу, а по его номеру в таблице, причем независимо от состояния флага IF. Программные прерывания широко используются для вызовов сервисов BIOS и ОС – это компактно и удобно.
В начале отработки любого (в том числе и программного) прерывания процессор сбрасывает флаг разрешения прерываний IF. Процедура обработки завершается инструкцией IRET, по которой из стека восстанавливаются автоматически сохраненные регистры (в восстановленном регистре флагов прерывания разрешены) и процессор начинает выполнение инструкции, следующей за той, после которой исполнялось прерывание. Конечно, программно во время обслуживания прерывания возможно умышленное или случайное изменение указателя или содержимого стека, и тогда инструкция IRET «отправит» процессор по другому адресу, в результате чего компьютер может и зависнуть. Если на время обработки требуется реакция и на другие прерывания, обработчик должен установить флаг IF. Прерывания, обслуживаемые до завершения обработки предыдущего, называются вложенными. Вложенные прерывания могут создавать опасность переполнения стека, поскольку каждое «вложение» будет использовать его для своих целей. Переполнение стека может также являться причиной зависаний. Длинные процедуры обработки со сброшенным флагом IF могут привести к потере системного времени, поскольку «часы» операционной системы используют аппаратные прерывания от таймера. Процедура обслуживания для каждого источника аппаратных прерываний должна быть написана весьма осмотрительно и учитывать нюансы работы остальных подсистем.
Маскируемые внешние прерывания обрабатываются процессором по сигналу на входе INT только при установленном флаге разрешения прерываний IF.
Немаскируемые прерывания обрабатываются процессором независимо от состояния флага разрешения прерывания IF. К ним относятся прерывания, по линии NMI (Non-Maskable Interrupt), а для процессоров, поддерживающих режим системного управления, еще и по линии SMI# (System Management Interrupt).
Внутренние прерывания процессора (исключения) генерируются при возникновении особых условий выполнения текущей инструкции. В большинстве своем они не столько асинхронны, сколько неожиданны для исполнения программного кода. Номер вектора определяется процессором в зависимости от происхождения исключения.
Каждому номеру (0-255) прерывания или исключения соответствует элемент в таблице дескрипторов прерываний IDT (Interrupt Descriptor Table). В реальном режиме таблица прерываний содержит дальние адреса (двойные слова) обслуживающих процедур и после сброса располагается, начиная с нулевых адресов. В защищенном режиме таблица IDT содержит 8-байтные дескрипторы прерываний, может хранить от 32 до 256 дескрипторов и располагаться в любом месте физической памяти.
Под исключения (внутренние прерывания) в процессорах Intel резервируются векторы 0-31 в таблице прерываний, однако в PC часть из них перекрывается системными прерываниями – сервисами BIOS и DOS, а также аппаратными прерываниями. Эти перекрытия особенно неприятны для защищенного режима; они усложняют процедуры обработчиков прерываний.
Для обработки аппаратных прерываний в многопроцессорных системах традиционные аппаратные средства становятся непригодными, поскольку прежняя схема подачи запроса INTR и передачи вектора в цикле INTA* явно ориентирована на единственность процессора. Для решения этой задачи в процессоры, начиная со второго поколения Pentium, введен расширенный программируемый контроллер прерываний APIC (Advanced Programmable Interruption Controller).

Прерывания и исключения – это состояния в ОС, переключающие процессор на код, лежащий вне нормального потока команд. Они обнаруживаются аппаратно и программно. При обнаружении прерывания или исключения процессор прекращает выполнять текущее действие и передает управление в особое место памяти – по адресу кода, обрабатывающего возникшее состояние. В 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 ). Создав такой объект и добавив его в другую очередь ядра, драйвер определяет перед началом операции, которую нельзя прервать (например, запись данных в регистр устройства), не произошел ли сбой питания. Если он произошел, драйвер не выполняет операцию.