4-5 signal (학습)

do·2022년 4월 26일
1

API

목록 보기
26/42

Chapter 10(p.271~331)

  • 시그널
    • 특정 이벤트가 발생했을 때 프로세스에게 전달하는 신호
    • 연산 오류 발생, 자식 프로세스의 종료, 사용자의 종료 요청 등
    • 굉장히 작은 값
    • 소프트웨어 인터럽트라고도 부름
    • 용도가 제한적이며, 여러 시그널이 겹칠 경우 원치 않는 결과가 발생할 수도 있음
    • 여러 종류가 있고 각각에 유일한 번호가 붙어있음
      • 프로세스를 종료하기 전에 처리할 작업이 남아있거나, 특정 시그널에 대해 종료하고 싶지 않으면, 시그널을 받을 때 시그널 핸들러를 지정하면 됨.
    • CPU는 매번 명령을 수행하기 전, 인터럽트라인이 세팅되어있는지를 검사함
  • 시그널 액션
    • terminate 프로세스 종료
    • ignore 전달받은 시그널을 무시함 (SIGKILL, SIGSTOP는 catch 불가능하므로 제외)
    • stop 프로세스 정지
    • continue 프로세스 재개
    • terminate w/ Core 종료 시, Core의 Memory Image를 Dump하여 커널에 보관한 후 종료함. 저장된 Memory Image는 디버깅 등에 이용된다.
  • 시그널 집합 (Signal Set)
    • 시그널 집합은 시그널을 비트 마스크로 표현합니다. 시그널 하나가 비트 하나를 가리킵니다.
    • 각 비트가 특정 시그널과 1:1로 연결되어 있습니다.
    • 시그널 집합의 처리를 위해 sigset_t라는 구조체를 제공하는데, <sys/sygnal.h>에 정의되어 있으며, sigset_t 구조체는 크기가 4인 unsigned int 배열을 사용합니다.
typedef struct {
	unsigned int __sigbits[4];
} sigset_t;
  • 시그널 마스크
    • 위 시그널 집합들을 현재 등록된 시그널 마스크에 추가하면 블록됩니다.
    • 시그널 핸들러가 동작을 완료하기 전에는, 해당 집합의 시그널 처리가 불가능합니다.
    • 핸들러가 완료되어야 시그널이 처리됩니다.
  • 시그널 핸들링
    • 운영체제는 자식 프로세스의 전달값을 전달받고 자식 프로세스가 종료되었는지 인식할 수 있음
    • 따라서 부모 프로세스는 자식 프로세스의 종료 여부를 계속해서 확인할 수 없으니 운영체제 보고 알려달라고 함
    • 부모 프로세스는 하던 일을 멈추고 자식 프로세스의 종료와 관련된 일을 처리하고 다시 하던 일 하면 됨

1. signal()

함수 원형. void ( *signal (int signo, void(*func)(int)) )(int)
2개 인자를 받고, void형 함수포인터를 리턴함.
첫번째 인자는 signo 정수, 두번째 인자는 함수포인터인데 int형 인자를 하나 받고 리턴하는게 없음
마지막도 int형 인자를 하나 받음
기능. 시그널을 받을 때 해당 시그널을 처리할 함수나 상수를 지정할 수 있습니다.
헤더. <signal.h>
매개변수1. int signo 시그널 번호(SIGKILL9, SIGSTOP19 제외)
매개변수2. void(*func)(int) 시그널을 처리할 핸들러로 아래 3가지 중 하나를 설정해야함
1. 함수이름(시그널 핸들러의 주소) 시그널이 발생하면 지정된 함수를 호출한다.
2. SIG_IGN 시그널을 무시한다. (SIGKILL과 SIGSTOP은 무시할 수 없음)
3. SIG_DFL 기존 방법을 따른다.
리턴. (성공) 이전에 설정된 시그널 핸들러의 포인터를 리턴
(실패) SIG_ERR를 리턴
예시.
만약 두번째 인자가 함수 주소고,
signo가 SIGKILL(9), SIGTRAP(5), SIGPWR(30)이 아니라면,
signal 함수는 시그널을 처리한 후 시그널 처리 방법을 기본 처리 방법(SIG_DFL)로 재설정함.
따라서 시그널 처리를 계속하려면 signal 함수를 호출해 시그널을 처리한 후 다시 signal함수를 설정해야함.
#define 되어있음.

