Программные каналы
Учебные материалы


Программные каналы



Карта сайта salutyoptom.ru

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

Рис. Одноканальная схема обмена 2-х процессов Процесс-1 Процесс-2 write Канал read =======> =======>

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

Общий канал Клиент-1 write ========> Сервер read ........ .... ========> Клиент-N ========> write Рис. Одноканальная схема обмена клиент-сервер

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

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

Процесс-1 write Канал-1 read Процесс-2 =========> =========> read Канал-2 write <========= <========= Рис. Двухканальный двунаправленный обмен 2-х процессов



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

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

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

Прочитанные блоки $$$$$$$$$ $$$$$$$$$ <= Указатель чтения Указатель => записи $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ $$$$$$$$$ Непрочитанные блоки Рис. Формальная модель канала

OS UNIX поддерживает 2 типа каналов: неименованные (или обычные) и именованные (или FIFO-файлы). Неименованные каналы поддерживают обмен данными только между процессами-родственниками, например, между предком и потомком или между потомками одного предка. Именованные каналы могут быть использованы для коммуникации любых, необязательно родственных, процессов. Каналы указанных типов создаются и открываются по-разному, но используются одинаково.

Неименованный канал создается и открывается системным вызовом

pipe

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

pipe

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

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

pipe

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

close

, чтобы освободить лишние канальные дескрипторы.

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

mkfifo

или

mknod

. Системный вызов

mkfifo

ориентирован исключительно на создание FIFO-файлов. Системный вызов

mknod

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

/etc/mkfifo

или универсальной командой

/etc/mknod

.

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

open

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

open

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

open

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

open

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

Обмен данными через обычный и именованный каналы реализован одинаково через системные вызовы

read

и

write

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

open

, системные вызовы

read

и

write

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

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

read

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

0

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

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

write

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

SIGPIPE

при попытке записи данных в канал.

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

O_NDELAY

или

O_NONBLOCK

с помощью системного вызова

fcntl

. Установка режимных флагов обеспечивает немедленный возврат кода

0

или

(-1)

системными вызовами ввода-вывода

read

и

write

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

open

.

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

close

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

rm

или системным вызовом

unlink

.

Следующий фрагмент C-кода демонстрирует передачу содержимого текстовой строки между двумя процессами через существующий

именованный

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

16.

Управление внешними устройствами в системе происходит на нескольких уровнях.

Самый верхний уровень представлен менеджером ввода/вывода (IOMAN). Это системный модуль, который содержит обработчики системных вызовов, связанных с вводом/выводом, и производит размещение в памяти необходимых структур. Интерфейс IOMAN к ядру специфицирован, поэтому пользователь может предложить свой модуль вместо стандартного.

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

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

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

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

19.

Управление памятью

Управление памятью в системе OS-9 является одним из самых совершенных среди систем ее класса. В основе лежит процесс "раскрашивания" памяти, который производится пользователем на этапе конфигурирования системы.

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

Эти принципы распределения памяти хорошо дополняют принцип открытости аппаратной конфигурации.

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

20.

Управление задачами

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

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

  • однозадачный режим - выделенный процесс монополизирует все системные ресурсы;

  • круговая (round-robin) диспетчеризация - системные ресурсы разделяются на равных несколькими процессами с самым большим приоритетом;

  • диспетчеризация на приоритетной базе (priority-based) - все процессы разделяют ресурсы пропорционально приоритетам.

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

21.

Поддержка внешних устройств

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

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

На принципиальном уровне для решения этой проблемы OS-9 предоставляет многоуровневую систему управления вводом/выводом. Две упомянутые задачи реально разводятся на системном уровне. За логические потоки отвечают файловые менеджеры, за физические - драйверы устройств. И те и другие специфицированы и доступны для написания и интеграции в систему.

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

Управление внешними устройствами в системе происходит на нескольких уровнях.

