Обработка событий в жестком реальном времени

Сергей Семанин, Вторник, 14 Июнь 2005, 15:43

Основная задача ядра ОС жесткого реального времени (ЖРВ) - гарантировать время реакции задачи на внешнее по отношению к ней событие. Ядро ОС, работающей в критически малых интервалах реального времени, должно также минимизировать время реакции на события.

В настоящее время существует классификация ОС на ОС "" и "мя" реального времени. Системами "мягкого реального " (МРВ) называют ОС, в которых возможны опоздания реакции на события по отношению к регламентированому времени.

Приведу цитату из Е. Хухлаева:

В жесткой системе:


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

В мягкой системе реального времени:


<ul>
<li>повышается стоимость опоздания;</li>
<li>допускается низкая производительноть в случае опоздания.</li>
</ul>
Примером мягкой системы является подсистема сетевого интерфейса. Если подтверждение о приеме посланного пакета не поступило после истечения определенного времени, то пакет считается потерянным. В этом случае можно просто повторить посылку пакета и примириться со значительным снижением производительноти системы.

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

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

Ну, а как же решаются проблемы "мя" реального времери на студиях? А так: быстродействие процессора выбирается в сотни раз большим, чем необходимо для проигрывания или копирования видео- или аудиопрограммы, и категорически запрещается выполнять на компьютере, транслирующем в эфир, или копирующем программу, одновременное выполнение каких-либо других программ!!! Как видите, такое "реальное время" обходится дорогой ценой. Поэтому я считаю, что все ответственные и критичные ко времени действия, даже бытовые, должны выполняться системами ЖРВ.

Другое дело - регламент ЖРВ может быть разным, но ОБЯЗАТЕЛЬНЫМ! На мой взгляд, исходя из вышесказанного, МРВ системы могут быть применимы только при редактировании текста и рисовании окошек Ну, а как вы относитесь к системам, которые ничего не гарантируют, и ни за что не отвечают?

Еще один довод против МРВ: известно, что минимальное время реакции на события в NT составляет десятки микросекунд, столько же имеют последние патчи Линукса, сделанные Инго Молнаром. Но пиковые опоздания могут и в той и в другой ОС составить 30-40 мс. Ну и чудесно! объявим их ЖРВ с регламентированым временем реакции 100 мс (возьмем с запасом). Вопрос ЖРВ решен, раз и навсегда!!! Ну, а как быть, все-таки, в тех случаях, когда задачи, требующие гарантированнойреакции, работают в микросекундных интервалах?

Ну, теперь пора поговорить о составляющих жесткого реального времени, и какими путями возможно его достичь. Основными источниками событий в системах ЖРВ являются прерывания. Время от запроса прерывания до активизации процесса, ожидающего сигнала о событии, жестко регламентирован. В случае "одно прерывание - один " регламентироват время реакции нетрудно, если разработчик прикладной системы знает время обработки прерывания. А как быть в случае, когда прерываний много, причем запросы приходят одновременно?

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

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

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

Но как быть в случаях, если необходимо время реакции 1 мкс? Выбрать процессор с тактовой частотой в 10 раз больше? При серийном производстве систем "под клю", например, роутеров или бортовых систем автомобилей, такое удорожание приводит к значительным убыткам. Ладно, откажемся от обработки прерываний в кольце пользователя. Тогда время
реакции на том же процессоре получается 3 мкс. Ура, получили экономию! Ну, пока остановимся на этом.

Но теперь представим ситуацию, когда в системе имеется 16 источников прерываний, и все 16 требований прерывания возникли одновременно. А событие, которого мы в данный момент ожидаем, находится на самом нижнем приоритетном уровне. Учитывая полученные в результате экономии 3 мкс на каждую обработку, вычисляем суммарное время обработки предыдущих уровней: 3*15 = 45. Значит, время реакции на "" событие составит 45 мкс. Многовато. Подумаем, на чем можно сэкономить. Обращаем внимание на то, что, собственно, время обработки данных возникающих прерываний составляет не более 100 нс. Время вызова обработчика прерывания на физическом уровне - 800 нс. Добавим 100 нс на обработку данных. Теперь время обработки 15 прерываний составит 0.9 * 15 = 13.5 мкс! Теперь положим данные в буфер и просигналим потоку семафором. Время реакции на событие составило 13.5 + 3 (время реакции на уровне потока) = 16 мкс. Сравним с предыдущими 45 мкс - неплохо! Делаем вывод, что во многих (но не во всех) случаях выгодно обработку
прерываний выполнить на физическом уровне, а о событии просигналить потоку семафором.

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

Иллюстрирую пример с 16 прерываниями.
Нарисую, чтобы пояснить предсказуемостьи выгоду многоуровневой обработки.
Принимаю время физической обработки - 1 мкс,
время обработки события - 10 мкс,
время окончательной обработки данных - 100 мкс.



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

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

Выводы:

<ol>
<li>Требования к обработке прерываний и событий неоднозначны и не могут быть сведены к единой универсальной схеме.</li>
<li>Для реализации ЖРВ необходимо использовать гибкую многоуровневую схему обработки прерываний - событий.</li>
<li>Жесткая схема обработки прерываний на уровне потоков приемлема лишь в тех случаях, когда быстродействие процессора выбирается в десятки - сотни раз большим, чем это необходимо при использовании многоуровневой схемы.</li>
</ol>

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

