Чтобы получить полное сетевое имя пути, используйте утилиту fullpath.

Пространство дескрипторов файлов

При открытии ресурса I/O, open() возвращает целое число, называемое дескриптор файла (FD), которое используется затем, чтобы направлять все последующие запросы I/O к данному менеджеру. (Внутри библиотечных процедур для направления опроса используется вызов ядра Sendfd().)

Пространство дескрипторов файлов, в отличие от пространства имен пути, полностью локально для каждого процесса. Менеджер использует сочетание PID и FD, чтобы определить управляющую структуру, созданную предыдущим вызовом open(). Эта структура называется блок управления файлом (OCB от английского open control block) и хранится внутри менеджера I/O.

Следующая диаграмма показывает, как менеджер I/O находит соответствующий OCB для пары PID и FD.


fig: i/pidfdocb.gif


PID и FD определяют OCB для Менеджера ввода/вывода.


Блоки управления файлами

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

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

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


fig: i/tmpfile.gif


Процесс A открывает файл /tmp/file дважды. Процесс B открывает тот же файл один раз.


Несколько дескрипторов файла в одном или нескольких процессах могут указывать на один и тот же OCB. Это может быть достигнуто двумя способами:

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

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

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


fig: i/dupfd.gif


Процесс открывает файл дважды, а затем получает третий FD посредством dup(). Его дочерний процесс унаследует все эти три дескриптора файла.


Вы можете предотвратить наследование дескриптора файла при использовании spawn() или exec(), предварительно вызвав функцию fcntl() и установив флаг FD_CLOEXEC.

Менеджер файловой системы

Эта глава охватывает следующие темы:

Введение

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

Что такое файл?

В QNX файл - это объект, в который может производиться запись, из которого может производиться чтение, либо и то и другое. QNX поддерживает шесть типов файлов; пять из них поддерживает Fsys:

Все эти типы файлов подробно описываются в этой главе. Шестой тип файлов - блок-ориентированные файлы - обслуживается Менеджером устройств.

Метки даты и времени

Fsys поддерживает четыре различных метки времени для каждого файла. Это:

Доступ к файлам

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

Процесс может выполняться с ID пользователя или ID группы файла, а не родительского процесса. Механизм, который позволяет это, называется setuid (установить ID пользователя) и setgid (установить ID группы).

Регулярные файлы и каталоги

Регулярные файлы

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

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

Каталоги

Каталог - это файл, который содержит элементы каталога. Каждый элемент каталога увязывает имя файла с файлом. Имя файла - это символьное имя, которое позволяет идентифицировать файл и работать с ним. Файл может быть идентифицирован несколькими именами (смотри секции "Связи и индексные дескрипторы (inodes)" и "Символические связи").

Следующая диаграмма показывает, как производится поиск файла с именем /usr/bill/file2.


fig: i/dirpath.gif


Путь в структуре каталога QNX к файлу /usr/bill/file2.


Операции с каталогами

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

Чтение элементов каталога

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

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

Экстенты

В QNX регулярные файлы и файлы каталога хранятся как последовательность экстентов. Экстент - это непрерывная последовательность блоков на диске.

Где хранятся экстенты

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


fig: i/extents.gif


Файл, состоящий из множества непрерывных областей на диске, называемых в QNX экстентами.




Увеличение файлов

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

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

Связи и индексные дескрипторы (inodes)

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

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

Если файл имеет только одну связь (т.е. одно имя), то блок inode хранится в элементе каталога для этого файла. Но если файл имеет более чем одну связь, то inode хранится как запись в специальном файле /.inodes, а элемент каталога для файла содержит указатель на запись inode.

Учтите, что вы можете создать связь для файла, только если файл и связь находятся в одной и той же файловой системе.


fig: i/twolinks.gif


Один и тот же файл обозначен двумя связями с именами "more" и "less".

Существует еще две ситуации, в которых для файла создается запись в файле /.inodes:

Если вы хотите: Используйте:
Создать связь из командного интерпретатора Утилиту ln
Создать связь из программы Функцию link()

Удаление связей

При создании файла, для него устанавливается счетчик связей, равный единице. По мере добавления ссылок этот счетчик увеличивается; при удалении связи счетчик связей уменьшается. Файл не удаляется с диска до того, как счетчик связей станет равным нулю и все программы, использующие этот файл, закроют его. Это позволяет использовать открытый файл даже после того, как у него удалены все связи.
Если вы хотите: Используйте:
Удалить связь из командного интерпретатора Утилиту rm
Удалить связь из программы Функции remove() или unlink()

Связи каталога

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

Имя файла "точка" соответствует текущему каталогу; "точка точка" соответствует каталогу, предшествующему текущему каталогу.

Заметьте, что "точка точка" для каталога "/" - это просто "/", - вы не можете подняться выше.

Символические связи

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

В следующем примере каталоги //1/usr/fred и //2/usr/barney являются связями на один и тот же каталог, хотя они находятся в различных файловых системах, и даже на различных узлах (смотри следующую диаграмму). Это не может быть сделано с использованием жестких связей:

//1/usr/fred --> //2/usr/barney

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

//1/usr/eric/src/test.c --> //1/usr/src/game.c

Figure showing two nodes using symbolic links
Если вы хотите: Используйте утилиту:
Создать символическую связь ln (с опцией -s)
Удалить символическую связь* rm
Узнать, является ли файл символической связью ls

