2014-11-26 5 views
0

정말 기본적인 쉘을 썼습니다. fork() 및 waitpid()를 사용하면 부모 프로세스가 자식을 기다리지 않습니다.waitpid()가 자식을 기다리지 않습니다.

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 
#include <sys/syscall.h> 
#include <linux/limits.h> 
#include "LineParser.h" 
#include <termios.h> 

#define MAX_STR 2048 
void execute(cmdLine *pCmdLine); 


int main() 
{ 
    char isContinuing = 1; 
    char path[PATH_MAX]; 
    char str[MAX_STR]; 
    char something[MAX_STR+PATH_MAX]; 
    cmdLine* cmd; 
    while(isContinuing) 
    { 
     getcwd(path, PATH_MAX); 
     printf("%s$ ", path); 
     fgets(str, MAX_STR, stdin); 
     if(!strncmp(str, "quit", strlen("quit"))) 
     { 
      isContinuing = 0; 
     } 
     else 
     { 
      cmd = parseCmdLines(str); 
      if(cmd->arguments != '\0') 
      { 
       execute(cmd); 
      } 
     } 
    } 

    freeCmdLines(cmd); 
    return 0; 
} 

void execute(cmdLine *pCmdLine) 
{ 
    pid_t id = fork(); 

    if(id == 0) 
    { 
     printf("I AM CHILD.\n"); 
     if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments)) 
     { 
      perror("execvp failed.\n"); 
      exit(1); 
     } 
     exit(0); 
    } 
    printf("I AM PARENT.\n"); 
    printf("WAITING FOR CHILD.\n"); 
    waitpid(id); 
    printf("DONE WAITING\n"); 

} 

LineParser 헤더 파일은 완전한 것이며 정상적으로 작동합니다. 지금, 어떤 이유로, 첫 번째 명령은 예상대로 작동하고, 는 이제 입력을 가정 해 봅시다 "에코 안녕", 출력은 예상대로

I AM PARENT. 
WAITING FOR CHILD. 
I AM CHILD. 
DONE WAITING. 

다음이 "안녕하세요"하고 경로를 인쇄, 명령을 다시 기다리는 중입니다. 내가 두 번째로 같은 입력 "에코 안녕하세요"를 입력 할 때 어떤 이유 , 출력은 다음과 같습니다

I AM PARENT. 
WAITING FOR CHILD. 
DONE WAITING. 
$PATH$ //(WITHOUT WAITING FOR INPUT !!!) 
I AM CHILD. 
hi 
//and here waiting for input// 

왜 이런 일이 발생합니까?

답변

1

