[CS] Signal에 대해 알아보자

윤동환·2023년 4월 3일
0

Computer Science

목록 보기
6/10
post-thumbnail

Signal이란?

특정 이벤트가 발생했을 때 프로세스에게 전달하는 신호입니다.
인터럽트라고 부르기도 합니다.

IPC?

Inter-Process Communication의 약자로, 실행중인 프로세스간 데이터를 주고받는 기법입니다.

IPC 방법들

  • FIle
  • Signal
  • Pipe / Named Pipe
  • Socket
  • Shared Memory
  • Message Passing
  • Remote Procedure Call(RPC)

Signal Handlerc

프로세스가 특정 시그널을 포착했을 때 수행해야 할 별도의 함수입니다.
signal(signal_no, signal_handler)처럼 사용할 수 있습니다.
커널에 해당 시그널 번호를 감지하고 알려달라고 요청한 후 signal_handler를 콜백함수 처럼 사용 할 수 있습니다.

시그널 종류

시그널 구현 함수

시그널 처리 과정

  1. 시그널 선정(sigfillset, sigaddset,...)
  2. mask 설정 (sigprocmask)
    시그널을 처리할 동안 방해받지 않기 위함
  3. 각 시그널에 대한 처리행동 지정(handler 함수 구현)

시그널 집합을 생성하거나 조작

시그널을 다루기 위해선 집합을 만들어야 합니다.

#include <signal.h>

int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
//set : 시그널 집합
//return 
//호출 성공시 0, 실패시 -1
//단, sigismember는 성공적으로 완료되면 지정된 신호가 지정된 집합의 구성원이면 1을 반환하고 그렇지 않으면 0을 반환합니다.
//유효하지 않거나 지원하지 않는 신호번호는 -1을 리턴합니다. (EINVAL)

집합 사용 예시

sigset_t set;
int result;

sigemptyset(&set);
sigfillset(&set);
sigdelset(&set, SIGALRM);
sigaddset(&set, SIGLRM);
result = sigismember(set, SIGALRM); // &안붙인 이유는 변경시킬 수 없는 const형으로 받기때문임

sigaction

특정 시그널을 받았을 때 프로세스가 취해야 할 행동을 지정해줍니다.
signum으로 지정한 시그널에 대해 act로 지정한 행동을 취합니다.
새로운 act가 등록되면 기존 act는 oldact에 저장됩니다.

#include <signal.h>

int sigcation(int signum, const struct sigaction *act, struct sigaction *oldact);

함수 설명
signum : 시그널 번호(단, SIGKILL, SIGSTOP은 적용 불가)
act : 프로세스가 지정한 시그널에 대해 취할 행동에 대한 정보
oldact : 이전 시그널에 대한 행동이 저장됨. 보통은 NULL로 입력
반환 값 : 성공시 0, 실패시 -1

sigaction 구조체

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

sa_handler에서 시그널에 대응하는 행동

  • SIG_DFL : 기본으로 설정된 행동
    대부분의 시그널에 대해 프로세스 종료
  • SIG_IGN : 해당 시그널 무시, 지정한 시그널에 대한 행동 없음 (단, SIGSTOP, SIGKILL은 무시할 수 없음)

sa_sigaction 사용방법

  • sa_handler와 sa_sigaction 둘 중 하나만 사용한다.
  • sa_sigaction을 사용하기 위해선 sa_flags에 SA_SIGINFO로 지정해야한다.

sa_mask란?
봉쇄된 시그널들의 집합
등록된 시그널은 시그널 핸들러가 실행되는 동안 봉쇄(blocking)된다.
blocking : 무시가 아닌, 시그널 핸들러 실행이 완료될 때까지 처리가 미뤄진다.
현재 처리중인 시그널도 봉쇄될 수 있다.

sa_flag란?s
시그널 처리 절차를 수정하는데 사용된다.
" | "(bitwise-OR) 을 사용하여 여러 플래그 사용이 가능하다.

처리 가능 값

  • SA_SIGINFO : sa_handler 대신 sa_sigaction을 선택
  • SA_NOCLDSTOP : signum이 SIGCHLD일 때 자식 프로세스가 종료되거나 중단되더라도 부모 프로세스는 이를 알려고 하지 않는다.
    (자식의 상태에 신경을 안써도 되는 상황)
  • SA_RESETHAND : signum에 대해 시그널 핸들러를 최초에 한번만 실행하고 그 다음부터는 동일한 시그널에 대해 SIG_DFL에 해당하는 기본적인 동작만 수행한다.
  • SA_NODEFER : 시그널 핸들러 내에서 시그널 받는 것을 금지하지 않는다.
    (즉, 마스크를 사용하지 않는다.)

sigaction 사용 예제

#include <signal.h>
#include <unistd.h>
#include <stdio.h>



void int_handler(int signum) {
		staitc int num = 0;
        
        printf("SIGINT : %d\n", signum);
        printf("int_handler called %d times\n", ++num);
}

int main() {
        struct sigaction act; //구조체 선언

        act.sa_handler = int_handler; //핸들러 초기화
        sigfillset(&act.sa_mask); //sig
        sigaction(SIGINT, &act, NULL);

        while(1) {
                printf("I'm sleep\n");
                sleep(1);
                if (num > 2) {
                        act.sa_handler = SIG_DFL; //기본 시그널 설정
                        sigaction(SIGINT, &act, NULL);
                }

        }
}

출력 결과물

[ydh@krujyit1 ~/src/program/simple_control_signal]$ ./a.out
I'm sleep
I'm sleep
^CSIGINT : 2
int_handler called 1 times
I'm sleep
^CSIGINT : 2
int_handler called 2 times
I'm sleep
^CSIGINT : 2
int_handler called 3 times
I'm sleep
^C

SIGINT가 2라는 값으로 handler에 전달된 것을 확인할 수 있다.
또한, 전역변수 num을 제어하여 일정 횟수 입력시 종료됨을 확인할 수 있다.

Sigprocmask

profile
모르면 공부하고 알게되면 공유하는 개발자

0개의 댓글