Самый верхний уровень представлен менеджером ввода/вывода (IOMAN). Это системный модуль, который содержит обработчики системных вызовов, связанных с вводом/выводом, и производит размещение в памяти необходимых структур. Интерфейс IOMAN к ядру специфицирован, поэтому пользователь может предложить свой модуль вместо стандартного.

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

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

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

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

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

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

Стандартные менеджеры

Стандартно с системой поставляются менеджеры для наиболее употребительных структур потоков:

  • pipeman - менеджер программного канала (обслуживает чисто логические структуры, построенные по принципу FIFO);

  • scf - менеджер байтового последовательного ввода/вывода (например, на терминал);

  • sbf - менеджер блочного последовательного ввода/вывода (например, на магнитную ленту);

  • rbf - менеджер блочного прямого доступа (например, к диску).

21.

Обработка исключительных ситуаций

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

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

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

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

Особым видом обработки исключения является обработка системного вызова. Это, ко всему прочему, означает, что обработка вызова может быть динамически изменена, а система может быть дополнена новыми вызовами. Обработка прерываний. Сигналы прерываний поступают от устройств не прямо на спец. процессор, а на спец. контроллер прерываний. Всего существует 16 прерываний от 0 - 15 0 - Наиболее приоритетное связано с системным таймером и не как не может быть использовано другим устройством. 1 - Закреплено за контроллером клавиатуры. 2 - Имеет техническое значение благодаря которому изначальное число прерываний было увеличено с 8 до 16. 3 - Используется вторым последовательным портом, однако если этот порт не нужен, то его можно отключить. 4 - Используется первым последовательным портом. 5 - Изначально является свободным и может использоваться различными устройствами по усмотрению пользователя или ОС. 6 - Закреплено за контроллером FDD. Не может быть использовано другими устройствами. 7 - Используется параллельным портом компьютера. Это прерывание при отключенном порте можно закрепить за другим устройством. 8 - Закреплено за часами реального времени. Это прерывание никогда не используется другими устройствами. 9 - Изначально является свободным, может использоваться платами расширения по усмотрению пользователя или ОС. Контроллер USB порта. 10 - Свободное, платы расширения. 11 - Изначально является свободным, но обычно используется видеоадаптерами. 12 - Жестко закреплено за мышью PS/2 13 - Жестко закреплено за встроенным или внешним математическим сопроцессором. 14 - Жестко закреплено за первым каналом контроллера. Не доступно для других IDE устройств. 15 - Жестко закреплено за вторым каналом IDE. С каждым устройством ввода - вывода связана область памяти называемая векторами прерываний. Выполняющий программу процессор может при необходимости приостановить процесс, чтобы обработать поступающую информацию. При обработке сигнала совершается необходимое действие, а затем продолжается работа приостановленной программы. Для того чтобы упорядочить обработку прерываний для каждого из них устанавливается приоритет. Прерывание Прерывание также является важным понятием в системном программировании, поскольку оно тесно связано с состоянием процесса и переключением процессов. Любая система управления процессами так или иначе использует прерывания. Прерывание - асинхронная прозрачная процедура (функция), вызываемая по внешнему событию. Прежде всего прерывание является процедурой, то есть некоторым алгоритмом, после выполнения которого происходит возврат к той части основной программы (точнее к тому состоянию процесса), в котором она была вызвана. Понятие асинхронная процедура означает, что она вызывается не как обычная процедура (функция) в языке программирования, то есть в основной программе (прерываемом процессе) отсутствует вызов этой процедуры в явном виде. Ее вызов осуществляется независимо от хода выполнения основной программы. Условием вызова ее является наступление некоторого внешнего по отношению к процессу события (например, поступление входных данных от внешнего устройства). Прерывающая процедура "вклинивается" между любыми последовательными шагами процесса, поэтому она должна обладать прозрачностью, то есть ее выполнение не должно влиять на прерываемый процесс. Можно сформулировать понятие прерывания и в терминологии процессов . Прерывание - приоритетный процесс, выполняемый по внешнему событию. В этом определении учитывается и асинхронный характер процессов, и их прозрачность по отношению друг к другу. Приоритетность обозначает, что основной (прерываемый) процесс не может выполняться до завершения процесса обработки прерывания. Обработка программного прерывания Программное прерывание имеет абсолютно такой же механизм реализации, что и обычное прерывание. Единственное отличие - источником прерывания является не внешнее событие, а специальная команда в программе. В связи с этим у программного прерывания теряется одно из важных свойств прерывания - асинхронность, оно становится обычной прозрачной процедурой. В связи с этим программное прерывание используется для взаимодействия с различными компонентами операционной системы, резидентными программами и т.п.. Сохранные в стеке регистры процессора в момент прерывания (формальные параметры функции обработки прерывания) могут использоваться для передачи параметров в вызываемую функцию (процедуру). Взаимодействие прерывающего процесса и основной программы Заметим, что функция обработки прерывания и основная (прерываемая) программа в приведенных выше терминах представляют собой процессы, которые протекают асинхронно, то есть независимо друг от друга. Условность этого случая состоит в том, что эти процессы неравноправны, но все равно на них распространяются все проблемы, связанные с взаимодействием таких процессов между собой, иначе говоря, синхронизацией. Самый простой способ синхронизации заключается в использовании общих глобальных переменных, которые изменяются одним из процессов и проверяются другим. Ввод-вывод данных по прерыванию Наиболее часто прерывание используется для организации обмена данными с относительно медленными устройствами, чтобы программа " не теряла зря времени" при ожидании готовности устройства к вводу-выводу очередной порции информации. В таком случае возникает уже физический параллелизм между выполняемой программой и операцией ввода-вывода, производимой устройством. Отложенное прерывание (Fork-обработка) При проектировании операционных систем и систем реального времени необходимо учитывать, насколько долго продолжается процесс обработки прерывания. В самом простом случае, когда при обработке прерывания повторные прерывания запрещены, временные задержки в обработке прерываний могут существенно ухудшить реактивность системы в целом. Тогда для выполнения продолжительных действий по обработке прерывания вводится так называемый " отложенный" режим их выполнения. В процессе реакции на прерывание обработчик выполняет при запрещенном прерывании только первичные действия, например, считывает данные. Затем процесс обработки продолжается уже при разрешенном прерывании и называется " отложенной обработкой" . При этом последующие прерывания не должны входить в фазу " отложенной" обработки, они просто оставляют собственные считанные данные в некоторой структуре, которая моделирует очередь. Взаимодействие " отложенной обработки" и последующих прерываний очень просто синхронизируется самой очередью Заметим, что как и во всех случаях синхронизации процессов через общие переменные, проверка и изменение этих переменных должна производиться при запрещенном прерывании. На самом деле " отложенную обработку" можно рассматривать как отдельный процесс, который расположен " между" обработчиком прерываний и основным процессом. Обработка прерываний. Типы прерываний. Переключение контекста процессов в IBM PC Все смены состояний процессов происходят по прерываниям. Прерывание - это событие / сигнал, заставляющий ЦП изменить текущий порядок исполнения команд процесса. Существуют аппаратные и программные прерывания. Аппаратные прерывания инициируются аппаратурой (например, сигнал микросхемы таймера), сигналом принтера, нажатием клавиш и т.д. Программные прерывания инициируются процессом и ничего не прерывают. Это обычные процедуры, которые используются программами для выполнения рутиной работы. Однако, эти программы содержатся в ОС, и механизм прерываний дает возможность обратиться к ним из программ пользователей. Программные прерывания могут быть вложенными. Так, аппаратные прерывания могут возникнуть при выполнении программных. Когда разрешенное прерывание вызывается, ЦП оставляет свою работу, выполняет прерывание, затем возвращается в место прерывания. Обработка прерываний состоит в следующем: 1. При возникновении прерывания, управление передается в ОС. 2. ОС запоминает состояние прерванного процесса в PCB процесса. 3. ОС анализирует тип прерывания и передает управление соответствующему обработчику. После обработки прерывания ОС либо продолжает выполнять процесс, либо запускает готовый процесс с наивысшим приоритетом. Существует 6 классов прерываний. 1. Программы-прерывания по системной директиве. Инициатор - активный процесс, выполнивший обращение к супервизору, то есть запрос на предоставление ОС системной вычислительной услуги. 2. Прерывания ввода-вывода. Инициируются устройством ввода/вывода (УВВ) и сигнализируют ЦП о том, что произошло изменение состояния канала ввода-вывода (КВВ) или УВВ (например: завершение операции, ошибка, переход устройства в состояние готовности). 3. Внешние прерывания. Нажатие операторами клавиш на панели ЭВМ или прием сигнала прерывания от другого ЦП в мультипроцессорной системе, сигнала от модема. 4. Прерывание по рестарту. Нажатие оператором кнопки рестарта или Reset. 5. Логические прерывания по контролю программы вызываются программными ошибками, обнаруженными при выполнении программы (деление на 0, попытка выполнить привилегированную команду в пользовательском режиме, неверный код операции, защита памяти и т.д.). 6. Прерывания по контролю машины из-за аппаратных ошибок прерывания упорядочены по приоритетам. Определенный тип прерываний запрещает свой тип и младшие и разрешает старшие. ЦП реагирует только на разрешенные прерывания, обработка запрещенных прерываний либо задерживается, либо, в некоторых случаях, игнорируется.

