Мне нужно уметь:
Я разрабатываю процесс, и у меня нет никакого способа проверить, сработал ли execvp ребенка или нет. Если это не удалось, мне нужно знать, что это не удалось. В настоящее время я использую
-1 != waitpid( pid, &status, WNOHANG )
Но кажется, что если execv процесса pid завершается неудачно, waitpid не возвращает -1.
Как я могу это проверить? Я прочитал справочную страницу waitpid, но она мне не понятна; может быть, мой английский недостаточно хорош
РЕДАКТИРОВАТЬ: чтобы объяснить больше:
Я строю свой собственный терминал для домашней работы. Мне нужно получить в качестве входных данных командную строку, скажем «ls», а затем я должен выполнить команду.
После того, как дочерний элемент разветвляется, дочерний элемент вызывает execvp для выполнения команды (после того, как я проанализирую строку), и родительский элемент должен проверить, был ли ‘&’в конце команды или нет.
если знак&’не существует в конце команды, тогда родитель должен ждать выполнения дочернего элемента.
поэтому мне нужно знать, если execvp не удалось. Если это не удалось, тогда родитель использует waitpid, чтобы дождаться, пока ребенок завершит выполнение. Если это не удалось, то родитель не будет ждать ребенка.
Распространенным решением для # 2 является открытие канала перед fork (), а затем запись в него в потомке после exec. В родительском случае успешное чтение означает сбой exec; неудачное чтение означает, что exec успешно завершен, а запись не состоялась.
// ignoring all errors except from execvp...
int execpipe[2];
pipe(execpipe);
fcntl(execpipe[1], F_SETFD, fcntl(execpipe[1], F_GETFD) | FD_CLOEXEC);
if(fork() == 0)
{
close(execpipe[0]);
execvp(...); // on success, never returns
write(execpipe[1], &errno, sizeof(errno));
// doesn't matter what you exit with
_exit(0);
}
else
{
close(execpipe[1]);
int childErrno;
if(read(execpipe[0], &childErrno, sizeof(childErrno)) == sizeof(childErrno))
{
// exec failed, now we have the child's errno value
// e.g. ENOENT
}
}
Это позволяет родителю однозначно узнать, был ли exec успешным, и в качестве побочного продукта, каким было значение errno в случае неудачи.
Если exec был успешным, дочерний процесс все еще может завершиться ошибкой с кодом завершения и проверкой состояния с помощью WEXITSTATUS
макрос даст вам это условие.
ПРИМЕЧАНИЕ: вызов waitpid
с WNOHANG
Флаг является неблокирующим, и вам может потребоваться опросить процесс, пока не будет возвращен правильный pid.
Вызов exec не должен возвращаться вообще, если он успешен, потому что он заменяет текущий образ процесса другим, поэтому, если это происходит, это означает, что произошла ошибка:
execvp(...);
/* exec failed and you should exit the
child process here with an error */
exit(errno);
Чтобы родительский процесс знал, если exec
не удалось прочитать статус дочернего процесса:
waitpid(pid, &status, WNOHANG);
А затем использовать WEXITSTATUS(status)
макрос из справочной страницы:
WEXITSTATUS (статус) возвращает статус выхода ребенка. это
состоит из наименее значащих 8 битов аргумента состояния,
дочерний элемент, указанный в вызове exit (3) или _exit (2) или в качестве аргумента для оператора возврата в main ()
Обратите внимание, что последнее утверждение означает, что если exec
успешно и запускает команду, вы получите статус выхода main()
функция этой команды, другими словами Вы не можете достоверно определить разницу между неудачной exec
и неудачная команда таким образом, так что зависит, если это имеет значение для вас.
Еще одна проблема:
если знак&’не существует в конце команды, то
Родителю нужно ждать, пока ребенок выполнит.
Вам нужно позвонить wait()
на дочернем процессе в какой-то момент в вашей программе, независимо от &
чтобы не оставлять дочерний процесс в живой мертвец государство,
Примечание: при использовании WNOHANG
это означает, что waitpid()
немедленно вернется, если ни один процесс не изменил свое состояние, то есть он не будет блокироваться, я полагаю, вы знаете это, в противном случае используйте wait()
или позвоните по телефону waitpid()
как часть вашего основного цикла.