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

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



Таймеры



Исчисление времени

В QNX исчисление времени основывается на системном таймере,
поддерживаемом операционной системой. Таймер содержит текущее значение
Координированного Всемирного Времени (UTC) относительно 0 часов, 0
минут, 0 секунд, 1 января 1970 года. Чтобы определить местное время,
функции исчисления времени используют переменную окружения TZ
(которая описывается в книге Руководство пользователя).


Простые средства отсчета времени

Командные файлы и процессы могут делать паузу на определенное
количество секунд, используя простые средства отсчета времени. В
командных файлах для этой цели используется утилита sleep; в
процессах используется функция Си sleep(). Также может
использоваться функция delay(), которой в качестве аргумента
передается длина интервала времени в миллисекундах.


Более сложное средство отсчета времени

Кроме того, процесс может создавать таймеры, устанавливать их на
определенный интервал времени и удалять таймер. Эти средства отсчета
времени основываются на спецификации POSIX Std 1003.4/Draft 9.


Создание таймеров


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


Установка таймеров


При установке таймеров вы можете использовать один из двух типов
интервалов времени:

  • абсолютный - время относительно 0 часов, 0 минут,
    0 секунд, 1 января 1970 года;
  • относительный - время относительно текущего показания часов.

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

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

  • для абсолютного таймера новый интервал заменяет текущий
    интервал времени;
  • для относительного таймера новый интервал добавляется к
    любому остающемуся интервалу времени.


Чтобы установить таймер:
Используйте функцию:
Абсолютный или относительный интервал
timer_settime()


Удаление таймеров


Чтобы удалить таймер, используйте функцию Си timer_delete().


Установка разрешения таймера


Вы можете установить разрешение для таймера с помощью утилиты
ticksize или функции qnx_timerperiod(). Вы можете
настраивать разрешение от 500 микросекунд до 50 миллисекунд.


Чтение таймера


Чтобы узнать оставшийся от таймера интервал или проверить, не был
ли таймер удален, используйте функцию Си timer_gettime().



Обработчики прерываний


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

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

Обработчик прерываний:

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


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




Если вы хотите:
Используйте функцию:
Установить обработчик прерывания
qnx_hint_attach()
Удалить обработчик прерывания
qnx_hint_detach()


Обработчики прерывания таймера

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

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




<!-- 3 -->

<!-- 4 -->


Пространство имен ввода/вывода



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




Введение



Пространство имен ввода/вывода

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


Префиксы и области полномочий

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



Разборка имен путей



Префиксы менеджера ввода/вывода

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

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




/дисковая файловая система (Fsys)
/devсистема символьных устройств (Dev)
/dev/hd0дисковый том без разделов (Fsys)


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










Имя пути: Совпадает:Относится к:
/dev/con1 /dev Dev
/dev/hd0
/dev/hd0
Fsys
/usr/dtdodge/test /Fsys

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



prefix=pid,unit:prefix=pid,unit:prefix=pid,unit


где pid - это ID процесса менеджера ресурсов I/O, а unit -
это один символ, используемый менеджером для нумерации префиксов, которыми
он владеет. В приведенном выше примере, если Fsys был бы
процессом 3 и Dev был бы процессом 5, то дерево префиксов
выглядело бы как:



/dev/hd0=3,a:/dev=5,a:/=3,e






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


Сетевой корень

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






/dev/ser1 локальный последовательный порт
//10/dev/ser1 последовательный порт в узле 10
//0/dev/ser1 локальный последовательный порт
//20/usr/dtdodge/test файл на узле 20

Заметьте, что //0 всегда указывает на локальный узел


Сетевой корень по умолчанию

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



//5 ls /


которая запускает утилиту ls на узле 5, возвратит то же
самое, что и:



ls /


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

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

/usr/home/luc

будет разбираться, как:

//9/usr/home/luc

что может быть интерпретировано, как "разобрать путь
/usr/home/luc, используя дерево префиксов 9-го узла".

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



ls /


команда унаследует сетевой корень по умолчанию //9, и
в результате вы получите:



ls //9/


Подобно тому, если бы вы ввели команду:


//5 ls /


Вы запустили команду ls на узле 5, но она по-прежнему унаследует
сетевой корень по умолчанию //9, поэтому в результате вы опять
получите ls //9/. В обоих случаях имя пути разбирается относительно
одного и того же пространства имен.





Если вы хотите:
Используйте:
Получить текущий сетевой корень по умолчанию
Функцию qnx_prefix_getroot()
Установить сетевой корень по умолчанию
Функцию qnx_prefix_setroot()
Запустить программу с новым сетевым корнем по умолчанию
Утилиту on


Передача имен путей между процессами


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

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


Псевдонимы префиксов

Мы рассмотрели префиксы, которые регистрируются менеджерами
ресурсов I/O. Вторая форма префикса известна как псевдоним
префикса
, это простая подстановка строки вместо искомого префикса.
Псевдоним префикса имеет форму:



prefix=строка-заменитель


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



/=//10/


Это приведет к тому, что ведущая косая черта (/) будет заменяться
на префикс //10/. Например, путь /usr/dtdodge/test будет
заменен следующим:

//10/usr/dtdodge/test

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

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



/dev=5,a:/=//10/


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


Создание специальных имен устройств


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



/dev/printer=//20/dev/spool


Любой запрос на открытие локального принтера /dev/printer
будет направляться по сети к реальному спулеру. Аналогичным образом,
если не существует локального дисковода для гибких дисков, псевдоним
для удаленного дисковода на узле 20 может иметь вид:



/dev/fd0=//20/dev/fd0


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

//20/dev/spool ИЛИ //20/dev/fd0


Относительные пути

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

Учтите, что результат зависит от того, начинается ли текущий
рабочий каталог с одинарной косой черты, либо с сетевого корня.


Текущий рабочий каталог

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

Например, эта команда:



cd //18/


является примером первой (определенной) формы и привязывает
последующие разборы относительных путей к узлу 18, независимо от того,
какое значение сетевого корня по умолчанию. Выполнив затем команду
cd dev, вы попадете в //18/dev.

С другой стороны, такая команда:


cd /


является примером второй формы, когда сетевой корень по умолчанию
влияет на разбор относительного пути. Например, если сетевой корень по
умолчанию //9, тогда, выполнив команду cd dev, вы попадете
в //9/dev. Так как текущий рабочий каталог не начинается с
указания узла, то сетевой корень по умолчанию добавляется для получения
полного сетевого пути.

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


Замечание о cd


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

В QNX, однако, cd не изменяет путь - за исключением
сокращенных ссылок "..". Например:



cd /usr/home/luc/test/../doc


установит текущий рабочий каталог /usr/home/luc/doc, даже
если некоторые элементы этого пути являются символическими связями.

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






Note: Чтобы получить полное сетевое имя пути, используйте утилиту
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. Это может быть достигнуто двумя
способами:

  • процесс может использовать функции Си dup(),
    dup2() или fcntl() для создания дубликата дескриптора
    файла, который указывает на тот же самый OCB;

  • при создании нового процесса посредством fork(),
    spawn() или exec(), все дескрипторы открытых файлов
    по умолчанию наследуются новым процессом; эти наследуемые дескрипторы
    указывают на те же самые OCB, что и соответствующие дескрипторы файла
    в родительском процессе.


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

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

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



fig: i/dupfd.gif




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






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




<!-- 4 -->


<!-- 5 -->

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



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




Введение


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



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


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

  • регулярные файлы - состоят из последовательности байт с
    произвольным доступом и не имеют предопределенной структуры;

  • каталоги - содержат информацию, необходимую для поиска
    регулярных файлов; также содержат статус и атрибуты для каждого
    регулярного файла;

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

  • программные каналы (pipes) и FIFO - служат как каналы
    ввода/вывода между взаимодействующими процессами;

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


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


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

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

  • дата последнего доступа (чтения);
  • дата последней записи;
  • дата последней модификации;
  • дата создания (уникальна для QNX).

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

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

  • владелец файла;
  • члены группы, к которой принадлежит владелец;
  • остальные.

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



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



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

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

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


Каталоги

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

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