* Помните, что удаление символической связи действует только на связь, а не на адресуемый объект

Некоторые функции оперируют непосредственно с символическими связями. Для этих функций замена обозначения связи в пути на ее содержимое не производится. К этим функциям относятся unlink() (которая удаляет символическую связь), lstat() и readlink().

Так как символические связи могут указывать на каталоги, то неверная конфигурация может привести к проблемам, таким, как циклические связи. Чтобы защититься от циклических связей, система накладывает ограничения на количество переходов; этот предел определен как SYMLOOP_MAX во включаемом файле <limits.h>.

Программные каналы (pipes) и FIFO

Программные каналы (pipes)

Программный канал - это неименованный файл, который служит как канал ввода/вывода между двумя или более взаимодействующими процессами - один процесс пишет в программный канал, другой читает из программного канала. Менеджер файловой системы обеспечивает буферизацию данных. Размер буфера определен как PIPE_BUF в файле <limits.h>. Программный канал удаляется после того как закрыты оба его конца.

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

Типичное применение программного канала состоит в соединении вывода одной программы с вводом другой программы. Это соединение часто производится командным интерпретатором (Shell). Например:

ls | more

направляет стандартный вывод от утилиты ls через программный канал в стандартный ввод утилиты more.
Если вы хотите: Используйте:
Создать программный канал из командного интерпретатора Символ программного канала ("|")
Создать программный канал из программы Функции pipe() или popen()


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

FIFO

FIFO - это по существу то же самое, что и программные каналы, за исключением того, что FIFO являются именованными постоянными файлами, которые хранятся в каталогах файловой системы.
Если вы хотите: Используйте:
Создать FIFO из командного интерпретатора Утилиту mkfifo
Создать FIFO из программы Функцию mkfifo()
Удалить FIFO из командного интерпретатора Утилиту rm
Удалить FIFO из программы Функции remove() или unlink()

Производительность Менеджера файловой системы

Свойства Менеджера файловой системы, обеспечивающие высокопроизводительный доступ к диску:

Лифтовый поиск

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

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

Кэш-буфер

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

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

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

Многопотоковая обработка

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

Клиент-управляемый приоритет

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

Временные файлы

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

Псевдодиски

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

Менеджер файловой системы в состоянии обойти кэширование, так как псевдодиск является встроенным, а не реализован как отдельный драйвер. Для информации об обмене составными сообщениями, смотри раздел "Дополнительные возможности" в главе "Микроядро".

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

Надежность файловой системы

В QNX высокая производительность файловой системы достигается не за счет снижения надежности. Это обеспечивается несколькими способами.

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

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

Восстановление файловой системы

Даже самые надежные системы не застрахованы от аварийных ситуаций, таких как:

Чтобы после таких ситуаций можно было восстановить как можно больше файлов, на диск записываются уникальные "сигнатуры" для автоматической идентификации и восстановления критических частей файловой системы. Файл с индексными дескрипторами (/.inodes), так же как и каждый каталог, и блок экстентов, все содержат уникальные образцы данных, которые могут быть использованы утилитой chkfsys для восстановления серьезно поврежденной файловой системы.

Более подробная информация о восстановлении файловой системы содержится в документации к утилите chkfsys.

Работа с дисками

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

Диски и дисковые подсистемы

QNX считает каждый физический диск на компьютере блок-ориентированным файлом. Как блок-ориентированный файл, диск рассматривается файловой системой QNX как последовательность блоков размером по 512 байт, независимо от размера диска. Блоки нумеруются, начиная с первого блока на диске (блок 1).

Так как каждый диск является блок-ориентированным файлом, он может быть открыт как одно целое для низкоуровневого доступа с использованием стандартных POSIX Си функций, таких как open(), read(), write() и close(). На уровне блок-ориентированного файла, который определяет целый диск, QNX не делает абсолютно никаких предположений о каких-либо структурах данных, которые могут существовать на диске.

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

Разделы ОС

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

Каждый раздел должен иметь "тип", узнаваемый операционной системой, которая должна использовать этот раздел. Следующий список содержит используемые на данный момент типы разделов:
Тип: Операционная система
1 DOS (12-битная FAT)
4 DOS (16-битная FAT; разделы <32Mбайт)
5 Расширенный раздел DOS
6 DOS 4.0 (16-битная FAT; раздел >=32Mбайт)
7 OS/2 HPFS
7 Предыдущая версия QNX 2 (до 1988)
8 QNX 1.x и 2.x ("qny")
9 QNX 1.x и 2.x ("qnz")
11 DOS 32-битная FAT; разделы до 2047Gбайт
12 То же, что тип 11, но использует LBA расширения прерывания Int 13h
14 То же, что тип 6, но использует LBA расширения прерывания Int 13h
15 То же, что тип 5, но использует LBA расширения прерывания Int 13h
77 QNX POSIX раздел
78 QNX POSIX раздел (вторичный)
79 QNX POSIX раздел (вторичный)
99 UNIX

Если вы хотите иметь несколько разделов QNX 4.x на одном физическом диске, вам следует использовать тип 77 для первого QNX раздела, тип 78 для второго QNX раздела, и тип 79 для третьего. Вы можете использовать другие типы для второго и третьего QNX разделов, но 78 и 79 предпочтительнее. Чтобы пометить любой из этих разделов как загрузочный, используйте утилиту fdisk.

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