23. 1.2. Архитектура ядра системы QNX

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

┌───────────────────────┐ ┌────────────────────────┐

│ Администратор │ │ Администратор │

│ процессов ├──┐ ┌──┤ файловой системы │

└───────────────────────┘ │ │ └────────────────────────┘

┌──┴──────┴──┐

│ Микроядро │

└──┬──────┬──┘

┌─────────────────────────┐ │ │ ┌────────────────────────┐

│ Администратор │ │ │ │ Сетевой │

│ устройств ├─┘ └──┤ администратор │

└─────────────────────────┘ └────────────────────────┘

Микроядро системы QNX координирует работу системных администраторов.

Рис. 1

1.2.1. Ядро системы QNX

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

В системе QNX ядро является действительно ядром. Прежде всего, как и подобает ядру операционной системы реального времени, оно имеет небольшой размер - менее 8 Кбайт. На ядро системы QNX возложено выполнение только двух основных функций:

- передача сообщений (ядро реализует передачу всех сообщений между всеми процессами во всей системе);

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

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

1.2.2. Системные процессы

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

- Администратор процессов (Proc);

- Администратор файловой системы (Fsys);

- Администратор устройств (Dev);

- Сетевой администратор (Net).

1.2.2.1. Системные процессы и процессы пользователя

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

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

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

