// параметры запуска не используются
char* const argv[] = { NULL };
struct inheritance inh;
inh.flags = 0;
// флаг удаленного запуска
inh.flags |= SPAWN_SETND;
// дескриптор хоста
inh.nd = netmgr_strtond(node, NULL);
pid_t pid = spawnp(command, 0, NULL, &inh, argv, NULL);
...
}
Использованная здесь форма spawnp()
наиболее близка к базовой spawn()
и отличается лишь тем, что для поиска файла программы используется переменная системного окружения PATH
.
Приведем характерный пример вызова группы exec*()
:
int execl(const char* path, const char* arg0, const char* arg1, ...
const char* argn, NULL);
где path
— путевое имя исполняемого файла; arg0
, …, argn
— символьные строки, доступные процессу как список аргументов. Список аргументов должен завершаться значением NULL
. Аргумент arg0
должен быть именем файла, ассоциированного с запускаемым процессом.
Примечание
Устоявшаяся терминология «запускаемый процесс» относительно exec*()
явно неудачна и лишь вводит в заблуждение. Здесь гораздо уместнее говорить о замещении выполнявшегося до этой точки кода новым, выполнение которого начинается с точки входа главного потока замещающего процесса.
Примечание
Если вызов exec*()
выполняется из многопоточного родительского процесса, то все выполняющиеся потоки этого процесса предварительно завершаются. Никакие функции деструкторов для них не выполняются.
Если вызов exec*()
успешен, управление никогда уже не возвращается в точку вызова. В случае неудачи возвращается -1 и errno
устанавливается так же, как описано выше для spawn()
.
В качестве примера работы вызова spawn*()
(использование exec()
аналогично) рассмотрим приложение ( файлы p1.cc, p1ch.cc ), в котором:
• Родительский процесс ( p1 ) порождает дочерний ( p1ch ) и ожидает от него поступления сигнала SIGUSR1
(сигналы детально обсуждаются позже, но здесь попутно «вскроем» одну из их особенностей).
• Дочерний процесс периодически посылает родителю сигнал SIGUSR1
.
• Родительский процесс может переустановить (с помощью параметров командной строки запуска) для дочернего: период посылки сигнала (1-й параметр задан в нашем приложении константой) и приоритет, с которым будет выполняться дочерний процесс (2-й параметр, в качестве которого ретранслируется единственный параметр команды запуска родителя).
Примечание
В данный момент нас интересует только то приложение, в котором дочерний процесс порождается вызовом spawnl()
. Используемые приложением механизмы и понятия — сигналы UNIX приоритеты, наследование и инверсия приоритетов — будут рассмотрены позже, поэтому при первом чтении их можно опустить. Нам не хотелось перегружать текст дополнительными «пустыми» примерами, лишь иллюстрирующими применение одной функции. Это приложение, созданное «на будущее», позволит нам отследить крайне актуальный для систем реального времени вопрос о наличии (или отсутствии) наследования приоритетов при посылке сигналов (допустимо как одно, так и другое решение, но оно должно быть однозначно единственным для ОС).
Итак, родительское приложение ( файл p1.cc ):
Сигналы и наследование приоритетов
#include
#include
#include
#include
#include
#include
// обработчик сигнала
static void handler(int signo, siginfo_t* info, void* context) {
int oldprio = getprio(0);
setprio(0, info->si_value, sival_int);
cout << "SIG = " << signo << " old priority = "
<< oldprio << " new priority = " << getprio(0) << endl;
setprio(0, oldprio);
}
int main(int argc, char* argv[]) {
// установить обработчик сигнала
sigset_t sig;
sigemptyset(&sig);
//определение #define SIGUSR1 16
sigaddset(&sig, SIGUSR1);
sigprocmask(SIG_BLOCK, &sig, NULL);
struct sigaction act;
act.sa_mask = sig;
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;
if (sigaction(SIGUSR1, &act, NULL) < 0)
perror("set signal handler"), exit(EXIT_FAILURE);
// создать новый (дочерний) процесс
const char* prg = "./p1ch", *sdelay = "3";
pid_t pid =
((argc > 1 ) && (atoi(argv[1]) >= sched_get_priority_min(SCHED_RR)) &&
(atoi(argv[1]) <= sched_get_priority_max(SCHED_RR))) ?
spawnl(P_NOWAIT, prg, prg, sdelay, argv[1], NULL) :
spawnl(P_NOWAIT, prg, prg, sdelay, NULL);
if (pid == -1)
perror("spawn child process"), exit(EXIT_FAILURE);
// размаскировать и ожидать сигнала.
sigprocmask(SIG_UNBLOCK, &sig, NULL);
while (true) {
Читать дальше
Конец ознакомительного отрывка
Купить книгу