Вы можете использовать утилиту fdisk для создания, модификации или удаления разделов.

Так как QNX рассматривает каждый раздел на диске как блок-ориентированный файл, то это дает возможность доступа к следующему:


fig: i/twodisks.gif


Два физических диска. Первый содержит DOS, QNX и UNIX разделы. Второй диск имеет DOS и QNX разделы.



Определение блок-ориентированный файлов

Имена всех блок-ориентированных файлов помещаются в дерево префиксов того компьютера, на котором расположены блок-ориентированные файлы (дерево префиксов рассматривается в главе "Пространство имен ввода/вывода"). Когда запускается драйвер контроллера дисков, Менеджер файловой системы автоматически регистрирует префиксы, которые определяют блок-ориентированный файл для каждого физического диска, подключенного к контроллеру. Утилита mount используется для того, чтобы зарегистрировать префикс для блок-ориентированного файла для каждого раздела на диске.

Пусть, например, у вас имеется стандартный контроллер Western Digital, к которому подключены два диска. На одном диске вы хотите смонтировать раздел DOS, раздел QNX и раздел UNIX. На другом диске вы хотите смонтировать раздел DOS и раздел QNX.

Менеджер файловой системы определит блок-ориентированные файлы /dev/hd0 и /dev/hd1 для двух дисков, подключенных к контроллеру.

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

mount -p /dev/hd0 -p /dev/hd1

определит следующие блок-ориентированные файлы:
Раздел ОС: Блок-ориентированный файл:
Раздел DOS на диске hd0 /dev/hd0t4
Раздел QNX на диске hd0 /dev/hd0t77
Раздел UNIX на диске hd0 /dev/hd0t99
Раздел DOS на диске hd1 /dev/hd1t4
Раздел QNX на диске hd1 /dev/hd1t77

Заметьте, что обозначение tn используется для обозначения разделов на диске, используемых определенными операционными системами. Например, раздел DOS обозначается t4, раздел UNIX - это t99 и т.д.

Монтирование файловой системы

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

mount /dev/hd0t77 /

монтирует файловую систему с префиксом / на разделе, который определен блок-ориентированным файлом с именем hd0t77.


Note: Если диск разбит на разделы, то вы должны смонтировать блок-ориентированный файл для раздела QNX 4.x (например /dev/hd0t77), а не основной блок-ориентированный файл, который определяет весь диск (например, /dev/hd0). Если вы попытаетесь смонтировать основной блок-ориентированный файл для всего диска, то при попытке доступа к файловой системе получите сообщение "corrupt filesystem" (поврежденная файловая система).

Демонтирование файловой системы

Чтобы демонтировать файловую систему, используйте утилиту umount. Так, например, следующая команда демонтирует файловую систему на первичном разделе QNX:

umount /dev/hd0t77

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

Ключевые компоненты QNX раздела

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

Эти структуры создаются при инициализации файловой системы утилитой dinit.


fig: i/qnxpart.gif


Структура файловой системы QNX внутри раздела диска.


Блок загрузчика

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

Корневой блок

Корневой блок имеет ту же структуру, что и обычный каталог. Он содержит информацию о четырех особых файлах:

Файлы /.boot и /.altboot содержат образы операционной системы, которые загружаются программой начальной загрузки QNX.

Обычно загрузчик QNX загружает образ ОС, хранящийся в файле /.boot. Но если файл /.altboot не пуст, то вам будет предложена опция загрузки образа, хранящегося в файле /.altboot.

Битовая карта

Чтобы распределять пространство на диске, QNX использует битовую карту, хранящуюся в файле /.bitmap. Этот файл содержит битовую маску для всех блоков на диске, показывающую, какие блоки заняты. Каждому блоку соответствует один бит. Если значение бита 1, то соответствующий блок на диске занят.

Корневой каталог

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

Менеджер файловой системы DOS

В QNX пространство имен ввода/вывода управляется через префиксы, которые направляют запросы соответствующим процессам-менеджерам. Одним из таких процессов является Менеджер файловой системы DOS (Dosfsys). Dosfsys регистрирует префикс /dos и представляет диски DOS внутри пространства имен QNX как "гостевые" файловые системы.

Dosfsys обеспечивает прозрачный доступ к дискам DOS, так что вы можете рассматривать файловые системы DOS как файловые системы QNX. Такая прозрачность позволяет процессам работать с файлами DOS без каких-либо специальных знаний или действий. Стандартные библиотечные функции ввода/вывода, такие как open(), close(), read() и write() работают с файлом в разделе DOS точно так же, как и с файлом в разделе QNX. Например, чтобы копировать файл из раздела QNX в раздел DOS, достаточно выполнить команду:

cp /usr/luc/file.dat /dos/c/file.dat

Заметьте, что /dos/c - это путь к DOS диску C. Команда cp не содержит какого-либо специального кода для определения, находится ли копируемый файл на диске DOS. Другие команды работают с такой же прозрачностью (например, утилиты cd, ls и mkdir).

Если не существует эквивалента DOS для функции QNX, такой как mkfifo() или link(), то Dosfsys возвращает соответствующий код ошибки (т.е. errno).

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

Файловая система CD-ROM

Файловая система CD-ROM, Iso9660fsys, обеспечивает прозрачный доступ к носителям CD-ROM, таким образом можно работать с файловыми системами CD-ROM, как будто это файловые системы POSIX. Такая прозрачность обеспечивает процессам доступ к файлам на CD-ROM стандартными средствами.