Начну с приоритетов: обработка прерываний на уровне потоков допустима только в потоках с наивысшими пиоритетами. Представьте себе ситуацию, когда обработка прерывания выполняется на среднем приоритете, и эту обработку вытесняет поток с большим приоритетом! В этом случае обработка может быть отложена на неопределенное время, а это недопустимо даже в системах "очень мя" реального времени. Поэтому для обработки прерываний на уровне потоков необходимо выделить N старших приоритетов в системе.

В схеме многоуровневой обработки прерываний, используемой в УжОС, обработка событий может производиться в старшей группе приоритетов жесткого реального времени, а отложенные прерывания могут быть обработаны в специально выделенном для этой цели диапазоне приоритетов. Это младшие 2 приоритета жесткого реального времени, на границе с приоритетной группой мягкого реального времени.

Как реализован механизм обработки прерываний в UzhOS на процессорах х86: аппаратные векторы прерываний передают управление диспетчеру прерываний, который регистрирует текущий физический приоритет обработки прерывания, устанавливает маски запрещеия прерываний, соответствующие текущему уровню, затем сообщает контроллеру о "конце прерывания". (контроллеры 8259 обладают недостатками, приводящими в определенных ситуациях к ложным прерываниям и блокировке входов IRQ, поэтому сигнал "конец прерывания" должен выдаваться как можно раньше. Существует опция работы с автоматическим оповещением о предоставлении прерывания). Затем обрабатывается список объектов физической обработки прерываний, установленный на текущем уровне. После вызова всех объектов обработки прерываний на текущем уровне проверяется предыдущий т.н. "уровень выполнения". Если предыдущий уровень меньше уровня выполнения диспетчера объектов, то проверяются флаги событий диспетчера. Если имеются события, то текущим устанавливается уровень выполнения диспетчера, и обрабатываются события диспетчера: старт и планирование объектов, переключение контекстов и т.п. Таким образом, диспетчер объектов выполняется на уровне физического прерывания с низшим приоритетом, исключается вложенность вызова диспетчера. Затем уровень выполнения снижается до предыдущего,устанавливаются маски запрещений прерываний, соответствующие предыдущему уровню, и осуществляется возврат из прерывания. Допускается полная вложенность обработок прерывания.

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

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

<ol>
<li>уровень ISR с заданным приоритетом. Выполняется на физическом уровне и предназначен для понижения текущего приоритета обработки;</li>
<li>уровень DeferredIrq, выполняется на специально выделенном уровне приоритета потока ЖРВ, имеет 16 приоритетов выполнения;</li>
<li>уровень CustomDPC, выполняется на специально выделенном уровне приоритета потока ЖРВ, имеет 16 приоритетов выполнения;</li>
<li>уровень асинхронной задачи ядра, выполняется в заранее созданном потоке ядра, имеет все свойства задачи ядра без ограничения. В контексте потока может вытеснять текущую задачу, имеет 16 уровней выполнения;</li>
<li>уровень асинхронной задачи пользователя, выполняется в заранее созданном потоке кольца пользователя, имеет все свойства задачи ядра без ограничения. В контексте потока может вытеснять текущую задачу, имеет 16 уровней выполнения;</li>
</ol>
Для пояснения п. 4 - 5 отмечу, что в ОС UzhOS поток не является конечной исполняемой инстанцией, а контекстом, в котором последовательноили с вытеснением могут выполняться до 16 уровней задач и DPC.

Для пояснения п. 2 - 3 отмечу, что отложенные обработчики класса "DPC" выполняются в контексте одного потока с вытеснением, но имеют ограничения, присущие обычным обработчикам прерывания: они не могут "" на семафоре и инициировать блокирующий ввод-вывод.

Теперь расскажу о приоритетах UzhOS в свете жесткого реалного времени. Диапазон приоритетов ОС - 255, и разбивается на следующие группы:

<ul>
<li>приоритеты 192-255 (64) - подгруппа приоритетов ЖРВ. На базовом приоритете этой подгруппы выполняется диспетчер отложенных прерываний (DpcForIsr). Т.о. задачи, выполняемые в этой подгруппе, имеют приоритет выше приоритетов процедур отложенных прерываний. Для критических секций отложенных прерываний используется базовый приоритет группы HRT +1. Т.е. при выполнении критических секций DpcForIsr возможно их вытеснение процедурами обработки физических прерываний и задачами HRT;</li>
<li>приоритеты 160-191 (32) - подгруппа приоритетов ЖРВ. На базовом приоритете этой подгруппы выполняется диспетчер отложенных прерываний (CustomDpc). Для критических секций отложенных прерываний CustomDpc используется базовый приоритет группы HRT +1;</li>
<li>приоритеты 60 - 159 - подгруппа приоритетов МРВ. Диапазон приоритетов этой группы - 100 - выбран из соображений совместимости с приоритетной схемой Linux;</li>
<li>приоритеты 8 - 59 - подгруппа динамических приоритетов. Соответствует приоритетной группе 0 Linux и приоритетной группе 4-15 NT;</li>
<li>приоритеты 0 - 7 - подгруппа "" (Idle) приоритетов. Соответствует приоритетной группе 0-3 NT; Не имеет аналога в Linux.</li>
</ul>

(продолжение следует)


это контент от Центр информации по операционным системам
( http://www.osrc.info/plugins/content/content.php?content.106 )