ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 리눅스 시그널 (signal)
    프로그래밍/리눅스 2014. 10. 2. 17:18

    리눅스에서 단 한번이라도 프로그래밍을 해봤다면 control+c를 누르면 프로그램이 중지되는 걸 볼 수 있을 것이다.

    이건 현재 실행중인 프로그램을 중지할 수 있는 무언가(?)를 했기 때문이다.

    이런 무언가를 리눅스에서는 시그널(Signal)이라고 한다.



    시그널의 종류는 굉장히 많은데 signum.h에 가보면 그 종류를 볼 수 있다.


    리눅스에서 프로그램이 실행하는 중에는 다양한 상황에 따라 OS에서 프로그램에 시그널을 날릴 수 있는데,

    이러한 시그널을 캐치해서 내가 의도하는 대로 프로그램을 돌아갈 수 있도록 만들어야 대처할 수 있으며 편해진다.

    이에 필요한 정보를 이제부터 하나하나 봐야겠다.

    /* Structure describing the action to be taken when a signal arrives.  */
    struct sigaction
      {
        /* Signal handler.  */
    #ifdef __USE_POSIX199309
        union
          {
      /* Used if SA_SIGINFO is not set.  */
      __sighandler_t sa_handler;
      /* Used if SA_SIGINFO is set.  */
      void (*sa_sigaction) (int, siginfo_t *, void *);
          }
        __sigaction_handler;
    # define sa_handler __sigaction_handler.sa_handler
    # define sa_sigaction __sigaction_handler.sa_sigaction
    #else
        __sighandler_t sa_handler;
    #endif
    
        /* Additional set of signals to be blocked.  */
        __sigset_t sa_mask;
    
        /* Special flags.  */
        int sa_flags;
    
        /* Restore handler.  */
        void (*sa_restorer) (void);
      };
    sa_handler : 시그널 핸들러. SIG_DFL 이 기본 값인데 시그널 자체의 행동을 수행한다. SIG_IGN을 넣어주면 해당 시그널을 무시한다.
    하지만 가장 중요한 것! 만약 여기에 시그널 핸들러의 포인터/함수이름을 주게 되면 그에 정의된 행동을 수행하게 된다.

    sa_mask : 마스크값으로 시그널 핸들러가 수행되는 동안 시그널을 block 혹은 non-block 으로 만드는 요소다.
    일반적으로 시그널은 쌓이지 않는데, sa_mask는 시그널이 처리되는 동안 나머지 시그널들을 블로킹 상태에 있도록 해서 순차적으로 시그널을 발생시키는 역할을 하게 된다.

    sa_flags : 시그널의 특성을 결정하는 변수로 or연산자(|)를 이용해서 여러개의 값을 줄 수 있다. 기본적으로 0을 준다.
    SA_NOCLDSTOP : 자식 프로세스가 중단 되었을 때  SIGCHLD 값을 받지 않는다.
    SA_ONESHOT : 한번 해당 시그널이 처리된 후에 signal action의 기본값을 재저장한다.
    SA_RESTART : SA_ONESHOT 과 반대되는 개념으로, signal action의 값을 저장하지 않는다. BSD 시그널에만 적용.
    SA_NOMASK : 시그널 핸들러로부터 발생되는 자체 시그널을 받지 않도록 한다.

    예제
    #include 
    #include 
    #include 
    #include 
    
    void Handler(int signo) {
      printf("Catch handler no : %d\n", signo);
      switch (signo) {
        case SIGINT:  printf("catch SIGINT\n"); break;
        case SIGALRM: printf("catch SIGALRM\n"); break;
      } // end of switch
      exit(0);
    }
    
    void CreateSignal() {
      struct sigaction action;
      action.sa_handler = Handler;
      sigfillset(&action.sa_mask);
      action.sa_flags = 0;
      sigaction(SIGINT, &action, NULL);
      sigaction(SIGALRM, &action, NULL);
    }
    
    int main() {
      CreateSignal();
    
      alarm(6);
      while (true) {
        printf("Continue..\n");
        sleep(1);
      } // end of while
    }
    

    만약 위 프로그램이 실행되는 동안 control+c를 입력하면 "catch SIGINT"가 출력된다.

Designed by Tistory.