본문 바로가기

Programming/Linux_Kernel

sigaction()


원문 : http://blog.naver.com/msd102?Redirect=Log&logNo=150009176058

-------------------------------------------------------------------------------------------


#include <signal.h>
int sigaction(int signum,  const  struct  sigaction  *act,
struct sigaction *oldact);



sigaction
() 시스템 호출은 특정 시그널의 수신에 대해서 취할 액션을 설정하거나 변경하기 위해서 사용된다.

signum는 시그널을 명시한다. SIGKILL과 SIGSTOP를 제외한 모든 시그널이 타당한 시그널이 될 수 있다.

만약 actnull이 아니라면 signum번호를 가지는 시그널에 대해서 act함수가 설치된다. 만약 oldact가 null이 아니라면 이전의 액션은 oldact에 저장된다.

sigaction구조체는 다음과 같이 정의되어 있다.

struct sigaction {    void (*sa_handler)(int);    void (*sa_sigaction)(int, siginfo_t *, void *);    sigset_t sa_mask;    int sa_flags;    void (*sa_restorer)(void);}		

sa_handler

signum번호를 가지는 시그널이 발생했을 때 실행된 함수를 설치한다. 함수외에도 SIG_DFL과 SIG_IGN을 지정할 수 있다. 전자는 시그널에 대한 기본행동을 후자는 시그널을 무시하기 위해서 사용한다.

sa_mask

sa_handler에 등록된 시그널 핸들러 함수가 실행되는 동안 블럭되어야 하는 시그널의 마스크를 제공한다. SA_NOMASK가 적용되어 있지 않다면

sa_flags

시그널 처리 프로세스의 행위를 수정하는 일련의 플래그들을 명시한다. 다음중 하나 이상의 것들에 의해서 만들어 진다.

SA_NOCLDSTOP

만약 signum이 SIGCHLD라면, 자식 프로세스가 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU등을 받아서 중단되었을 때 이를 통지 받을 수 없게 된다.

SA_ONESHOT, SA_RESETHAND

일단 시그널 처리기가 호출되면, 기본 상태에 대한 시그널 액션을 재 저장한다. 이는 signal(2)호출에 대한 기본 행위이다.

SA_RESTART

일부 시스템 호출들이 시그널을 통해 재시작할 수 있도록 함으로서 BSD 시그널과 호환되도록 한다.

SA_NOMASK, SA_NODEFER

시그널이 자체 시그널 처리기로부터 수신 받지 않도록 한다.

SA_SIGINFO

시그널 처리기가 하나가 아닌 3개의 인자를 취할경우 sa_handler대신 sigaction의 siginfo_t를 이용할 수 있다. siginto_t는 다음과 같이 정의된 구조체이다.

siginfo_t {    int      si_signo;  /* 시그널 넘버 */    int      si_errno;  /* errno 값 */    int      si_code;   /* 시그널 코드 */    pid_t    si_pid;    /* 프로세스 ID 보내기 */    uid_t    si_uid;    /* 프로세스를 전송하는 실제 사용자 ID */    int      si_status; /* Exit 값 또는 시그널 */    clock_t  si_utime;  /* 소모된 사용자 시간 */    clock_t  si_stime;  /* 소모된 시스템 시간 */    sigval_t si_value;  /* 시그널 값 */    int      si_int;    /* POSIX.1b 시그널 */    void *   si_ptr;    /* POSIX.1b 시그널 */    void *   si_addr;   /* 실패를 초래한 메모리 위치 */    int      si_band;   /* 밴드 이벤트 */    int      si_fd;     /* 파일 기술자 */}						
SIGCHLD 시그널은 si_pid, si_uid, si_status, si_utime, si_stime를 채운다. si_int, si_ptr은 시그널의 송신자에 의해서 명시될 수 있다.

si_code는 왜 시그널이 보내졌는지를 지시한다. 

----------------------------------------------------------------

sigaction() 함수는 signal() 보다 향상된 기능을 제공하는 시그널 처리를 결정하는 함수입니다. signal()에서는 처리할 행동 정보로 시그널이 발생하면 호출이될 함수 포인터를 넘겨 주었습니다. 그러나 sigaction()에서는 struct sigaction 구조체 값을 사용하기 때문에 좀더 다양한 지정이 가능합니다.

