8. Администраторы ресурсов


Введение

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

Администраторы ресурсов, как правило, предназначены для обеспечения интерфейса с различными типами устройств, в том числе физическими устройствами (например, последовательными и параллельными портами, сетевыми платами, жесткими дисками) и виртуальными устройствами (например, /dev/null, сетевой файловой системой, псевдотерминалом).

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

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

На самом деле, администратор ресурсов представляет собой серверную программу пользовательского уровня, которая принимает сообщения от других программ и при необходимости может взаимодействовать с оборудованием. При этом производительность и гибкость служб межзадачного взаимодействия в ОС QNX Neutrino позволяют реализовать администратор ресурсов вне ОС.

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

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

Например, администратор ресурсов devc-ser* может быть назначен для управления последовательным портом, однако в пространстве имен путей физический ресурс может быть назван как /dev/ser1. Запрос служб последовательного порта, как правило, выполняется с помощью его открытия, в данном случае обращения к физическому ресурсу с именем /dev/ser1.
Зачем писать администратор ресурсов?
Написание администратора ресурсов имеет смысл по нескольким причинам.

Например, встраиваемый модуль поддержки протокола TCP/IP содержит программный код, реализующий администратор ресурсов и регистрирующий имя /proc/ipstats. Если открыть это имя и прочитать данные из него, администратор ресурсов возвратит текст с описанием статистики по IP-протоколу.

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

    cat /proc/my_stats

и ресурс менеджер выдаст соответствующую статистику.

Также можно использовать утилиты командной строки для драйвера робота-манипулятора. Драйвер может зарегистрировать следующее имя: /dev/robot/arm/angle, и в результате любая информация, передаваемая на это устройство, будет интерпретироваться как значение угла, на который нужно установить манипулятор. Для того чтобы протестировать этот драйвер из командной строки, можно набрать следующую команду:

    echo 87 >/dev/robot/arm/angle

Утилита echo открывает путь /dev/robot/arm/angle и записывает туда символьную цепочку ("87"). Драйвер обрабатывает запись и устанавливает манипулятор под углом 87 градусов. Следует отметить, что данное тестирование было выполнено без помощи специальной тестирующей программы.

Другой пример: имена типа /dev/robot/registers/r1, r2.... При чтении с этих имен выдается содержание соответствующих регистров. При записи на эти имена устанавливаются заданные значения в соответствующие регистры.

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

Например, драйвер последовательного порта регистрирует такие имена регистров, как /dev/ser1 и /dev/ser2. Когда пользователь применяет команду ls -l /dev, библиотека сама выполняет необходимую обработку для передачи соответствующих ответов на возникающие сообщения _IO_STAT5, поэтому человек, который пишет драйвер последовательного порта, может сосредоточиться на деталях управления оборудованием последовательного порта.
Каталоговые администраторы ресурсов
Администраторы ресурсов каталогового типа регистрируют точку монтирования посредством администратора процессов. Точка монтирования представляет собой часть пути, зарегистрированного администратором процессов. Управление остальными частями пути выполняется администратором ресурсов каталогового типа. Например, если администратор ресурсов каталогового типа присоединяет точку монтирования к /mount, то при проверке пути /mount/home/thomasf:

Ниже приведено несколько примеров использования администраторов ресурсов каталогового типа:
Обмен информацией посредством механизма межзадачного взаимодействия ОС QNX Neutrino
Как только администратор ресурсов установил свой префикс путевого имени, он начинает получать сообщения при каждой попытке клиентской программы сделать по этому путевому имени вызов open(), read(), write() и т. д. Например, после того как администратор ресурсов devc-ser* получит путевое имя /dev/ser1, и клиентская программа выполнит следующую команду:

    fd = open ("/dev/ser1", O_RDONLY);

клиентская Си-библиотека сгенерирует сообщение io_open и затем передаст его администратору ресурсов посредством механизма межзадачного взаимодействия.

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

    read (fd, buf, BUFSIZ);

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

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

