2014-12-10 8 views
0

나는 명령 1의 관련 오류 코드, 오류가 반환됩니다 명령 줄에서 실행할 때 일부 입력이 있습니다오류 조건에 대해 올바른 WEXITSTATUS를 반환() waitpid를 얻을 수 없음

$ foo bar 
[some useful error message...] 
$ echo $? 
1 

나는 waitpid()으로이 오류 코드를 잡으려고 노력하고 있어요 :

... 
char *proc_cmd = "foo bar" 
pid_t proc = popen4(proc_cmd, in_fd, out_fd, err_fd, POPEN4_FLAG_NONE); 
... 
if (waitpid(proc, &global_foo_status, WNOHANG | WUNTRACED) == -1) { 
    /* process failed */ 
} 
... 
pthread_create(&proc_thread, NULL, perform_foo_function, bar_data); 
pthread_join(proc_thread, (void **) NULL); 
... 

프로세스가 실패 할 때까지로 인해 데이터에 오류가 bar_data 더 이상 처리하지 않는 것입니다, 또는 때까지 perform_foo_function()를 실행 내 스레드 :

static void * perform_foo_function (data *bar_data) { 
    /* check before */ 
    if (WIFEXITED(global_foo_status)) { 
     int exit_status = WEXITSTATUS(global_foo_status); 
     if (exit_status != 0) 
      /* process failed */ 
    } 

    /* do stuff with bar_data */ 
    while (bar_data) { 
     /* causes error ... */ 
    } 

    /* check after */ 
    if (WIFEXITED(global_foo_status)) { 
     int exit_status = WEXITSTATUS(global_foo_status); 
     if (exit_status != 0) 
      /* process failed */ 
    } 

    pthread_exit(NULL); 
} 

제 질문은이 프로세스의 오류 상태를 잡는 방법입니까? 디버깅 과정에서 의도적으로 오류 상황을 만들거나 합법적 인 입력을 제공하든 WEXITSTATUS은 항상 0입니다.

waitpid()에 대한 오해와 관련된 상태 코드 확인 및이를 작동시키기 위해 어떤 변경을해야합니까?

다음 코드는 차단하지 않고, 작동하는 것 같다

후속 :

... 
char *proc_cmd = "foo bar" 
pid_t global_foo_pid = popen4(proc_cmd, in_fd, out_fd, err_fd, POPEN4_FLAG_NONE); 
... 
if (waitpid(global_foo_pid, &global_foo_status, WNOHANG | WUNTRACED) == -1) { 
    /* process failed */ 
} 
... 
pthread_create(&proc_thread, NULL, perform_foo_function, bar_data); 
pthread_join(proc_thread, (void **) NULL); 
... 

static void * perform_foo_function (data *bar_data) 
{ 
    /* do stuff with bar_data */ 
    while (bar_data) { 
     /* causes error ... */ 
    } 

    /* check after */ 
    if (WIFEXITED(global_foo_status)) { 
     waitpid(global_foo_pid, &global_foo_status, WUNTRACED); 
     int exit_status = WEXITSTATUS(global_foo_status); 
     if (exit_status != 0) 
      /* process failed */ 
    } 

    pthread_exit(NULL); 
} 

을 나는 과정이 있기 때문에 waitpid() 전화가 응답하지 않습니다 "후 확인"같은데요 이 단계에서 이미 종료되었습니다.

답변

1

여기 몇 가지가 있습니다.

먼저 global_foo_status 변수는 waitpid() 또는 친구에게 전화를 건 후에 만 ​​업데이트됩니다. 표시된 코드에서 스레드를 만들기 전에 waitpid()으로 한 번만 호출하면됩니다. 따라서 사용중인 WIFEXITEDWEXITSTATUS 매크로는 모두 과 동일한 값인 waitpid()에 대한 초기 호출에서 작동합니다. 디버깅 할 때 항상 값이 0 인 이유는 프로세스가 종료 된 후 업데이트 된 값을 얻지 못하기 때문이며 그 값을 계속해서 반복해서 확인하기 때문입니다. 프로세스가 종료되었는지 여부를 확인하려면 매번 waitpid()으로 다시 전화해야합니다.

두 번째로 WIFEXITED은 프로세스가 정상적으로 종료되면 true로 평가되지만 프로세스가 종료 할 수있는 유일한 방법은 아닙니다. 신호가 수신되어 프로세스가 종료 된 경우 true로 평가되는 또 다른 매크로 인 WIFSIGNALED이 있습니다. WIFEXITED 만 사용하여 종료를 확인하고 프로세스에 의해 신호가 비정상적으로 종료되는 경우 영구적으로 검사하지 못할 수 있습니다. 어떤 이유로 든 프로세스가 중지되었는지 확인하려면 waitpid()의 반환을 사용하는 것이 좋습니다.

귀하의 기능은 아마 다음과 같아야합니다 전체 프로세스 검사도 별도의 함수로 밖으로 인수 분해를위한 주요 후보

static void * perform_foo_function (data *bar_data) { 

    /* check before */ 

    pid_t status = waitpid(global_foo_pid, &global_foo_status, WNOHANG); 
    if (status == -1) { 
     perror("error calling waitpid()"); 
     exit(EXIT_FAILURE); 
    } 
    else if (status == global_foo_pid) { 

     /* Process terminated */ 

     if (WIFEXITED(global_foo_status)) { 

      /* Process terminated normally */ 

      int exit_status = WEXITSTATUS(global_foo_status); 
      if (exit_status) { 
       /* Process failed */ 

       return NULL; 
      } 
      else { 
       /* Process terminated normally and successfully */ 

       return NULL; 
      } 
     } 
     else { 

      /* Process terminated abnormally */ 

       return NULL; 
     } 
    } 

    /* Process is still running if we got here */ 

    /* do stuff with bar_data */ 

    while (bar_data) { 
     /* causes error ... */ 
    } 

    /* Check after - if getting an error from doing stuff 
     with bar_data implies the process should always 
     shortly terminate, then you probably don't want 
     WNOHANG in the following line.      */ 

    status = waitpid(global_foo_pid, &global_foo_status, WNOHANG); 
    if (status == -1) { 
     perror("error calling waitpid()"); 
     exit(EXIT_FAILURE); 
    } 
    else if (status == global_foo_pid) { 

     /* Process terminated */ 

     if (WIFEXITED(global_foo_status)) { 

      /* Process terminated normally */ 

      int exit_status = WEXITSTATUS(global_foo_status); 
      if (exit_status) { 
       /* Process failed */ 

       return NULL; 
      } 
      else { 
       /* Process terminated normally and successfully */ 

       return NULL; 
      } 
     } 
     else { 
      /* Process terminated abnormally */ 

       return NULL; 
     } 
    } 

    pthread_exit(NULL); 
} 

있다.

perform_foo_function()을 동시에 실행하는 여러 스레드가있는 경우 waitpid()은 그 중 하나에서 적절하게 복귀 할 것입니다.waitpid()을 호출하기 전에 스레드가 확인할 수있는 별도의 변수 global_foo_has_finished 또는 이와 유사한 변수가 필요할 수 있습니다. 또한 모든 전역에 대한 액세스를 동기화하거나 필요하지 않게 다시 디자인해야합니다 (예 : global_foo_pid을 스레드 함수에 넣을 수 있습니다. global_foo_status은 다른 곳에서는 절대 액세스 할 수 없기 때문에 전역적일 필요가 없습니다.).