— префиксные компоненты пути исполняемого файла не являются каталогами;
Даже из этого очень краткого обзора вызова
spawn
становятся очевидными некоторые вещи:
• Эта форма универсальна (самодостаточна), она позволяет обеспечить весь спектр разнообразных форм порождения нового процесса
• Она же и самая громоздкая форма, тяжеловесная для практического кодирования, поэтому в реальных текстах в большинстве случаев вы вместо нее встретите ее конкретизации:
spawnl
,
spawnle
,
spawnlp
,
spawnlpe
,
spawnp
,
spawnv
,
spawnve
,
spawnvp
,
spawnvpe
.
Все эти формы достаточно полно описаны в [1]. Функционально они эквивалентны
spawn
, поэтому мы не станем на них детально останавливаться.
• Хотя вызов
spawn
и упоминается в описаниях как POSIX-совместимый, в QNX он существенно расширен и модифицирован и поэтому в лучшем случае может квалифицироваться как «выполненный по мотивам» POSIX.
В качестве примера приведем использованную в [4] (глава Д. Алексеева «Утилита on») форму вызова для запуска программы (с именем, заданным в строке
command
) на удаленном узле
node
(например,
/net/xxx
) сети QNET (как вы понимаете, это совершенно уникальная возможность QNX, говорить о которой в рамках POSIX-совместимости просто бессмысленно):
— символьные строки, доступные процессу как список аргументов. Список аргументов должен завершаться значением
NULL
. Аргумент
arg0
должен быть именем файла, ассоциированного с запускаемым процессом.
Примечание
Устоявшаяся терминология «запускаемый процесс» относительно
exec*
явно неудачна и лишь вводит в заблуждение. Здесь гораздо уместнее говорить о замещении выполнявшегося до этой точки кода новым, выполнение которого начинается с точки входа главного потока замещающего процесса.
Примечание
Если вызов
exec*
выполняется
из многопоточного родительского процесса, то все выполняющиеся потоки этого процесса предварительно завершаются. Никакие функции деструкторов для них не выполняются.
Если вызов
exec*
успешен, управление никогда уже не возвращается в точку вызова. В случае неудачи возвращается -1 и
errno
устанавливается так же, как описано выше для
spawn
.
В качестве примера работы вызова
spawn*
(использование
exec
аналогично) рассмотрим приложение ( файлы p1.cc, p1ch.cc), в котором:
• Родительский процесс ( p1) порождает дочерний ( p1ch) и ожидает от него поступления сигнала
SIGUSR1
(сигналы детально обсуждаются позже, но здесь попутно «вскроем» одну из их особенностей).
• Дочерний процесс периодически посылает родителю сигнал
SIGUSR1
.
• Родительский процесс может переустановить (с помощью параметров командной строки запуска) для дочернего: период посылки сигнала (1-й параметр задан в нашем приложении константой) и приоритет, с которым будет выполняться дочерний процесс (2-й параметр, в качестве которого ретранслируется единственный параметр команды запуска родителя).
Примечание
В данный момент нас интересует только то приложение, в котором дочерний процесс порождается вызовом
spawnl
. Используемые приложением механизмы и понятия — сигналы UNIX приоритеты, наследование и инверсия приоритетов — будут рассмотрены позже, поэтому при первом чтении их можно опустить. Нам не хотелось перегружать текст дополнительными «пустыми» примерами, лишь иллюстрирующими применение одной функции. Это приложение, созданное «на будущее», позволит нам отследить крайне актуальный для систем реального времени вопрос о наличии (или отсутствии) наследования приоритетов при посылке сигналов (допустимо как одно, так и другое решение, но оно должно быть однозначно единственным для ОС).