C сигнал родительского процесса от ребенка - PullRequest
0 голосов
/ 27 апреля 2010

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

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

Спасибо!

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

int errorPipe[2];
signal( SIGPIPE, SIG_IGN );

int oldflags = fcntl (errorPipe[0], F_GETFD, 0);
oldflags |= FD_CLOEXEC;
fcntl (errorPipe[0], F_SETFD, oldflags);
oldflags = fcntl (errorPipe[1], F_GETFD, 0);
oldflags |= FD_CLOEXEC;
fcntl (errorPipe[1], F_SETFD, oldflags);

pipe( errorPipe );

// in the child..
char *error_message = "exec failed";
write( errorPipe[1], error_message, strlen(error_message)+1 );
exit(-1);

// in the parent
printf("read gives: %d\n", read(errorPipe[0], error_read, MAX_LINE_LENGTH) );

Ответы [ 3 ]

4 голосов
/ 27 апреля 2010

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

[РЕДАКТИРОВАТЬ]: Как использовать это:

Если родитель должен подождать, пока не узнает, успешно ли выполнялся дочерний процесс execve() (объединяющий системный вызов), тогда он должен заблокировать read() в канале. Нулевой результат указывает на успех. (Убедитесь, что вы игнорировали SIGPIPE.)

Если у родителя есть какая-то структура обработки событий, основанная на неблокирующем вводе-выводе и select() (или poll() или kqueue() или ...), то дождитесь, пока канал станет читабельным, прежде чем пытаться прочитать сообщение ( которая будет нулевой длины, если ребенок правильно сделал execve().

2 голосов
/ 27 апреля 2010

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

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

Или вы можете wait (2) для дочернего процесса.

int child_pid = fork();
if (child_pid == 0) {
    execvp("/path/to/executable", ...);
    exit(123); /* this happens only if execvp() fails to invoke executable */
}

/* ... */

int status = 0;
int exit_pid = waitpid(-1, &status, WNOHANG);
if (exit_pid == child_pid && WIFEXITED(status)) {
    if (WEXITSTATUS(status) == 0) {
        /* child process exited fine */
    } else if (WEXITSTATUS(status) == 123)
        /* execvp() itself failed */
    } else {
        /* executed child process failed */
    }
}
0 голосов
/ 27 апреля 2010

Кэшируйте pid для (дочернего) процесса, для которого вы хотите проверить статус в родительском. Добавьте обработчик для SIGCHLD в родительском. В дочернем вызове exit с некоторым значением состояния по вашему выбору, чтобы обозначить, что execvp не удалось. При получении сигнала у родителя теперь у вас есть 2 варианта
a) Вызвать waitpid с pid -1 (то есть подождать любого дочернего элемента), проверить возвращаемое значение, если оно соответствует вашему кэшированному pid, проверить состояние с помощью макросов, таких как WEXITSTATUS.
б) Вызовите waitpid со своим кэшированным pid, а затем при возврате проверьте состояние выхода.

Чтобы сделать это надежным, вы должны позвонить в WIFEXITED (статус), прежде чем проверять статус выхода через WEXITSTATUS. WIFEXITED возвращает true, если дочерний процесс завершился нормально, то есть, вызвав exit или _exit, а не в результате ошибки сегмента, необработанного сигнала и т. Д. Также см. Man wait (2).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...