Можно ли запустить процесс Linux, получив PID, но запустить позже при определенных условиях? - PullRequest
3 голосов
/ 19 октября 2019

Я думаю о каком-то инструменте, который может приостановить программу при запуске.

Например, my_bin запускается сразу.

$ ./my_bin

С этим инструментом

$ magic_tool ./my_bin

my_bin начнется. Я могу получить PID. Тогда я смогу начать фактический запуск позже.

Ответы [ 2 ]

5 голосов
/ 19 октября 2019

Я только что проверил свое предложение в комментариях, и оно сработало! Это код в моем magic_tool.c:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int main (int argc, char *argv[])
{
    pid_t pid; 

    printf("Executing %s to wrap %s.\n", argv[0], argv[1]);

    pid = fork();

    if (pid == -1)
        return -1;

    if (pid == 0) {
        raise(SIGSTOP);
        execl(argv[1], "", NULL);
    } else {
        printf("PID == %d\n", pid);
    }   

    return 0;
}

Я написал другую тестовую программу target.c:

#include <stdio.h>

int main ()
{
    puts("It works!\n");
    return 0;
}

Запустив ./magic_tool ./target, напечатал PID и вернулся в оболочку. Только после запуска kill -SIGCONT <printed_pid> был напечатан It works!. Возможно, вы захотите сохранить PID в другом месте, а также выполнить некоторые проверки в magic_tool, но я думаю, что это, тем не менее, хорошее подтверждение концепции.

РЕДАКТИРОВАТЬ:

Я немного поиграл с этим, и по какой-то причине это не всегда работало (см. Почему ниже). Решение простое - просто следуйте правильному расколу и умрите образец чуть более точно в magic_tool.c:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int main (int argc, char *argv[])
{
    pid_t pid; 

    printf("Executing %s to wrap %s.\n", argv[0], argv[1]);
    pid = fork();

    if (pid == -1)
        return -1;

    if (pid == 0) {
        setsid();
        pid = fork();

        if (pid == -1)
            return -1;

        if (pid == 0) {
            raise(SIGSTOP);
            if (execl(argv[1], "", NULL))
                return -1;
        }       
        printf("PID == %d\n", pid); 
    }
    return 0;
}

Я нашел объяснение в этом ответе :

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

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

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

Ответ также связан с IEEE Std 1003.1-2017 _Выходная запись , которая содержит более подробную информацию по этому вопросу.

4 голосов
/ 19 октября 2019

Это, в основном, идея, очень похожая на @gst, но сделанная полностью в оболочке, вы можете порождать подоболочку (это разветвляется и создавать новый pid) и заставить подоболочку отправлять сам сигнал SIGSTOP, когда подоболочка получает сигнал SIGCONT. подает сигнал и возобновляет, подоболочка exec намеченная программа (это заменяет подоболочку намеченной программой без создания нового pid). Чтобы основная оболочка могла продолжать работу, подоболочка должна работать в фоновом режиме с &.

В двух словах:

(kill -STOP $BASHPID && exec ./my_bin) &
subpid=$!    # get the pid of above subshell
... do something else ...
kill -CONT $subpid   # resume

Еще одна идея, которая не пострадаетИсходя из состояния гонки между основным процессом, отправляющим SIGCONT, и самим SIGSTOP-файлом подоболочки, вместо этого следует использовать дескриптор файла для реализации ожидания:

exec {PIPEFD}<> <(:)   # set PIPEFD to the file descriptor of an anonymous pipe
(read -u $PIPEFD && exec ./my_bin) &
subpid=$!    # get the pid of above subshell
... do something else ...
echo >&$PIPEFD    # resume
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...