Менеджер Iso9660fsys реализует стандарт ISO 9660, включая расширения Rock Ridge. Этому стандарту соответствуют компакт-диски DOS и Windows. В дополнение к обычным файлам, Iso9660fsys также поддерживает аудио.

Файловая система флэш

Менеджер файловой системы флэш Efsys.* был специально разработан для работы, как со встроенной, так и со сменной флэш-памятью. Файлы, записанные на сменные носители флэш (карты PC-Card), переносимы в другие системы, которые также поддерживают этот стандарт.

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

Ограничения

Функциональность файловой системы ограничена используемыми устройствами памяти. Например, для устройств ROM файловая система доступна только для чтения.

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

Восстановление свободного пространства

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

Со временем свободное место закончится, и менеджеру файловой системы придется выполнить восстановление свободного пространства (иногда эту операцию называют еще "уборка мусора"). Во время этой процедуры Efsys.* восстанавливает свободное место, занимаемое удаленными файлами и каталогами. Для проведения этой операции менеджеру файловой системы требуется хотя бы один свободный блок. Утилита mkffs автоматически резервирует для этой цели один блок при создании файловой системы.

Сжатие и распаковка

Менеджер Efsys.* поддерживает распаковку, что увеличивает объем данных, который может храниться на носителе. Распаковка выполняется менеджером файловой системы для приложений прозрачно.

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

Доступ к файлам

Если запретить расширения POSIX, то владельцем файлов всегда будет считаться root, а биты режима всегда будут установлены в rwx. Команды chgrp, chmod и chown в этом случае не будут работать.

Монтирование

Может производиться только при инициализации разделов или при запуске менеджера файловой системы.

Доступ на низком уровне

При запуске Efsys.*, он создает для каждого устройства памяти специальный файл в каталоге /dev. В системе с двумя устройствами памяти Efsys.* создаст файлы /dev/skt1 и /dev/skt2. Специальные устройства игнорируют разбиение на разделы, позволяя доступ к носителям на низком уровне.

Доступ к разделу, содержащему образ файловой системы, возможен только на низком уровне (как к "сырому" устройству). Для каждого такого раздела Efsys.* создает специальный файл вида /dev/sktXimgY, где X - это номер гнезда (socket), а Y - номер раздела на этом носителе.

Файловая система NFS

Первоначально разработанная компанией Sun Microsystems, NFS (Network File System - Сетевая Файловая Система) является TCP/IP приложением, которое с тех пор было реализовано на большинстве DOS и UNIX систем. Его реализация в QNX не заменима для прозрачного доступа к файловым системам других ОС, поддерживающих NFS.


Note: QNX изначально поддерживает сетевые файловые системы. Использовать NFS необходимо только для доступа к не-QNX NFS файловым системам, либо если вы хотите открыть NFS-клиентам доступ к файлам QNX.

NFS позволяет отображать удаленные файловые системы - полностью или частично - в локальное пространство имен. Каталоги на удаленной системе выглядят как часть локальной файловой системы, и все утилиты работы с файлами (ls, cp и mv) работают с удаленными файлами так же, как и с локальными.


Note: В QNX 4 для NFS требуется менеджер Socket, который поддерживает сетевые протоколы TCP/IP. Заметьте, что его "облегченный" вариант, Socklet, может использоваться, если не нужна NFS.

Файловая система SMB

SMBfsys реализует протокол SMB (Server Message Block) совместного использования файлов, который используется различными серверами, такими как Windows NT, Windows 95, Windows for Workgroups, LAN Manager, Samba. SMBfsys обеспечивает QNX-клиенту прозрачный доступ к удаленным дискам таких серверов.

SMBfsys реализует этот протокол, используя только NetBIOS поверх TCP/IP, не NetBEUI. Соответственно, необходимо, чтобы TCP/IP был установлен, как на QNX-машине, так и на удаленном сервере. После того, как запущен SMBfsys и смонтирован удаленный сервер, файловая система сервера появляется в локальном дереве каталог.

Менеджер устройств

Эта глава охватывает следующие темы:

Введение

Менеджер устройств QNX (Dev) является интерфейсом между процессами и терминальными устройствами. Эти терминальные устройства располагаются в пространстве имен ввода/вывода с именами, начинающимися с /dev. Например, консольное устройство в QNX будет иметь имя:

/dev/con1

Обслуживание устройств

Программы в QNX получают доступ к терминальным устройствам, используя стандартные функции open(), close(), read() и write(). Для процесса QNX терминальное (оконечное) устройство представляется двунаправленным потоком байт, который может считываться и записываться процессом.

Менеджер устройств регулирует поток данных между приложением и устройством. Dev выполняет некоторую обработку этих данных в соответствии с параметрами управляющей структуры терминала (называемой termios), которая существует для каждого устройства. Пользователи могут запрашивать и/или изменять эти параметры с помощью утилиты stty; программы могут использовать функции tcgetattr() и tcsetattr().

Параметры структуры termios управляют функциональностью низкого уровня, такой как:

