Я беру курс ОС и пишу оболочку. И у меня возникла проблема с execvp() и pipe. Следующий код представляет собой упрощенную версию кода, в котором возникает проблема.
execvp() никогда не заканчивается на трубе
static pid_t
command_exec(command_t *cmd, int *pass_pipefd) //the function that executes commands. this function will be called multiple times if the input line contains multiple commands. Ex. "echo abc | cat"
{
pid_t pid = 0; //child pid
int pipefd[2]; //array for pipe
if(cmd->controlop == CMD_PIPE){
//if the control operation of the command is pipe(to the left of a '|'), create a pipe
pipe(pipefd);
}
pid = fork();
if(pid==0){ //child branch
dup2(*pass_pipefd,0);//redirect stdin to the pipe from last command
if(strcmp(cmd->argv[0],"cd")){ //if the command is not cd
if(cmd->controlop == CMD_PIPE){
dup2(pipefd[1],1);
//if command's control operation is pipe(to the left of a '|'), redirect stdout to pipefd[1]
}
if(execvp(cmd->argv[0],cmd->argv)<0)//execute the command,use stdin as input and stdout as output(but they may be redirected)
printf("%s fails\n",arg[0]);
}
exit(0);
}else{//if parent
wait(NULL); //wait for the child
if(cmd->controlop == CMD_PIPE){
*pass_pipefd = pipefd[0];//if command's control operation is pipe(to the left of a '|'), set *pass_pipefd to the output of the pipe array.
return pid;
}
}
Если вход «эхо-а», то выходной сигнал не является проблемой. execvp() завершит и ждет (NULL) в родительском не будет ждать вечно. Однако, если вход является «echo abc | cat», тогда «abc» будет выводиться на терминал, но программа застрянет. причина в том, что execvp(), который выполняет «cat», никогда не заканчивается, поэтому ожидание (NULL) в родительском ожидании навсегда. Я знаю, что execvp() не возвращается, но он должен в конечном итоге закончить. Я думаю, что я могу испортить вещи перенаправления stdin и stdout, но я не могу найти ошибку.
Проще говоря, вы не закрываете достаточно файлов decriptors. В частности, родитель должен закрыть оба конца трубы. У вас также нет родительского ожидания синхронно (хотя это не является частью вашей проблемы здесь). Вы должны разрешить всем процессам в конвейере работать сразу, потому что если у вас есть 'A | B', и вы дожидаетесь окончания 'A' до запуска' B', но 'A' производит больше данных, чем подходит в буфере канала (от 4 KiB до 64 KiB, IIRC, в зависимости от платформы), тогда' A' никогда не выходит , поэтому 'B' никогда не запускается, поэтому системные блокировки. _ [... продолжение ...] _ –
_ [... продолжение ...] _ Поскольку ваш код не является исполняемым - это не MCVE ([Минимальный, полный, проверяемый пример] (http: // stackoverflow .com/help/mcve)) - Я не склонен это исправлять; Я не могу сказать достаточно, как это называется, и как выглядят входные данные. Но 'cat' не заканчивается до тех пор, пока его стандартный ввод не вернет EOF, и пока есть процесс с открытием конца записи в трубе, его стандартный ввод не вернет EOF. Но у вашего кода оболочки довольно ясно, что труба открыта, поэтому вы снова зашли в тупик. –
@JonathanLeffler Спасибо, Джонатан. Я попробую это сделать – user2829353