#define SIG_ERR (void (*) ()) -1 //시그널로 반환되면 오류가 발생함
#define SIG_DFL (void (*) ()) 0
#define SIG_IGN (void (*) ()) 1

2. sigaction()

함수 원형. int sigaction(int signo, const struct sigaction *act, struct sigaction *oldact)
기능. signal()보다 향상된 기능을 제공하는, 시그널 처리를 결정하는 함수
헤더. <signal.h>
매개변수1. int signo 시그널 번호
매개변수2. const struct sigaction *act 시그널을 처리할 방법을 지정한 구조체 주소
매개변수3. struct sigaction *oldact 기존에 시그널을 처리하던 방법을 저장할 구조체 주소. 보통 NULL값을 사용함 (새로운 행동인 act가 등록되면서 기존의 행동은 oldact에 저장됨)
리턴. (성공) 0, (실패) -1
signal()에서는 처리할 행동 정보로 시그널이 발생하면 호출이 될 함수포인터를 넘겨주었음. 그러나 sigaction()에서는 struct sigaction 구조체 값을 사용해서 좀 더 다양한 지정이 가능함.

sigaction 구조체.

struct sigaction {
	void (*sa_handler)(int);
    //시그널을 처리하기 위한 핸들러(SIG_DFL/SIG_IGN/핸들러함수)
    
    void (*sa_sigaction)(int, siginfo_t *, void *);
    //sa_handler 대신에 사용할 수 있고 sa_handler에 비해 추가 정보를 알 수 있음 (둘 중 하나만 사용)
    //sa_flags = SA_SIGINFO 여야함
    //int는 signo, siginfo_t*는 시그널이 발생한 원인을 담은 구조체 포인터
    //void * 시그널이 전달될 때 시그널을 받는 프로세스의 내부 상태를 나타내는 ucontext_t 구조체 포인터
    
	sigset_t sa_mask;
    //시그널 마스크: 봉쇄된 시그널들의 집합
    //sa_mask에 등록된 시그널은 시그널 핸들러가 실행되는 동안 봉쇄됨
    //봉쇄(blocking): 무시가 아니라, 시그널 핸들러 실행이 완료될 때까지 처리가 미뤄짐.
    				//현재 처리 중인 시그널도 봉쇄됨
    
	int sa_flags;
    //시그널 처리 절차를 수정하는데 사용됨
    //여러 플래그를 사용하고 싶으면 '|'(OR연산자) 사용
}

sa_flags

의미
SA_SIGINFOsa_handler 대신에 sa_sigaction을 선택함. sa_sigaction이 받는 인수에는 시그널 번호, 시그널이 만들어지는 이유, 시그널을 받은 프로세스의 정보 등 확인 가능함
SA_NOCLDSTOPsigno가 SIGCHILD일 때, 자식 프로세스가 종료되거나 중단되더라도 부모 프로세스는 이를 알려고 하지 않음
SA_RESETHANDsigno에 대해서 시그널 핸들러를 최초에 한번만 실행하고, 그 다음부터는 동일한 시그널에 대해서 SIG_DFL에 해당하는 기본적인 동작만 수행함
SA_NODEFER시그널 핸들러 내에서 시그널 받는 것을 금지하지 않음. 즉, 마스크를 사용하지 않음

3. sigemptyset()

함수 원형. int sigemptyset(sigset_t *set)
기능. 시그널 집합 비우기
시스템에서 정의한 모든 시그널을 배제해 인자로 지정한 시그널 집합을 빈 집합으로 만듭니다. 즉, 시그널 집합의 모든 비트를 0으로 설정합니다.
헤더. signal.h
매개변수1. sigset_t *set 시그널 집합
리턴. (성공) 0, (실패) -1