Менеджер устройств также предоставляет набор дополнительных услуг, доступных процессам для работы с терминальным устройством. В следующей таблице приведены некоторые из этих услуг.
Процесс может: Функция Си:
Выполнять операции чтения с контролем времени dev_read() или read() и tcsetattr()
Получать асинхронное извещение о доступных данных dev_arm()
На одном или более устройствах ввода ждать полного завершения операции вывода tcdrain()
Посылать команду Break по каналу связи tcsendbreak()
Разорвать соединение tcdropline()
Вставить входные данные dev_insert_chars()
Выполнять неблокирующиеся чтение и запись open() и fcntl() (O_NONBLOCK mode)

Режим редактируемого ввода

Наиболее важный режим работы устройства управляется битом ICANON в управляющей структуре termios. Если этот управляющий бит установлен, то Менеджер устройств выполняет функции редактирования строки для принимаемых символов. Таким образом, только когда строка "введена" - обычно, когда получен символ перевода каретки (CR), - данные станут доступны для прикладных процессов. Такой режим работы называется редактируемым - от английского edited. Этот режим еще называют canonical (каноническим) и иногда cooked (приготовительным).

Большинство неполноэкранных приложений выполняются в редактируемом режиме. Типичным примером является командный интерпретатор (Shell).

Следующая таблица показывает, как Dev обрабатывает некоторые специальные управляющие символы, если соответствующие параметры установлены в структуре termios.
Dev выполнит: Когда получит символ:
Сдвиг курсора на один символ влево LEFT
Сдвиг курсора на один символ вправо RIGHT
Сдвиг курсора в начало строки HOME
Сдвиг курсора в конец строки END
Удаление символа слева от курсора ERASE
Удаление символа в текущей позиции курсора DEL
Удаление всей строки ввода KILL
Стирание текущей строки и восстановление предыдущей UP
Стирание текущей строки и восстановление следующей DOWN
Переключение между режимами вставки и заменыINS

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

Если терминал подключен к QNX через последовательный канал, необходимо установить редактирующие символы, которые будут использоваться для данного конкретного терминала. Для этого вы можете использовать утилиту stty. Например, если терминал VT100 подключен к последовательному порту (/dev/ser1), то следующая команда извлечет соответствующие редактирующие символы из базы данных terminfo и применит их к /dev/ser1:

stty term=vt100 </dev/ser1

Если же к этому последовательному порту подключен модем, для связи с другой QNX системой с помощью утилиты qtalk, редактирующие символы следует установить так:

stty term=qnx </dev/ser1

Режим необрабатываемого ввода

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

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

При чтении из сырого устройства приложение может задать условия, при которых будет удовлетворен запрос на ввод данных. Критерии, используемые при приеме сырых данных, базируются на двух параметрах структуры termios: MIN и TIME. Приложение может определить еще один дополнительный параметр при вызове функции dev_read(). Этот параметр, TIMEOUT, используется при написании протоколов или приложений реального времени. Учтите, что для функции read() TIMEOUT всегда 0.

Когда процесс запрашивает ввод n байт данных, эти три параметра определяют, когда должен быть удовлетворен запрос:
MINTIMETIMEOUT Описание:
000 Вернуть немедленно столько байт, сколько доступно в данный момент (но не более n байт)
M00 Вернуть не более n байт только тогда, когда доступны, по меньшей мере, M байт
0T0 Вернуть не более n байт только тогда, когда доступен хотя бы один байт либо истекло T x .1 секунд.
MT0 Вернуть не более n байт только тогда, либо когда будут доступны M байт, либо будет принят хотя бы один байт и интервал между любыми последовательно принятыми символами превысил T x .1 секунд.
00t Зарезервировано.
M0 tВернуть не более n байт только тогда, когда доступны M байт либо истекло t x .1 секунд.
0Tt Зарезервировано.
MTt Вернуть не более n байт только тогда, когда доступны M байт, либо истекло t x .1 секунд и не был получен ни один символ, либо был принят хотя бы один байт и интервал между любыми последовательно принятыми символами превысил T x .1 секунд.

Драйверы устройств

На рисунке показана типичная подсистема устройств в QNX.

Figure showing a typical QNX device subsystem

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


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

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

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

Dev помещает выводимые данные в очередь вывода; данные извлекаются драйвером по мере того, как символы физически передаются устройству. Dev вызывает проверенную процедуру внутри драйвера каждый раз, когда добавляются новые данные, таким образом он "подталкивает" драйвер к работе (в случае, если он не был занят). Благодаря использованию очередей вывода Dev реализует буферизованную запись (write-behind) для всех терминальных устройств. Только когда буферы вывода заполнены, Dev вызывает блокирование процесса при записи.

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

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

Управление устройствами

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

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

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

Управление устройствами на низком уровне выполняется через дальний вызов входной точки ioctl внутри каждого драйвера. Общий набор ioctl команд поддерживается непосредственно Dev. Специфические для устройства ioctl команды могут быть посланы QNX процессами драйверу через функцию Си qnx_ioctl().

Консоль QNX

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

QNX позволяет параллельное выполнение множества сессий на консолях посредством виртуальных консолей. Драйвер Dev.con обычно поддерживает более одного набора очередей ввода/вывода к Dev, которые доступны пользовательским процессам как множество терминальных устройств с именами вида /dev/con1, /dev/con2 и т.д. С точки зрения приложения, это "настоящие" доступные консоли.

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

Функции, специфичные для консоли

