2016-05-07 6 views
1

私はエクササイズとして自分のシンプルなシェルを書いています。ゾンビプロセスを処理するには、SIGCHLDシグナルに登録する必要があります。何らかの理由で、sigactionを使用してハンドラを追加すると、プログラムは終了しますが、理由はわかりません。sigactionを使用すると私のプログラムが予期せず動作するのはなぜですか?

process_arglist()0を返されたが、私は1を返し、私は、信号処理がその影響を与える可能性がどのように表示されていない場合は、main()、我々の出口で見ることができます。

ここに私のコードです。それは&で終了するコマンドを処理する必要があります(私たちはfork()で、子コードでexecvpを使います)。 例:ping 127.0.0.1 -c 5 &

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <errno.h> 
#include <pthread.h> 
#include <signal.h> 
#include <sys/wait.h> 
#include <stdlib.h> 
#include <unistd.h> 

void sigchld_handler(int signal) { 
    int my_errno = errno; 
    while (waitpid(-1, 0, WNOHANG) > 0); // WNOHANG so handler will be non-blocking. 
    errno = my_errno; 
} 

int handle_background_command(int count, char** arglist) { 

    pid_t pid; 
    arglist[count - 1] = NULL; // remove "&" from arglist 

    //Handle SIGCHLD signal 
    struct sigaction sa, sa_dft; 
    sa.sa_handler = sigchld_handler; 
    sa.sa_flags = SA_NOCLDSTOP; 

    if (sigaction(SIGCHLD, &sa, &sa_dft) == -1) { 
    perror("error when trying to set signal action"); 
    exit(-1); 
    } 

    if((pid = fork()) == -1) { 
    perror("error when trying to fork() from handle_background_command()"); 
    exit(1); 
    } 

    if(pid == 0) { 

    // Child code 

    sigaction(SIGCHLD, &sa_dft, NULL); 

    if(execvp(arglist[0], arglist) == -1) { 
     perror("error when trying to execvp() from handle_background_command()"); 
     exit(1); 
    } 

    } 

    // Parent code 
    return 1; 
} 


int process_arglist(int count, char** arglist) 
{ 
    return handle_background_command(count, arglist); 
} 

int main(void) 
{ 
    while (1) 
    { 
     char** arglist = NULL; 
     char* line = NULL; 
     size_t size; 
     int count = 0; 

     if (getline(&line, &size, stdin) == -1) { 
      printf("out!"); 
      break; 
     } 


     arglist = (char**) malloc(sizeof(char*)); 
     if (arglist == NULL) { 
      printf("malloc failed: %s\n", strerror(errno)); 
      exit(-1); 
     } 
     arglist[0] = strtok(line, " \t\n"); 

     while (arglist[count] != NULL) { 
      ++count; 
      arglist = (char**) realloc(arglist, sizeof(char*) * (count + 1)); 
      if (arglist == NULL) { 
       printf("realloc failed: %s\n", strerror(errno)); 
       exit(-1); 
      } 

      arglist[count] = strtok(NULL, " \t\n"); 
     } 

     if (count != 0) { 
      int result = process_arglist(count, arglist); 
      printf("result = %d\n", result); 
      if (!result) { 
       free(line); 
       free(arglist); 
       printf("out\n"); 
       break; 
      } 
     } 

     free(line); 
     free(arglist); 
    } 
    pthread_exit(NULL); 
    return 0; 
} 

また、信号処理コードを取り除いても機能します。
理由は何ですか?

EDIT はここstraceユーティリティの出力(最後の行)です:

--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=2818, si_status=0, si_utime=0, si_stime=0} --- 
wait4(-1, NULL, WNOHANG, NULL)   = 2818 
wait4(-1, NULL, WNOHANG, NULL)   = -1 ECHILD (No child processes) 
rt_sigreturn()       = -1 EINTR (Interrupted system call) 
write(1, "out!", 4out!)      = 4 
exit_group(0)       = ? 
+++ exited with 0 +++ 
+0

strace' 'の下で実行して、何が起こるかを参照してください。ログファイル -ffo' straceの '。次に 'logfile'sを調べます。 –

+0

各呼び出しの後にエラーチェックを追加します。これは必須です。 –

答えて

1

あなたのプログラムは、(getlineのがシグナルハンドラによって中断された)のgetline関数からEINTR(中断システムコール)で終了します。

チェックこの:How to handle EINTR (interrupted System Call)

+0

'SA_RESTART'を追加すると、そのトリックがやりました!どうもありがとうございます! – LiorGolan

関連する問題