Предположим, что вы написали сервер базы данных. Как следует классифицировать эту программу?

Сервер базы данных должен выполнять функции, аналогичные функциям Администратора файловой системы, который получает запросы (сообщения) на открытие файлов и чтение или запись данных. Несмотря на то, что запросы к серверу базы данных могут быть более сложными, и в том и в другом случае формируется набор примитивов (посредством сообщений), в результате чего обеспечивается доступ к системному ресурсу. В обоих случаях речь идет о процессах, которые могут быть написаны конечным пользователем и выполняться по необходимости. Таким образом, сервер базы данных можно рассматривать как системный процесс в одном случае и как прикладной в другом. Фактически нет никакой разницы. Важно отметить, что в системе QNX подобные процессы включаются без каких бы то ни было модификаций других компонентов операционной системы.

24. АДМИНИСТРАТОР ПРОЦЕССОВ

3.1. Введение

3.1.1. Функции Администратора процессов

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

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

3.1.2. Примитивы создания процесса

В системе QNX существует три примитива создания процесса:

fork()

exec()

spawn()

Примитивы fork() и exec() определены стандартом POSIX, а примитив spawn() реализован только в QNX.

3.1.2.1. fork()

Примитив fork() порождает процесс, являющийся его точной копией. Новый процесс выполняется в том же адресном пространстве и наследует все данные порождающего процесса.