В дополнение к реализации стандартного терминала QNX (описан в Руководстве пользователя), драйвер консоли также обеспечивает набор специфических для консоли функций, которые позволяют приложениям непосредственно взаимодействовать с драйвером консоли путем обмена сообщениями. Связь устанавливается вызовом функции Си console_open(). После того как связь установлена, процесс имеет доступ к следующим возможностям:
Процесс может:Через функцию Си:
Читать непосредственно с экрана консоли console_read()
Писать непосредственно на экран консоли console_write()
Получать асинхронное извещение о важных событиях (например, изменение положения курсора, размера дисплея, переключение консоли и т.д.) console_arm()
Управлять размерами консоли console_size()
Переключать видимую консоль console_active()

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

Последовательные устройства

Последовательные каналы связи обслуживаются драйвером Dev.ser. Этот драйвер может обслуживать более одного физического канала; он обеспечивает терминальные устройства с именами вида /dev/ser1, /dev/ser2 и т.д.

При запуске Dev.ser вы можете задать аргументы командной строки, которые определяют, какие - и сколько - последовательные порты установлены. Чтобы увидеть доступные последовательные порты, используйте утилиту ls:

ls /dev/ser*

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

Параллельные устройства

Параллельные порты принтера обслуживаются драйвером Dev.par. При запуске Dev.par вы можете задать аргумент командной строки, который определяет, какой последовательный порт установлен. Чтобы увидеть, доступен ли последовательный порт, используйте утилиту ls:

ls /dev/par*

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

Dev.par является примером сервера ввода/вывода, не использующим прерывания. Этот процесс нормально находится в состоянии RECEIVE-блокирован, ожидая появления данных в очереди вывода и "толчка" от Dev. Когда доступны данные для вывода на печать, Dev.par выполняется в цикле работа-ожидание (с относительно низким адаптивным приоритетом), ожидая, когда символы будут приняты принтером. Такой низкоприоритетный цикл работа-ожидание не влияет на общую производительность системы и, в то же время, достигает максимально возможную пропускную способность к параллельному устройству.

Производительность подсистемы устройств

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

Эти правила - в сочетании с исключительно маленькими задержками прерывания и диспетчеризации в QNX - обеспечивают очень эффективную модель ввода.

Менеджер сети

Эта глава охватывает следующие темы:

Введение

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

Обязанности Менеджера сети

Менеджер сети отвечает за распространение примитивов передачи сообщений QNX в пределах локальной сети. Стандартные примитивы передачи сообщений используются без изменения для связи с удаленным компьютером. Другими словами, не существует особых "сетевых" Send(), Receive() или Reply().

Независимый модуль

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

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

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

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

Интерфейс Микроядро/Менеджер сети

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

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

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

Посылка сообщения на удаленный узел


fig: i/sendrmot.gif


Процесс вызывает Send() или Reply() к удаленному узлу.


В случае вызова Send() или Reply() к удаленному узлу, имеют место следующие события:

  1. Процесс вызывает Send() или Reply(), и Микроядро копирует данные из области данных процесса в буфер виртуального канала.
  2. Микроядро добавляет в очередь Менеджера сети элемент, содержащий идентификаторы отправителя, удаленного получателя и указатель на данные в буфере виртуального канала. Если перед этим очередь была пуста, то Менеджер сети получает прокси, извещающее о том, что появилась новая работа.
  3. Менеджер сети извлекает элемент из очереди.
  4. Менеджер сети посылает элемент соответствующему сетевому драйверу.
  5. Менеджер сети начинает передачу данных по сети и отвечает за доставку.

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

Получение сообщения с удаленного узла


fig: i/recvrmot.gif


Процесс получает удаленный Send() или Reply().


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

  1. Сетевой драйвер помещает поступившие по сети данные в соответствующий буфер виртуального канала.
  2. Сетевой драйвер информирует Менеджер сети о том, что прием завершен.
  3. Менеджер сети использует частный вызов Ядра, извещая его о том, что прием завершен.
  4. Микроядро копирует данные из буфера виртуального канала в буфер процесса (при условии, что он RECEIVE- или REPLY-блокирован на этом виртуальном канале).

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

Сетевые драйверы

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

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

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

Идентификаторы узла и сети

Каждый узел в локальной сети идентифицируется двумя числами:

Физический ID узла

Физический ID узла определяется оборудованием. Сетевые платы обмениваются данными друг с другом, указывая физический ID удаленного узла, с которым должна быть установлена связь. В случае сети Ethernet или Token Ring - это большое число, которым неудобно оперировать людям и утилитам. Например, каждая плата Ethernet или Token Ring имеет уникальный 48-битный физический ID узла в соответствии со стандартом IEEE 802. Платы Arcnet, напротив, имеют всего лишь 8-битный ID.

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

Логический ID узла

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

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

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

Логические ID узлов обычно присваиваются по порядку, начиная с 1. Например, узел, имеющий плату Ethernet, может получить логический ID 2, который будет соответствовать физическому ID узла 00:00:c0:46:93:30.

Логические ID узлов должны быть уникальны для всех узлов во всех соединенных QNX-сетях, чтобы сделать возможным функционирование мостов.

Логический ID сети

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

На следующей диаграмме узел 7 имеет две сетевые платы, которые позволяют ему иметь доступ к узлам в логических сетях 1 и 2. Узлы 8 и 9 имеют по три платы, подключающие их к сетям 1, 2 и 3.

Заметьте, что все логические ID узлов уникальны для всех трех логических узлов.


