Операционная система QNX 4.Архитектура системы

         

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


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

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



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


Для удовлетворения потребностей разных приложений в системе QNX реализованы три метода планирования:

планирование по принципу простой очереди (первым пришел_первым обслужен); круговой метод планирования; адаптивное планирование.

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

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

Три процесса, имеющие одинаковые приоритеты, находятся в состоянии ГОТОВ. Если процесс А блокируется, процесс В начнет выполняться.

Рис. 10

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



Если вы хотите Используйте
Определить метод планирования для процесса Функцию getscheduler()
Установить метод планирования для процесса Функцию setscheduler()



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


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

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



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


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

mount /dev/hd0t77 /

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

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



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


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

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

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

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



О команде cd


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

В QNX команда cd не изменяет путевое имя за исключением сокращений "..". Например, команда

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

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

Более подробно о символических связях и сокращениях см. раздел 5 "Администратор файловой системы".

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



О работе в реальном времени


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



Область действия Сетевого администратора


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



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


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

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

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

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

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

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



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


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

Можно также подключиться к масштабируемому прерыванию от таймера, которое выдается каждые 100 миллисекунд в зависимости от значения ticksize. Эти таймеры являются альтернативой таймерам стандарта POSIX 1003.4 при обработке прерываний нижнего уровня.



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


Отметим некоторые особенности работы процессов, которые "ловят" сигналы с помощью обработчика сигналов.

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

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



Однокомпьютерная модель


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

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



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


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



Операционная система с передачей сообщений


QNX стала первой коммерческой операционной системой данного класса, в которой IPC основан на принципе передачи сообщений. Именно благодаря глобальному использованию передачи сообщений во всей системе, ОС QNX обладает присущей ей мощностью, простотой и элегантностью.

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

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

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



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


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

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

Допустим, что у вас имеется контроллер диска 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 и т.д.



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


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

из интерпретатора (Shell) - с помощью утилит ps или sin; из программы - с помощью функции qnx_psinfo().

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

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

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



Определение способа обработки сигнала


Для задания способа обработки сигнала следует воспользоваться функцией ANSI C signal() или функцией POSIX sigaction().

Функция sigaction() предоставляет больше возможностей по управлению средой обработки сигнала.

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



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


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

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



Отключение виртуальных каналов


Существует несколько причин, по которым процесс не может осуществлять связь по установленным виртуальным каналам, а именно:

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

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

На каждом узле Администратор процессов проверяет целостность виртуального канала. Это делается следующим образом:

Каждый раз при успешной передаче по виртуальному каналу, обновляется временная метка, связанная с данным виртуальным каналом, для фиксации времени последней активности; Через интервалы времени, устанавливаемые при инсталляции, Администратор процессов просматривает каждый виртуальный канал. В том случае, если в виртуальном канале нет активности, Администратор процессов посылает сетевой пакет проверки целостности канала Администратору процессов другого узла; В том случае, если ответ не получен, или зафиксирован сбой, виртуальный канал помечается, как сбойный. Далее предпринимается ряд действий, определенных при инсталляции для восстановления связи; Если попытки восстановления закончились безуспешно, виртуальный канал "отключается". Все процессы, блокированные на данном канале, переходят в состояние ГOTOB (READY). (Процессы анализируют возвращаемый код сбоя виртуального канала.)

Для управления параметрами, связанными с проверкой целостности виртуального канала, используется утилита netpoll.



Относительные составные имена


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

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



Перечень сигналов


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