struct sigaction {    void (*sa_handler)(int);    
// 시그널을 처리하기 위한 핸들러. 
// SIG_DFL, SIG_IGN 또는 핸들러 함수
void (*sa_sigaction)(int, siginfo_t *, void *);
// 밑의 sa_flags가 SA_SIGINFO일때 

// sa_handler 대신에 동작하는 핸들러
sigset_t sa_mask;
// 시그널을 처리하는 동안 블록화할 시그널 집합의 마스크    int sa_flags;                // 아래 설명을 참고하세요.    void (*sa_restorer)(void);  // 사용해서는 안됩니다.}

ss_flgs는 아래와 같은 값이 사용되며, OR 연산자로 여러 개를 동시에 지정하여 사용할 수 있습니다.

옵션 의미
SA_NOCLDSTOP signum이 SIGCHILD일 경우, 자식 프로세스가 멈추었을 때,
부모 프로세스에 SIGCHILD가 전달되지 않는다.
SA_ONESHOT
또는 SA_RESETHAND
시그널을 받으면 설정된 행도을 취하고 시스템 기본 설정인
SIG_DFL 로 재설정된다.
SA_RESTART 시그널 처리에 의해 방해 받은 시스템 호출은 시그널 처리가
끝나면 재시작한다.
SA_NOMASK
또는 SA_NODEFER
시그널을 처리하는 동안에 전달되는 시그널은 블록되지
않는다.
SA_SIGINFO

이 옵션이 사용되면 sa_handler대신에 sa_sigaction이
동작되며, sa_handler 보다 더 다양한 인수를 받을 수
있습니다. sa_sigaction이 받는 인수에는 시그널 번호,
시그널이 만들어진 이유, 시그널을 받는 프로세스의
정보입니다.

 

헤더 signal.h
형태 int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
인수
int signum 시그널 번호
struct sigaction *act 설정할 행동. 즉, 새롭게 지정할 처리 행동
struct sigaction *oldact 이전 행동, 이 함수를 호출하기 전에 지정된 행동 정보가 입력됩니다.
반환
0 성공
-1 실패

예제 1

이번 예제도 signal()에서 처럼 Ctrl-C 를 누르면 사용자 핸들러가 실행되었다가 두 번째 Ctrl-C 키를 누르면 기존 방법대로 프로그램이 종료되도록 해 보겠습니다.

#include <stdio.h>#include <signal.h>struct sigaction act_new;struct sigaction act_old;void sigint_handler( int signo){   printf( "Ctrl-C 키를 눌루셨죠!!\n");   printf( "또 누르시면 종료됩니다.\n");   sigaction( SIGINT, &act_old, NULL);}int main( void){      act_new.sa_handler = sigint_handler; // 시그널 핸들러 지정   sigemptyset( &act_new.sa_mask);      // 시그널 처리 중 블록될 시그널은 없음                                              // SIGINT를 지정하면서 act_old에 이전 정보를 구합니다.                                              sigaction( SIGINT, &act_new, &act_old);    while(1 )   {      printf( "forum.falinux.com\n");      sleep( 1);   }}
]$ ./a.outforum.falinux.comforum.falinux.comCtrl-C 키를 눌루셨죠!!또 누르시면 종료됩니다.forum.falinux.comforum.falinux.com]$

예제 2

sigaction() 에서는 시그널 발생하여 처리 중일 때에는 다른 시그널이 발생하더라도 블록이 되도록 지정할 수 있습니다. Ctrl-C 키를 누르면 3초간 대기하도록 하는데, 이때 프로그램을 종료시키는 또다른 키인 Ctyrl-Z를 누르면 어떻게 되는지 보겠습니다.

#include <stdio.h>#include <signal.h>void sigint_handler( int signo){   int   ndx;   printf( "Ctrl-C 키를 눌루셨죠.\n");   printf( "3초간 대기하겠습니다. 이때 Ctrl-Z키를 눌러 주세요.\n");   for ( ndx = 3; 0 < ndx; ndx--){      printf( "%d 초 남았습니다.\n", ndx);      sleep( 1);   }}int main( void){   struct sigaction act;   act.sa_handler = sigint_handler;  // 시그널 핸들러 지정   sigfillset( &act.sa_mask);        // 모든 시그널을 블록   sigaction( SIGINT, &act, NULL);   while(1 )   {      printf( "forum.falinux.com\n");      sleep( 1);   }}
]$ ./a.outforum.falinux.comforum.falinux.comCtrl-C 키를 눌루셨죠.3초간 대기하겠습니다. 이때 Ctrl-Z키를 눌러 주세요.3 초 남았습니다.2 초 남았습니다.              <- Ctrl-Z 키를 누름1 초 남았습니다.[1]+  Stopped                 ./a.out]$ 

3초간 대기 중에 프로그램을 종료하기 위해 Ctrl-Z 키를 눌러도 모든 시그널에 대해 블록 처리가 되어 바로 Ctrl-Z 처리가 안됩니다. 그러다가 시그널 처리가 완료되어 핸들러에서 복귀되면 그때서야 Ctrl-Z 가 처리되어 프로그램이 종료됩니다.



sigaction man page 번역