Note: Логические ID узлов сети назначаются системным администратором. Более подробно см. в главе "Установка сети" в книге Руководстве пользователя.


fig: i/multinet.gif


Несколько физических сетей сосуществуют посредством логических сетей.


Выбор сети

В случае, когда узлы соединены более чем одной логической сетью, Менеджер сети может выбирать, какую из сетей использовать для передачи к удаленному узлу. Например, на приведенном выше рисунке узел 7 может передавать данному узлу 8, используя либо сеть 1, либо сеть 2.

Распределение нагрузки

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

Например, два компьютера Pentium, соединенные сетью 10BASE-T Ethernet, будут ограничены 1.1 миллионом байт в секунду, то есть скоростью передачи данных, обеспечиваемой сетевым оборудованием. Однако если поместить по две платы Ethernet в каждый из компьютеров и соединить их отдельными кабелями, то Менеджер сети сможет передавать данные по обеим сетям одновременно. При большой нагрузке это обеспечит увеличение пропускной способности в два раза по сравнению с одной сетью.

Менеджер сети будет пытаться сбалансировать нагрузку, выбирая сетевой драйвер. В рассмотренном выше примере, если производится передача с узла 7 на узел 8 по сети 1 и другая передача на узел 8 инициируется на узле 7, то сеть 2 будет автоматически выбрана для передачи данных.

Отказоустойчивость

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

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

Мосты между сетями QNX

Менеджер сети позволяет любому узлу играть роль моста между двумя отдельными сетями QNX, базирующимися на стандарте IEEE 802.


Note: Так как QNX использует одинаковый формат пакетов и протокол на всех IEEE 802 сетях, можно создавать мосты между сетями Ethernet, Token Ring и FDDI.

Для сетей Arcnet нельзя создавать мосты.


Рассмотрим следующую диаграмму, где одной сети принадлежат узлы 17 и 18, а другой - узлы 18 и 19:


fig: i/relay.gif


Мост между двумя IEEE 802 QNX сетями.


Узлы 17 и 18 находятся в одной сети, поэтому они могут общаться друг с другом напрямую. То же справедливо для узлов 18 и 19. Но как могут общаться узлы 17 и 19?

Так как обе локальные сети базируются на IEEE 802, узел 18 автоматически перенаправляет пакеты, позволяя узлам 17 и 18 создать виртуальный канал. Хотя они и не подключены к одной и той же локальной сети, узлы 17 и 19, тем не менее, могут общаться друг с другом.

Сеть TCP/IP

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

По мере того как Интернет стал занимать все большее место в нашей повсеместной жизни, протокол, на котором он основан - IP (Internet Protocol) - приобретает все большее значение. Даже если вы не подключаетесь непосредственно к Интернет как к таковому, IP протокол и связанный с ним инструментарий поистине вездесущи, делая IP стандартом "де-факто" для многих частных сетей.

IP используется везде, начиная от простых задач (например, удаленный вход в систему (login)) и до более сложных (например, отслеживание биржевых котировок в реальном времени). Все больше и больше компаний используют World Wide Web ("всемирную паутину"), основанную на IP, для переписки с клиентами, рекламы и другой деловой активности.

Менеджер TCP/IP

Менеджер TCP/IP в QNX происходит из Berkley BSD 4.3, который является наиболее распространенным стеком TCP/IP в Интернет и использован как основа для многих систем.

Сокет API

Библиотека BSD сокета API была очевидным выбором для QNX 4. Сокет API является стандартным API для программирования TCP/IP в среде Unix. В среде Windows, Winsock API базируется на BSD сокете API. Это облегчает переход между ними.

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

accept()
bind()
bindresvport()
connect()
dn_comp()
dn_expand()
endprotoent()
endservent()
gethostbyaddr()
gethostbyname()
getpeername()
getprotobyname()
getprotobynumber()
getprotoent()
getservbyname()
getservent()
getsockname()
getsockopt()
herror()
hstrerror()
htonl()
htons()
h_errlist()
h_errno()
h_nerr()
inet_addr()
inet_aton()
inet_lnaof()
inet_makeaddr()
inet_netof()
inet_network()
inet_ntoa()
ioctl()
listen()
ntohl()
ntohs()
recv()
recvfrom()
res_init()
res_mkquery()
res_query()
res_querydomain()
res_search()
res_send()
select()
send()
sendto()
setprotoent()
setservent()
setsockopt()
shutdown()
socket()

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

Возможность взаимодействия сетей

При разработке Менеджера TCP/IP в QNX в первую очередь принималась во внимание возможность взаимодействия сетей. Учитывались как требования RFC, так и реальные условия. Менеджер TCP/IP охватывает всю функциональность, предлагаемую RFC 1122. Также поддерживаются протоколы ARP, IP, ICMP, UDP и TCP.

NFS

Network File System (NFS) является приложением TCP/IP, реализованным на большинстве DOS и Unix систем. NFS позволяет отображать удаленные файловые системы - или их части - в локальное пространстве имен. Файлы на удаленной системе показываются как часть локальной файловой системы QNX.


Note: В QNX 4 для поддержки NFS требуется менеджер Socket. Учтите, что "облегченная" версия менеджера, Socklet, может быть использована, если нет необходимости в NFS.

SMB