4. sigfillset()

함수 원형. int sigfillsetsigset_t *set)
기능. 시그널 집합에 모든 시그널 설정
인자로 받은 시그널 집합을 시스템에서 정의한 모든 시그널을 포함하는 집합으로 만듭니다. 즉, 시그널 집합의 모든 비트를 1로 설정합니다.
헤더. signal.h
매개변수1. sigset_t *set 시그널 집합
리턴. (성공) 0, (실패) -1

5. sigaddset()

함수 원형. int sigaddset(sigset_t *set, int signo)
기능. 시그널 집합에 시그널 설정 추가
signo로 정의한 시그널을 set로 지정한 시그널 집합에 추가합니다.
헤더. signal.h
매개변수1. sigset_t *set 시그널 집합
매개변수2 int signo
리턴. (성공) 0, (실패) -1

6. sigdelset()

함수 원형. int sigdelset(sigset_t *set, int signo)
기능. 시그널 집합에 시그널 설정 삭제
signo로 정의한 시그널을 set로 지정한 시그널 집합에 제거합니다.
헤더. signal.h
매개변수1. sigset_t *set 시그널 집합
매개변수2 int signo
리턴. (성공) 0, (실패) -1

7. sigismember()

함수 원형. int sigismember(sigset_t *set, int signo)
기능. 시그널 집합에 설정된 시그널 확인
signo로 정의한 시그널이 set로 지정한 시그널 집합에 포함되어 있는지 확인
헤더. signal.h
매개변수1. sigset_t *set 시그널 집합
매개변수2 int signo
리턴. (signo가 set에 속하면) 1
(signo가 set에 속하지 않으면) 0
(오류 시) -1

siginfo

sigaction 구조체 내 두번째 인자

siginfo_t {
               int      si_signo;     /* 시그널 넘버 */
               int      si_errno;     /* 에러 넘버 */
               int      si_code;      /* 시그널 발생 이유 */
               int      si_trapno;    /* 하드웨어 송신 시그널의 트랩넘버
               				(대부분 아키텍처에서 사용 x)*/
               pid_t    si_pid;       /* 시그널을 보낸 프로세스의 pid */
               uid_t    si_uid;       /* 시그널을 보낸 프로세스의 effective user id */
               int      si_status;    /* EXIT 값 혹은 시그널 */
               clock_t  si_utime;     /* 소요된 User time */
               clock_t  si_stime;     /* 소요된 System time */
               union sigval si_value; /* 시그널 발생시 전달할 값 */
               int      si_int;       /* POSIX.1b signal */
               void    *si_ptr;       /* POSIX.1b signal */
               int      si_overrun;   /* Timer overrun count;
                                         POSIX.1b timers */
               int      si_timerid;   /* Timer ID; POSIX.1b timers */
               void    *si_addr;      /* Memory location which caused fault */
               long     si_band;      /* Band event (was int in
                                         glibc 2.3.2 and earlier) */
               int      si_fd;        /* File descriptor */
               short    si_addr_lsb;  /* Least significant bit of address
                                         (since Linux 2.6.32) */
               void    *si_lower;     /* Lower bound when address violation
                                         occurred (since Linux 3.19) */
               void    *si_upper;     /* Upper bound when address violation
                                         occurred (since Linux 3.19) */
               int      si_pkey;      /* Protection key on PTE that caused
                                         fault (since Linux 4.6) */
               void    *si_call_addr; /* Address of system call instruction
                                         (since Linux 3.5) */
               int      si_syscall;   /* Number of attempted system call
                                         (since Linux 3.5) */
               unsigned int si_arch;  /* Architecture of attempted system call
                                         (since Linux 3.5) */
           }
   

1개의 댓글

comment-user-thumbnail
2022년 12월 21일

안녕하세요. 정리를 굉장히 잘해놓으신 덕분에 c언어 함수들을 익히는데 큰 도움을 받고 있습니다. 거의, 메뉴얼 급으로 설명과 예시가 잘 정리되었네요. 감사합니다.

답글 달기