Замечание

Все драйверы устройств и файловые системы в ОС QNX Neutrino реализуются как администраторы ресурсов. Это означает, что любой администратор ресурсов, написанный пользователем, может иметь те же функциональные возможности, которые есть у "собственного" драйвера устройств или файловой системы ОС QNX Neutrino.

Например, файловые системы FTP. Здесь администратор ресурсов получает часть пространства путевых имен (например, /ftp) и разрешает пользователям применять команду cd для доступа к FTP-сайтам. Например, при вводе команды cd /ftp/rtfm.mit.edu/pub произойдет соединение с сайтом rtfm.mit.edu и переход в каталог /pub. После перехода в этот каталог пользователь получает возможность открывать, редактировать или копировать файлы.

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

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

Архитектура администратора ресурсов
Схематичная структура администратора ресурсов:

initialize the dispatch interface

register the pathname with the process manager

DO forever

receive a message

SWITCH on the type of message

CASE io open:

perform io open processing

ENDCASE

CASE io read:

perform io read processing

ENDCASE

CASE io write:

perform io write processing

ENDCASE

. // и т.д. - обработка всех других сообщений

. // и выполнение соответствующих операций

ENDSWITCH

ENDDO


Таким образом, архитектура администраторов ресурсов состоит из трех частей:

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

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

    3. Получение и обработка сообщений.

Данная конструкция по обработке сообщений требуется для каждого администратора ресурсов без исключения. В ОС QNX Neutrino поставляется набор удобных библиотечных функций для реализации этой структуры (а также других базовых структур).
Типы сообщений

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

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

Такой подход можно считать довольно разумным, например, потому, что было бы неэффективно передавать полное путевое имя на каждый вызов read(). Обработчик io_open также может выполнять какие-нибудь задачи (например, проверку разрешений) однократно, а не с каждым сообщением ввода/вывода. Кроме того, когда функция read() уже прочитала 4096 байт данных из дискового файла, там могут остаться еще 20 Мбайт непрочитанных данных, поэтому для функции read() нужна некоторая контекстная информация, сообщающая позицию чтения.
Разделяемая библиотека администратора ресурсов
При разработке специализированной встраиваемой системы часть сил может быть потрачена на написание администратора ресурсов, если у вас нет готового драйвера для нужного аппаратного компонента системы.

Разделяемая библиотека администратора ресурсов в ОС QNX Neutrino упрощает эту задачу.
Автоматическая обработка сообщений по умолчанию
Если какие-либо функции не нужны для администратора ресурсов по тем или иным причинам (например, в случае, если аналогово-цифровой преобразователь не поддерживает функцию lseek() или не требует ее), разделяемая библиотека может выполнять действия по умолчанию.

Предусмотрено два уровня действий по умолчанию.
Более подробно о действиях по умолчанию см. в разделе "Второй уровень обработки сообщений по умолчанию" далее в этой главе.
Функции open(), dup() и close()
Другой удобной службой, предоставляемой разделяемой библиотекой администратора ресурсов, является автоматическая обработка сообщений dup().

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

fd = open ("/dev/device", O RDONLY);

...

fd2 = dup (fd);

...

fd3 = dup (fd);

...

close (fd3);

...

close (fd2);

...

close (fd);


Клиент сгенерирует сообщение io_open для первого вызова open() и затем два сообщения io_dup для двух вызовов dup(). После этого, когда клиент выполнит вызовы close(), он сгенерирует три сообщения io_close.

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

Разделяемая библиотека администратора ресурсов предоставляет обработчики по умолчанию, которые регистрируют сообщения open(), dup() и close() и выполняют работу только по последней операции закрытия (т. е. третье сообщение io_close в приведенном примере).
Многопоточная обработка
Одной из отличительных черт ОС QNX Neutrino является возможность применять потоки (threads). Посредством использования множества потоков работу администратора ресурсов можно организовать таким образом, чтобы несколько потоков одновременно ожидали сообщения и затем одновременно обрабатывали их.

