1장. sigaction(2)
시그널 처리관련 함수
1.1. 사용법
#include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); int sigpending(sigset_t *set); int sigsuspend(const sigset_t *mask); |
1.2. 설명
sigaction() 시스템 호출은 특정 시그널의 수신에 대해서 취할 액션을 설정하거나 변경하기 위해서 사용된다.
signum는 시그널을 명시한다. SIGKILL과 SIGSTOP를 제외한 모든 시그널이 타당한 시그널이 될 수 있다.
만약 act가 null이 아니라면 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; /* 파일 기술자 */ }
si_code는 왜 시그널이 보내졌는지를 지시한다.
sigprocmask()는 현재 블록된 시그널들을 변경시키기 위해서 사용한다. 호출의 행위는 how 값들에 대해서 의존적이 된다. how는 다음중 하나를 선택할 수 있다.
- SIG_BLOCK
-
set에 설정된 시그널을 블럭 시그널셋에 추가시킨다.
- SIG_UNBLOCK
-
시그널 셋set의 시그널을 현재의 블럭된 시그널에서 삭제한다.
- SIG_SETMASK
-
시그널 셋set의 시그널을 블럭화된 시그널로 지정한다.
sigpending()함수는 전달 시그널들에 대한 검사를 허용한다. 전달 시그널들의 마스크는 set에 저장된다.
sigsuspend()는 프로세스의 시그널 마스크를 일시적으로 mask로 대체하고, 시그널이 수신될때까지 프로세스를 중지시킨다.
1.4. 에러
- EINVAL
-
부적절한 시그널이 지정되거나. 무시할 수 없는 SIGKILL SIGSTOP에 대한 액션을 변경하고자 할 경우
- EFAULT
-
act, oldact, set, oldset 이 타당하지 않은 메모리 영역을 가리킬 경우
- EINTR
-
시스템 호출이 인터럽트 되었다.
1.5. 예제
#include <signal.h> #include <unistd.h> #include <string.h> #include <stdio.h> void sig_int(int signo); void sig_usr(int signo); int main() { int i = 0; struct sigaction intsig, usrsig; usrsig.sa_handler = sig_usr; sigemptyset(&usrsig.sa_mask); usrsig.sa_flags = 0; intsig.sa_handler = sig_int; sigemptyset(&intsig.sa_mask); intsig.sa_flags = 0; // SIGINT에 대해서 sig_int를 등록한다. if (sigaction(SIGINT, &intsig, 0) == -1) { printf ("signal(SIGINT) error"); return -1; } // SIGUSR2에 대해서 usrsig를 등록한다. if (sigaction(SIGUSR2, &usrsig, 0) == -1) { printf ("signal(SIGUSR2) error"); return -1; } while(1) { printf("%dn", i); i++; sleep(1); } } void sig_int(int signo) { sigset_t sigset, oldset; // 핸들러가 수행되는 동안 수신되는 모든 시그널에 대해서 // 블럭한다. sigfillset(&sigset); if (sigprocmask(SIG_BLOCK, &sigset, &oldset) < 0) { printf("sigprocmask %d error n", signo); } fprintf(stderr, "SIGINT !!!!n"); sleep(5); } void sig_usr(int signo) { printf("sig_usr2n"); } |