프로그래밍/리눅스

리눅스 시그널 (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"가 출력된다.