Server Message Block (SMB), который используется многими различными серверами, такими как Windows NT, Windows 95, Windows for Workgroups, LAN Manager и Samba. SMBfsys позволяет клиенту QNX прозрачный доступ к удаленным дискам на таких серверах.

Оконная система Photon microGUI

Эта глава охватывает следующие темы:

Графическое микроядро

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

При создании оконной системы Photon microGUI была применена архитектура микроядра, успешно воплощенная в QNX для создания POSIX ОС для встроенных систем.

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

Хотя на первый взгляд это может показаться похожим на построение графической системы по классической схеме клиент/сервер, используемой в X Window System, архитектура Photon отличается за счет ограничения функциональности, реализуемой внутри самого графического микроядра (или сервера), и распределения большей части функций GUI между взаимодействующими процессами.

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

Для управления средой GUI, Photon создает 3-мерное "пространство событий" и ограничивается только оперированием регионами и выполнением отсечения и направления различных событий по мере их прохождения сквозь регионы в этом пространстве событий.

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

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

Пространство событий Photon

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

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


fig: i/regions.gif


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


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

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

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

Регионы

Каждому региону соответствует прямоугольная область, определяющая его положение в 3-мерном пространстве событий. Регион также имеет атрибуты, определяющие, как он взаимодействует с различными классами событий при пересечении ими региона. Взаимодействие региона с событиями определяется двумя битовыми масками:

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

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

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

События

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

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

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

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

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

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

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

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


fig: i/clipping.gif


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


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

Графические драйверы

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

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

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

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

Несколько графических драйверов

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

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

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

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

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

Цветовая модель

Для представления цветов используется 24-битная RGB модель (по 8 бит для красного, зеленого и синего), что обеспечивает 16,777,216 цветов. В зависимости от используемого типа оборудования, драйвер либо непосредственно отображает 24-битный цвет, либо использует различные варианты смешивания цветов, чтобы отобразить требуемый цвет на оборудовании, поддерживающем меньшее число цветов.

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

Масштабируемые шрифты

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

Масштабируемые шрифты в Photon поддерживаются быстродействующим сервером шрифтов, который загружает описания шрифтов, хранящиеся в сжатом виде в файлах *.pfr (Portable Font Resource, ресурсы переносимых шрифтов), и затем приводит вид символов в соответствие с любым размером точки и разрешением. Стоит отметить, что формат PFR обеспечивает более чем в два раза лучшее сжатие по сравнению с PostScript шрифтами.

Наборы шрифтов

Основной латинский набор

Основной латинский (Core Latin) набор шрифтов Photon (latin1.pfr), который охватывает два набора символов стандарта Unicode, Basic Latin (U+0000 - U+007F) и Latin-1 Supplement (U+0080 - U+00FF), включает следующие масштабируемые шрифты:

Расширенный латинский набор

Расширенный латинский (Extended Latin) набор (latinx.pfr) охватывает наборы символов Unicode Latin Extended-A (U+0100 - U+017F) и Latin Extended-B (U+0180 - U+0217) и включает следующие шрифты:

Поддерживаемые языки

Имея в своем распоряжении Основной латинский набор (latin1.pfr), разработчик может поддерживать множество языков, включая:

Датский;
Голландский;
Английский;
Финский;
Фламандский;
Французский;
Немецкий;
Гавайский;
Исландский;
Индонезийский;
Ирландский;
Итальянский;
Норвежский;
Португальский;
Испанский;
Суахили;
Шведский.

Расширенный набор (latinx.pfr) позволяет дополнительно поддерживать:

Африканский;
Баскский;
Каталонский;
Хорватский;
Чешский;
Эсперанто;
Эстонский;
Гренландский;
Венгерский;
Латышский;
Литовский;
Мальтийский;
Польский;
Румынский;
Словацкий;
Турецкий;
Валлийский.

Дополнительные языковые пакеты

Для Photon предлагаются несколько дополнительных пакетов для поддержки национальных языков:

Многоязычная поддержка Unicode

Photon разработан с учетом поддержки национальных символов. Следуя стандарту Unicode (ISO/IEC 10646), Photon предоставляет разработчикам возможность создавать приложения, поддерживающие основные мировые языки.

Unicode основывается на наборе символов ASCII, но использует 16-битную кодировку для полной поддержки многоязычного текста. Нет никакой необходимости прибегать к escape-последовательностям или управляющим кодам для задания любого символа любого языка. Заметьте, что кодировка Unicode обрабатывает все символы - алфавитные, идеограммы, специальные символы - абсолютно одинаковым образом.

UTF-8 кодировка

Известная раньше как UTF-2, UTF-8 (от "8-битная форма") кодировка определяет использование символов Unicode в 8-битной среде UNIX.

Вот некоторые основные характеристики UTF-8:

Системная библиотека включает ряд функций преобразования:
Функция:Описание:
mblen()Длина многобайтной строки в символах
mbtowc()Преобразовать многобайтный символ в двухбайтный символ
mbstowcs()Преобразовать многобайтную строку в двухбайтную строку
wctomb()Преобразовать двухбайтный символ в его многобайтное представление
wcstombs()Преобразовать строку двухбайтных символов в многобайтную строку

В дополнение к перечисленным выше функциям, разработчики могут также воспользоваться собственной библиотекой Photon, функциями PxTranslate, которые выполнят различные преобразования наборов символов в/из UTF-8.

Поддержка анимации

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

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

Поддержка печати

Photon предусматрив