3.1.2.2. exec()

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

3.1.2.3. spawn()

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

3.1.3. Что наследует процесс

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

───────────────────────────────────────────────────────────────────

Что наследуется fork() exec() spawn()

───────────────────────────────────────────────────────────────────

Идентификатор процесса Нет Да Нет

Открытые файлы Да На выбор* На выбор

Блокировка файлов Нет Да Нет

Задержанные сигналы Нет Да Нет

Маска сигнала Да На выбор На выбор

Игнорируемые сигналы Да На выбор На выбор

Обработчик сигналов Да Нет Нет

Переменные среды Да На выбор На выбор

Идентификатор сеанса Да Да На выбор

Группа процесса Да Да На выбор

Реальные идентификаторы Да Да Да

группы и пользователя

( UID, GID )

Эффективные UID, GID Да На выбор На выбор

Текущий рабочий каталог Да На выбор На выбор

Маска создания файлов Да Да Да

Приоритет Да На выбор На выбор

Метод планирования Да На выбор На выбор

Виртуальные каналы Нет Нет Нет

Символические имена Нет Нет Нет

Таймеры реального времени Нет Нет Нет

───────────────────────────────────────────────────────────────────

Примечание.

* - вызывающий процесс может по необходимости выбрать - да или нет.

3.2. Жизненный цикл процесса

Каждый процесс проходит следующие четыре фазы:

1. Создание;

2. Загрузку;

3. Выполнение;

4. Завершение.

3.2.1. Создание

Создание процесса заключается в присвоении идентификатора процесса (ID) новому процессу и задании информации, определяющей программную среду нового процесса. Большая часть этой информации наследуется от "родителя" нового процесса (см. предыдущий параграф).

3.2.2. Загрузка

Загрузка образов процессов выполняется загрузчиком "по цепочке". Загрузчик входит в состав Администратора процессов и выполняется под идентификатором нового процесса. Это позволяет Администратору процессов выполнять другие запросы при загрузке программ.

3.2.3. Выполнение

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

3.2.4. Завершение

Процесс завершается одним из двух способов:

- по сигналу, определяющему процесс завершения;

- при возврате управления по функции exit() - явно, либо по функции main() - по умолчанию.

Завершение включает в себя две стадии:

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

- все виртуальные каналы, которые имел процесс;

- вся память, выделенная процессу;

- все символические имена;

- все номера основных устройств (только для администраторов ввода/вывода );

- все обработчики прерываний;

- все proxy;

- все таймеры.

2. После запуска программы завершения к породившему его процессу посылается уведомление о завершении процесса (эта фаза выполняется внутри Администратора процессов).

Если породивший процесс не выдал wait() или waitpid(), то порожденный процесс становится так называемым "зомби"-процессом и не завершается до тех пор, пока породивший процесс не выдаст wait() или не завершится сам.

Для того, чтобы не ждать завершения порожденного процесса, следует либо установить признак _SPAWN_NOZOMBIE в функциях qnx_spawn() или qnx_spawn_option(), либо в функции signal() задать для SIGCHLD признак SIG_IGN. В этом случае порожденные процессы при завершении не становятся "зомби"-процессами.

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

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

25. 3.3. Состояния процессов

Процесс всегда находится в одном из следующих состояний:

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

BLOCKED (блокирован) - процесс находится в одном из следующих состояний блокировки:
SEND-блокирован;
RECEIVE-блокирован;
REPLY-блокирован;
SIGNAL-блокирован;

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

WAIT- (ожидает) - процесс выдал wait() или waitpid() и ожидает информацию о состоянии порожденных им процессов;

DEAD (мертв) - процесс завершен, но не может передать информацию о своем состоянии породившему его процессу, поскольку тот не выдал функцию wait() или waitpid(). За завершенным процессом сохраняется состояние, но занимаемая им память освобождается. Процесс в состоянии DEAD также называют "зомби"-процессом.