Сигнал Обрабатывается Действие по умолчанию Описание
Стандартные сигналы
SIGABRT да Завершить процесс Сигнал ненормального завершения, такой же, какой выдается функцией abort()
SIGALARM да Завершить процесс Сигнал истечения времени, такой же, какой выдается функцией alarm()
SIGFPE** да Завершить процесс Ошибочная арифметическая операция (целочисленная или с плавающей точкой), например, деление на 0 или операция, приводящая к переполнению
SIGHUP да Завершить процесс Гибель инициатора сессии, либо зависание на управляющем терминале
SIGILL да Завершить процесс Обнаружение аппаратной ошибки
SIGINT да Завершить процесс Интерактивный сигнал внимания ()
SIGKILL да Завершить процесс Сигнал завершения (следует использовать только в чрезвычайных ситуациях)
SIGPIPE да Завершить процесс Попытка записи в канал при отсутствии процессов, читающих из него
SIGOUIT да Завершить процесс Интерактивный сигнал завершения
SIGSEGV** да Завершить процесс Обнаружение неправильной ссылки в памяти
SIGTERM да Завершить процесс Сигнал завершения
SIGUSR1 да Завершить процесс Зарезервирован как 1-й сигнал, определяемый приложением
SIGUSR2 да Завершить процесс Зарезервирован как 2-й сигнал, определяемый приложением
Сигналы, управляющие работой процессов
SIGHLD да Игнорировать сигнал Завершить порожденный процесс
SIGCONT нет Продолжить процесс Продолжить, если данный процесс задержан задержки; игнориро вать сигнал, если этот процесс не задержан
SIGSTOP* нет Приостановить процесс Сигнал задержкки процесса
SIGTSTP* нет Игнорировать сигнал Не поддерживается в QNX
SIGTTIN нет Игнорировать сигнал Не поддерживается в QNX
SIGTTOU нет Игнорировать сигнал Не поддерживается в QNX
Специальные сигналы QNX
SIGBUS** да Завершить процесс Указывает на ошибку четности в памяти (специальная интерпретация QNX)
SIGDEV да Завершить процесс Генерируется, когда в Администраторе устройств возникает важное и запрашиваемое событие
SIGPWR да Завершить процесс Мягкая перезагрузка по нажатию клавиш <CTRL> <ALT> <SHIFT> <DEL> или по выполнению утилиты shutdown
Исторически оставшиеся сигналы UNIX
SIGIOT*** да Завершить процесс Команда IOT
SIGSIS*** да Завершить процесс Некорректный аргумент в системном вызове
SIGWINCH*** да Завершить процесс Смена окна
SIGURG*** да Завершить процесс Выполнение необходимого условия
SIGPOLL*** да Завершить процесс Выполнение выбранного события
SIGEMT*** да Завершить процесс Команда EMT (эмулятор внутреннего прерывания)
SIGTRAP да Завершить процесс Неподдерживаемое программное прерывание

Условные обозначения:

*обслуживающий процесс может "защитить" себя от этого сигнала посредством функции qnx_pflags(). Для этого обслуживающий процесс должен иметь уровень суперпользователя;
**процесс завершается в случае возникновения второго сбоя во время обработки процессом первого;
***этот сигнал оставлен для исторической совместимости с некоторыми версиями системы UNIX, он не генерируется никакими компонентами системы QNX.



Передача сообщений


Для прямой связи друг с другом взаимодействующие процессы используют следующие функции языка Си:

C-функция Назначение
Send() для посылки сообщений;
Receive() для приема сообщений;
Reply() для ответа процессу, пославшему сообщение.

Эти функции могут использоваться локально или по всей сети.

Обратите внимание на то, что для прямой связи процессов друг с другом необязательно использование функций Send(), Receive() и Reply(). Система библиотечных функций QNX надстроена над системой обмена сообщениями, поэтому процессы могут использовать передачу сообщений косвенно при использовании стандартных сервисных средств, например, программных каналов (pipe).

Процесс А посылает сообщение процессу В, который принимает его, обрабатывает и передает ответ.

Рис. 3

Приведенный выше рис. 3 иллюстрирует простой пример использования функций Send(), Receive() и Reply() при взаимодействии двух процессов - А и В:

Процесс А посылает сообщение процессу В, выдав ядру запрос Send(). С этого момента процесс А становится SEND-блокированным до тех пор, пока процесс В не выдаст Receive(), подтверждая получение сообщения; Процесс В выдает Receive() процессу А, ожидающему сообщения. Процесс А изменяет свое состояние на REPLY-блокированное. Поскольку от процесса В ожидается сообщение, он не блокируется.
Обратите внимание на то, что, если бы процесс В выдал Receive() до отправления ему сообщения, он оставался бы RECEIVE-блокированным до момента приема сообщения. В этом случае процесс А (отправитель) перешел бы сразу в REPLY-блокированное состояние после отправления сообщения процессу В; Процесс В выполняет необходимую обработку, определяемую полученным от процесса А сообщением, и выдает Reply(). Процесс А получает ответное сообщение и разблокировывается. Процесс В также разблокировывается. Какой из процессов начнет выполняться первым, зависит от их относительных приоритетов.



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


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

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



Передача составных сообщений


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

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

Creceivemx() Readmsgmx() Receivemx() Replymx() Sendmx() Writemsgmx()

Cоставное сообщение может быть описано с помощью управляющей структуры mx. Ядро собирает части сообщения в единый поток данных.