Такое управление потоками является еще одной удобной функцией, которую предоставляет разделяемая библиотека администратора ресурсов. Эта библиотека не только следит за количеством созданных и ожидающих потоков, но также и за тем, чтобы это количество было оптимальным.
Функции диспетчеризации
В ОС QNX Neutrino предусмотрен набор функций вида dispatch_*(), которые:
Более подробную информацию можно найти в главе, посвященной написанию администратора ресурсов, в "Руководстве программиста" (Programmer's Guide).
Составные сообщения
Для сохранения пропускной способности сети и поддержки атомарных операций в ОС QNX Neutrino поддерживаются составные сообщения (combine messages). Составное сообщение генерируется Си-библиотекой клиента и состоит из нескольких сообщений ввода/вывода и/или соединения, объединенных в одно.

Например, функция readblock() позволяет потоку автоматически выполнять операции lseek() и read(). В клиентской библиотеке это осуществляется с помощью объединения сообщений io_lseek и io_read. При получении этого составного сообщения разделяемая библиотека администратора ресурсов обработает оба сообщения, входящие в него (io_lseek и io_read), и таким образом работа функции readblock() будет сделана атомарной.

Составные сообщения также полезны для функции stat(). Вызов stat() может быть реализован в клиентской библиотеке посредством функций open(), fstat() и close(). Вместо генерирования трех сообщений для каждой из этих функций, библиотека объединяет их в одно составное сообщение, что повышает производительность (особенно при использовании сети), а также упрощает администратор ресурсов, поскольку в этом случае для него не требуется функция установления соединения для обработки вызова stat().

Разделяемая библиотека администратора ресурсов самостоятельно выполняет разделение составного сообщения на составные компоненты и передачу этих компонентов различным функциям для обработки. Это, опять же, позволяет минимизировать усилия, связанные с написанием администратора ресурсов.
Второй уровень обработки сообщений по умолчанию
Поскольку большое число сообщений, принимаемых администратором ресурсов, касается некоторого общего набора атрибутов, в ОС QNX Neutrino предусмотрен еще один уровень обработки сообщений по умолчанию. Этот второй уровень, называемый разделяемой библиотекой iofunc_*(), позволяет администратору ресурсов автоматически обрабатывать такие функции, как stat(), chmod(), chown(), lseek() и так далее без необходимости писать дополнительный код. Еще одним преимуществом является то, что обработчики iofunc_*() реализуют POSIX-семантику для сообщений, а это опять же уменьшает работу программиста.

Необходимо рассмотреть три основных структуры (рис. 8.1):

Рис. 8.1. Администратор ресурсов управляет тремя структурами данных

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

Администратор ресурсов может управлять более чем одним устройством (например, devc-ser* может отвечать за /dev/ser1, /dev/ser2, /dev/ser3 и т. д.), поэтому атрибутная запись содержит данные по каждому отдельному устройству. В частности, она включает такие элементы, как пользовательский и групповой идентификатор владельца устройства, время последнего изменения и т. д.

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

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

Рис. 8.2. Открытие различных устройств множеством клиентов

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


Рис. 8.3. Инкапсуляция

Библиотека по умолчанию содержит следующие обработчики вызовов iofunc_*():

chmod()

chown()

close()

devctl()

fpathconf()

fseek()

fstat()

lock()

lseek()

mmap()

open()

pathconf()

stat()

utime()

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

Для получения более подробной информации о разработке администраторов ресурсов см. главу «Администраторы ресурсов» учебного пособия Р. Кртена «Введение в QNX Neutrino. Руководство для разработчиков приложений реального времени».


5 Их посылает утилита ls. — Прим. научн. ред.

6
Имеется в виду блок управления открытым контекстом (184ОСВ). — Прим. научн. ред.