코드 몇 가지 문제가 있습니다 다음 waitpid()에 대한 도달 할 수없는 코드에

  • 잘못된 매개 변수 목록을 exit() 문을 퍼팅 while 루프
  • 을 통해 모든 반복에 malloc이 메모리를 삭제하지

    1. 함수
    2. 실행 함수에서 상위 코드와 하위 코드의 구분이 불분명하다
    3. something가 SYS IMO/wait.h
    4. 에 대한 #include 누락/types.h
    5. SYS에 대한 #include 누락 fgets 기능
    6. 로부터의 반환 값을 확인하는 데 실패 변수가 사용되지 않은 : 문제는 struct cmdLine의 정의를 포함해야

    코드의 컴파일 가능한 버전은 다음과 같습니다. 컴파일러는 원래 코드에 많은 문제점을 발견했습니다.

    #include <stdio.h> 
    #include <unistd.h> 
    #include <string.h> 
    #include <stdlib.h> 
    #include <sys/syscall.h> 
    #include <linux/limits.h> 
    //#include "LineParser.h" 
    #include <termios.h> 
    #include <sys/types.h> 
    #include <sys/wait.h> // prototype for waitpid() 
    
    
    //note: pid_t waitpid(pid_t pid, int *status, int options); 
    
    
    struct cmdLine 
    { 
        char ** arguments; // arguments[x] = ptr to an argument string 
    }; 
    
    #define MAX_STR (2048) 
    #define MAX_PATH (256) 
    void execute(struct cmdLine *); 
    struct cmdLine * parseCmdLines(char *); 
    void freeCmdLines(struct cmdLine *); 
    
    
    
    int main() 
    { 
        char path[PATH_MAX]; 
        char str[MAX_STR]; 
        //char something[MAX_STR+PATH_MAX]; 
        struct cmdLine* pCmd = NULL; 
    
        while(1) 
        { 
         getcwd(path, PATH_MAX); 
         printf("%s$ ", path); 
         if(NULL == fgets(str, MAX_STR, stdin)) 
         { 
          perror("fgets failed"); 
          exit(EXIT_FAILURE); 
         } 
    
         // implied else 
    
         if(!strncmp(str, "quit", strlen("quit"))) 
         { // then strings equal 
          break; // exit while loop (and pgm) 
         } 
    
         // implied else input not equal 'quit' 
    
         pCmd = parseCmdLines(str); 
         if((NULL != pCmd) && (NULL != pCmd->arguments)) 
         { // then one or more arguments entered/parsed 
          execute(pCmd); 
         } // end if 
    
         freeCmdLines(pCmd); // free all strings memory, then free struct memory 
         pCmd = NULL; // cleanup 
        } // end while 
    
        return 0; 
    } // end function: main 
    
    
    void execute(struct cmdLine *pCmdLine) 
    { 
        int status = 0; 
        pid_t id = fork(); 
    
        if(id == 0) 
        { // then, child 
         printf("I AM CHILD.\n"); 
         if(!execvp(pCmdLine->arguments[0], pCmdLine->arguments)) 
         { // if no error then never gets here 
          perror("execvp failed.\n"); 
         } // end if 
        } 
    
        else 
        { // else, parent 
         printf("I AM PARENT.\n"); 
         printf("WAITING FOR CHILD.\n"); 
         waitpid(id, &status, 0); 
         printf("DONE WAITING\n"); 
        } // end if 
    } // end function: execute 
    
  • +0

    대단히 감사합니다! 사실 문제는 'waitpid()'에 있었고 while 루프 밖에서 무료로 사용한다는 것을 알지 못했습니다. 오케이. 그건 그렇고, 나는 무언가를 사용하지만, 완전한 코드에서는, 부적절하므로 여기서 제거하는 것을 잊었다. 다시 한번 감사드립니다. – Joseph

    +0

    'execvp', 대부분의 다른 함수는 실패시'-1'을 반환합니다. '0'을 반환하지 않습니다. 따라서'execvp failed '코드는 절대로 실행될 수 없습니다. –

    0

    waitpid(2)에 전화가 잘못되었습니다.

    man 2 waitpid에 따르면,는 다음과 같습니다

    waitpid(id, &status, 0); 
    

    이나 자식을 위해 작동 할 간단한 버전 wait(2)을 사용

    pid_t waitpid(pid_t pid, int *status, int options); 
    

    당신은 아마 int을 정의하고로 호출해야합니다 :

    wait(&status); 
    
    0

    이 함수는 잘못된 수의 인수를 사용하여 waitpid() 함수를 호출하여 정의되지 않은 동작입니다. 어떤 일이든 일어날 수있다.

    코드의이 단순화 된 변형 나를 위해 잘 작동 :

    #include <stdlib.h> 
    #include <stdio.h> 
    #include <unistd.h> 
    #include <sys/types.h> 
    #include <sys/wait.h> 
    
    int main() 
    { 
        int i; 
    
        for (i = 0; i < 3; i += 1) 
        { 
         pid_t id = fork(); 
    
         if(id == 0) 
         { 
          char *argv[] = { "echo", "hi", NULL }; 
    
          printf("I AM CHILD.\n"); 
          execvp("echo", argv); 
          /* failed to exec */ 
          perror("execvp failed.\n"); 
          exit(1); 
         } else if (id < 0) { 
          perror("fork failed.\n"); 
          exit(1); 
         } 
         printf("I AM PARENT.\n"); 
         printf("WAITING FOR CHILD.\n"); 
         waitpid(id, NULL, 0); 
         printf("DONE WAITING\n"); 
        } 
    
        return 0; 
    } 
    
    0

    귀하의 주요 문제는 컴파일러가 코드를 확인하지 않는다는 것입니다. 일반적으로 컴파일러 경고를 활성화하고이를 이해하려고 노력해야합니다.

    $ gcc -Wall -Wextra -Werror -Os -c myshell.c 
    

    이것은 내가 사용하는 최소 명령 줄입니다. 코드가 이러한 설정으로 컴파일되면 코드에서 찾기 힘든 버그를 이미 제거했습니다. 이 버그들 중에는 다른 사람들이 이미 언급 한 것처럼 waitpid에 대한 호출이 있습니다.

    http://pubs.opengroup.org/onlinepubs/7908799/xsh/waitpid.html을 살펴보십시오. 오픈 그룹 사양에서는 waitpid 기능을 사용하기 전에 과 <sys/wait.h> 두 개의 헤더 #include이 필요합니다. 당신의 프로그램은 이것을하지 않습니다.

    +0

    'waitpid()'의 매뉴얼 페이지는 포함해야하는 헤더를 알려줍니다. –

    +0

    ... 특정 시스템 및 운영 체제. Linux에서만 실행되는 소프트웨어를 개발하려면 Linux man 페이지보다 Open Group 사양을 고수해야합니다. –

    관련 문제