Риc. 6



Планирование по принципу простой очереди


При планировании по принципу простой очереди процесс, выбранный для выполнения, продолжает работать до тех пор, пока он:

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

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



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


При открытии файла, его составное имя сопоставляется с деревом префиксов для того, чтобы направить запрос 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 - это идентификатор процесса для администратора ресурсов ввода/вывода;
unit - это однознаковый номер, позволяющий выбирать один из нескольких возможных префиксов, которые имеет администратор.

В предыдущем примере, если Fsys - это процесс 3, а Dev - процесс 5, то дерево системных префиксов могло бы выглядеть так

/dev/hd0=3, a:/dev=5, а:/=3,е

Если вам нужно Воспользуйтесь
Отобразить на экране дерево префиксов Утилитой prefix
Получить доступ к дереву префиксов из Си-программы Функцией qnx_prefix_query()



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


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



Прием сигналов


В зависимости от того, каким образом был определен способ обработки сигнала, возможны три варианта его приема:

Если процессу не предписано выполнять каких-либо специальных действия по обработке сигнала, то по умолчанию поступление сигнала прекращает выполнение процесса; Процесс может проигнорировать сигнал. В этом случае выдача сигнала не влияет на работу процесса (обратите внимание на то, что сигналы SIGCONT, SIGKILL и SIGSTOP не могут быть проигнорированы при обычных условиях); Процесс может иметь обработчик сигнала, которому передается управление при поступлении сигнала. В этом случае говорят, что процесс может "ловить" сигнал. Фактически такой процесс выполняет обработку программного прерывания. Данные с сигналом не передаются.

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



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


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

fork() exec() spawn()

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



Приоритет, управляемый клиентом


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

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

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

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

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

Для установки приоритета, управляемого клиентом, воспользуйтесь функцией qnx_pflags()

qnx_pflags(~0, _PPF_PRIORITY_FLOAT | _PPF_PRIORITY_REC, 0, 0);



Приоритеты процессов


В системе QNX каждому процессу присваивается приоритет. Планировщик выбирает для выполнения процессы, находящиеся в состоянии ГОТОВ, в соответствии с их приоритетами. (Центральный процессор может использовать только процесс, находящийся в состоянии ГОТОВ.) Для выполнения выбирается процесс, имеющий наивысший приоритет.

На рис. 9 представлен пример выполнения процессов в соответствии с приоритетом.

Очередь процессов (A-F), находящихся в состоянии ГОТОВ. Остальные процессы (G-Z) блокированы. В данный момент выполняется процесс А. Процессы А, B и С имеют высший приоритет, поэтому они будут разделять процессорное время в соответствии с установленным алгоритмом планирования.

Рис. 9

Процессам присваиваются приоритеты в диапазоне от 0 (низший) до 31 (высший). По умолчанию процесс наследует приоритет от породившего его процесса; обычно он равен 10 для приложений, запускаемых из интерпретатора Shell.

Если вы хотите Используйте
Определить приоритет процесса Функцию getprio()
Задать приоритет процессу Функцию setprio()



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


Программный канал (pipe) - это неименованный файл, который служит каналом ввода/вывода между двумя или несколькими взаимодействующими процессами: один процесс выполняет запись в канал, другой - чтение из канала. Администратор файловой системы таким образом обеспечивает буферизацию данных. Размер буфера определяется как {PIPE_BUF} в файле . Канал удаляется, как только он закрывается с двух сторон.

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

Типичное применение программного канала - это соединение выхода одной программы со входом другой. Такое соединение часто выполняется интерпретатором Shell. Например,

ls | move

направляет стандартный выход от утилиты ls через канал на стандартный вход утилиты more.

Если вы хотите Используйте
Создать канал из интерпретатора Shell символ канала ("|")
Создать канал из программы функции Си pipe() или popen()

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



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


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

элеваторный доступ; кэш-буфер; многопоточную обработку; управляемый клиентом приоритет; временные файлы; электронные диски (ramdisk).



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


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

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

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



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


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

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

На рис._16 показано, как администратор ввода/вывода устанавливает соответствие между отдельными парами PID, FD и OCB.

Рис. 16



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


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



QNX как сеть


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

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

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



Работа с устройствами


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

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

Параметры tеrmios управляют функционированием устройств на низшем уровне, в частности они задают:

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

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

В приведенной ниже таблице представлены некоторые из этих функций.

