2015-01-30 2 views
0

Я беру курс ОС и пишу оболочку. И у меня возникла проблема с 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, но я не могу найти ошибку.

+1

Проще говоря, вы не закрываете достаточно файлов decriptors. В частности, родитель должен закрыть оба конца трубы. У вас также нет родительского ожидания синхронно (хотя это не является частью вашей проблемы здесь). Вы должны разрешить всем процессам в конвейере работать сразу, потому что если у вас есть 'A | B', и вы дожидаетесь окончания 'A' до запуска' B', но 'A' производит больше данных, чем подходит в буфере канала (от 4 KiB до 64 KiB, IIRC, в зависимости от платформы), тогда' A' никогда не выходит , поэтому 'B' никогда не запускается, поэтому системные блокировки. _ [... продолжение ...] _ –

+0

_ [... продолжение ...] _ Поскольку ваш код не является исполняемым - это не MCVE ([Минимальный, полный, проверяемый пример] (http: // stackoverflow .com/help/mcve)) - Я не склонен это исправлять; Я не могу сказать достаточно, как это называется, и как выглядят входные данные. Но 'cat' не заканчивается до тех пор, пока его стандартный ввод не вернет EOF, и пока есть процесс с открытием конца записи в трубе, его стандартный ввод не вернет EOF. Но у вашего кода оболочки довольно ясно, что труба открыта, поэтому вы снова зашли в тупик. –

+0

@JonathanLeffler Спасибо, Джонатан. Я попробую это сделать – user2829353

ответ

0

Проще говоря, вы не закрываете достаточно файлов decriptors. В частности, родитель должен закрыть оба конца трубы.

Кроме того, в оболочке вы не можете заставить родителя ждать синхронно для каждого дочернего элемента до завершения следующего (хотя это не является частью вашей проблемы здесь). Вы должны позволить всем процессам в конвейере запускаться сразу, потому что если у вас есть A | B, и вы дождались завершения A до запуска B, но A производит больше данных, чем подходит в буфере для труб (от 4 KiB до 64 KiB, IIRC, в зависимости от на платформе), то A никогда не выйдет, поэтому B никогда не запускается, поэтому системные блокировки.

Поскольку ваш код не является исполняемым - это не MCVE (Minimal, Complete, Verifiable Example) - я не склонен его исправлять; Я не могу сказать достаточно, как это называется, и как выглядят входные данные. Но cat не заканчивается до тех пор, пока его стандартный ввод не вернет EOF, и пока процесс с открытым концом канала открыт, его стандартный ввод не вернет EOF. Но у вашего кода оболочки довольно ясно, что труба открыта, поэтому вы снова зашли в тупик.

+0

Спасибо! Уже исправлено! Отмечено как правильный ответ. – user2829353

Смежные вопросы