2013-02-10 9 views
0

경로 숙제를위한 기본 셸을 작성하고 해당 경로 목록에서 명령을 찾고 명령을 실행합니다. 그것은 또한 파이프를 다루기위한 것입니다. 그러나 자식 프로세스를 포크하면 gdb에서 "Write error : Broken Pipe"메시지가 나타나고 프로그램이 갑자기 종료됩니다.파이프로 포크 프로세스에서 프로그램 충돌이 발생했습니다

필자는 올바른 파이프를 열고 닫는 것에 대해 조심스럽게 생각하고 있기 때문에 왜 이런 일이 일어나고 있는지 이해할 수 없습니다. 원하는 프로세스대로 작동하는 것처럼 보입니다. C 및 유닉스 프로그래밍 경험이있는 사람이 문제 진단에 도움을 줄 수 있습니까? 논리적으로 잘못된 포크 구현/파이프 구현이 있습니까?

//commands is of the format {"ls -al", "more", NULL} 
//it represents commands connected by pipes, ex. ls -al | more 
char **commands = parseArgv(consoleinput, SPECIAL_CHARS[4]); 

int numcommands = 0; 

while(commands[numcommands]!=NULL) 
{ 
    numcommands++; 
} 

const int numpipes = 2*(numcommands-1); 

int pipefds[numpipes]; 

int i=0; 
for(i=0; i<numpipes;i=i+2) 
{ 
    pipe(pipefds+i); 
} 

int pipe_w = 1; 
int pipe_r = pipe_w - 3; 
int curcommand = 0; 

while(curcommand < numcommands) 
{ 
    if(pipe_w < numpipes) 
    { 
     //open write end 
     dup2(pipefds[pipe_w], 1); 
    } 

    if(pipe_r > 0) 
    { 
     //open read end 
     dup2(pipefds[pipe_r], 0); 
    } 

    for(i=0;i<numpipes;i++) //close off all pipes 
    { 
     close(pipefds[i]); 
    } 

    //Parse current command and Arguments into format needed by execv 

    char **argv = parseArgv(commands[curcommand], SPECIAL_CHARS[0]); 

    //findpath() replaces argv[0], i.e. command name by its full path ex. ls by /bin/ls 
    if(findPath(argv) == 0) 
    { 
     int child_pid = fork(); 

     //Program crashes after this point 
     //Reason: /bin/ls: write error, broken pipe 

     if(child_pid < 0) 
     { 
      perror("fork error:"); 
     } 
     else if(child_pid == 0)  //fork success 
     { 
      if(execv(argv[0], argv) == -1) 
      { 
       perror("Bad command or filename:"); 
      } 

     } 
     else 
     { 
      int child_status; 
      child_pid = waitpid(child_pid, &child_status, 0); 
      if(child_pid < 0) 
      { 
       perror("waitpid error:"); 
      } 
     } 
    } 
    else 
    { 
     printf("Bad command or filename"); 
    } 
    free(argv); 

    curcommand++; 
    pipe_w = pipe_w + 2; 
    pipe_r = pipe_r + 2; 
} 

//int i=0; 
for(i=0;i<numpipes;i++) //close off all pipes 
{ 
    close(pipefds[i]); 
} 

free(commands); 
+0

[최소 테스트 케이스] (http://sscce.org)를 만들 수 있습니까? –

+1

'pipe_w - 3'? 정말? –

+0

일반적인 표준 in/out 설명자를 닫기 전에 pipe descriptor를 복제합니다. _ 항상 errors_를 확인하십시오 ._ 또한 자녀에게도 복제해야합니다. –

답변

0

fork() 호출 후, 즉 하위 프로세스에서 파일 설명자를 복제하는 것이 올바른 방법입니다. 또한 waitpid()를 호출하면 하나의 자식 프로세스가 다른 프로세스를 기다리고 쉘이 중단됩니다. wait() 호출은 루프 이후로 이동되어야합니다. 즉 부모가 모든 자식을 기다려야합니다.