Процесс может Посредством функции Си
Выполнять синхронизированные операции чтения dev_read() или read() + tcsetattr()
Асинхронно оповестить процесс о доступности данных на одном или нескольких устройств ввода dev_arm()
Ожидать полного завершения передачи выходных данных tcdrain()
Послать прерывание по каналу связи tcsendbreak()
Отсоединить коммуникационный канал tcdropline()
Ввести данные dev_insert_chars()
Выполнить неблокирующее чтение или запись (режим O_NONBLOCK) open() и fcntl()



Разделы операционной системы


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

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

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

Тип Операционная система
1 DOS (12-битовая FAT)
4 DOS (16-битовая FAT)
5 Раздел расширения DOS
6 Большие разделы DOS 4.0 (>32 Мбайт)
7 QNX 1.x и 2.x ("qnx")
7 OS/2 HPFS
8 QNX 1.x и 2.x ("qny")
9 QNX 1.x и 2.x ("qnz")
77 QNX 4.x
78 QNX 4.x
79 QNX 4.x
99 UNIX

Если вам требуется более одного раздела для QNX 4.x на одном физическом диске, то следует использовать тип 77 для первого раздела QNX, тип 78 для второго раздела QNX и тип 79 для третьего раздела QNX.

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

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

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

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

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

Таблица разделов

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

Рис. 23



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


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

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



Рекомендуемые функции для обработчиков сигналов


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

_exit() getegid() rmdir() tcdrain() access() geteuid() setgid() tcflow() alarm() getgid() setpgid() tcflush() cfgetispeed() getgroups() setsid() tcgetattr() cfgetospeed() getpgrp() setnid() tcgetpgrp() cfsetispeed() getpid() sigaction() tcsendbreak() cfsetospeed() getppid() sigaddset() tcsetattr() chdir() getuid() sigdelset() tcgetgrp() chmod() kill() sigemptyset() time() chown() link() sigfillset() times() close() lseek() sigismember() umask() creat() mkdir() signal() uname() dup2() mkfifo() sigpending() unlink() dup() open() sigprocmask() ustat() execle() pathconf() sigsuspend() utime() execve() pause() slup() wait() fcntl() pipe() stat() waitpid() fork() read() sysconf() write() fstat() rename()



Reply-управляемая передача сообщений


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

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



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


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

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

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

Приложение может уточнить режим доступа к вводимым данным при выдаче запроса на чтение посредством функции dev_read(). Уточнение, задаваемое параметром TIMEOUT, обычно используется в протоколах записи, либо в приложениях реального времени. Обратите внимание на то, что для функции read() значение TIMEOUT всегда равно 0.

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

MIN TIME TIMEOUT Описание
0 0 0 Возвратить управление немедленно, считав столько байтов, сколько доступно в данный момент (до n байтов)
М 0 0 Возвратить управление, считав до n байтов, только в том случае, если доступно по крайней мере M байтов
0 T 0 Возвратить управление, считав до n байтов, если доступен хотя бы один байт, либо если истекло T*0.1 секунд
M T 0 Возвратить управление, считав до n байтов, в том случае, если либо доступно не менее M байтов, либо если считан хотя бы один байт и интервал времени между последовательно считанными двумя любыми символами превысил T*0.1 секунд
0 0 t Зарезервировано
M 0 t Возвратить управление, считав до n байтов по истечении t*0.1 секунд, либо в случае доступности не менее M байтов
0 T t Зарезервировано
M T t Возвратить управление, считав до n байтов в случае доступности не менее M байтов, либо по истечении t*0.1 секунд после получения последнего символа, либо при получении хотя бы одного байта и превышении интервала времени между двумя последовательными считываниями символов T*0.1 секунд



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


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

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

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

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

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

stty term=vt100 </dev/ser1

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

stty term=qnx </dev/ser1



Считывание таймера


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



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


В системе 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, в результате чего получилось бы

< /pre>

ls //9/

Аналогично, если бы вы ввели команду

//5 ls /

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

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



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


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

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

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



Сигналы и сообщения


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

процесс разблокировывается; выполняется обработка сигнала; функции Send() или Receive() возвращают управление с кодом ошибки.

Если процесс был SEND-блокированным, то проблемы не возникает, так как получатель не получит сообщение. Но если процесс был REPLY-блокированным, то неизвестно, было обработано отправленное сообщение или нет, а следовательно неизвестно, нужно ли еще раз выдавать Send().

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

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

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