ВНИМАНИЕ. Более подробно состояния блокировок рассмотрены в разделе 2 "Микроядро".

На рис. 15 представлены возможные состояния процесса в системе QNX.

┌────────┐ ┌────────┐

│ HELD │ │ SEND ├─────┐

└────────┘ │ блокир.│ │

_ │12 └───┬────┘ │

│ │ │ _ │2

│ └───────────┐ │ │ │

11 └────────────┐_ 1_ │6 _

┌───────┐ 9 ┌──┴─────┐ 3 ┌─────────┐ 7 ┌──────────┐

│ WAIT ││ READY │<───┤ REPLY ├<────┤ SIGNAL │

│ожидает│10 └────┬─┬─┘5 │блокиров.├────>┤блокирован│

└───────┘ │ _─────┐└─────────┘ 8 └──────────┘

└──────┐└───────────────_ 4

14 13 ┌─────┴─────┐ ┌────┴─────┐

освобож- <──────────┤ DEAD │ │ RECEIVE │

дение про- │ (зомби) │ │блокирован│

цесса └───────────┘ └──────────┘

Определены следующие переходы из одного состояния в другое:

1. Процесс посылает сообщение.

2. Процесс-получатель принимает сообщение.

3. Процесс-получатель отвечает на сообщение.

4. Процесс ожидает сообщения.

5. Процесс принимает сообщение.

6. Сигнал разблокирует процесс.

7. Сигнал пытаетcя разблокировать процесс;

получатель запрашивает сообщение о захвате сигнала.

8. Процесс-получатель принимает сигнал.

9. Процесс ожидает завершения порожденного процесса.

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

процесс.

11. Процессу выдан SIGSTOP.

12. Процессу выдан SIGCONT.

13. Процесс завершается.

14. Порождающий процесс ожидает завершения, завершается сам или уже

завершен.

Рис.15

3.3.1. Определение состояний процессов

Определить состояние конкретного процесса возможно:

из интерпретатора (Shell) - с помощью утилит ps или sin;

из программы - с помощью функции qnx_psinfo().

Определить состояние операционной системы в целом возможно:

из интерпретатора - с помощью утилиты sin;

из программы - с помощью функции qnx_osinfo().

Утилита ps определена стандартом POSIX, следовательно командные файлы с ее использованием являются мобильными. Утилита sin уникальна в QNX, она предоставляет полезную информацию о системе QNX, которую нельзя получить с помощью утилиты ps.

3.4. Символические имена процессов

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

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

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

В случае работы в сети проблема усложняется, т.к. сервер должен обслуживать клиентов, которые находятся на разных узлах сети. В QNX имеется возможность поддерживать работу как с глобальными, так и с локальными именами. Глобальные имена доступны во всей сети, а локальные - только на том узле, где они зарегистрированы. Глобальные имена начинаются со знака слэш (/). Например:

qnx локальное имя;

company/xyz локальное имя;

/company/xyz глобальное имя.

ВНИМАНИЕ. Рекомендуем начинать все имена с названия вашей фирмы, во избежание конфликтов с другими производителями программной продукции по поводу имен программ.

Для того, чтобы использовать глобальные имена хотя бы на одном из узлов сети, необходимо запустить "определитель имен процессов" (утилита nameloc). Этот процесс содержит записи всех зарегистрированных глобальных имен.

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

Для регистрации имени процесс-сервер использует функцию Си qnx_name_attach(). Для определения имени процесса процесс-клиент использует функцию Си qnx_name_locate().

2.3.2. Синхронизация процессов

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

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

ВНИМАНИЕ. Более подробно механизм планирования работы процессов рассмотрен в подразделе 2.7 "Планирование процессов".

2.3.3. Состояния блокировок

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

Состояния блокировок процессов приведены в следующей таблице.

────────────────────────────────────────────────────────────────

Если процесс выдал Процесс является



edu 2018 год. Все права принадлежат их авторам! Главная