[UNIX] 시그널

Taegang Yun·2023년 12월 8일
1

Unix 프로그래밍

목록 보기
12/19

시그널

소프트웨어 인터럽트로 프로세스에 뭔가 발생했음을 알리는 간단한 메시지를 비동기적으로 보내는 것.

시그널 핸들러

프로세스를 종료하기 전에 처리할 작업이 남아 있는 경우, 특정 시그널은 종료하고 않고자 하는 경우 시그널을 처리하는 함수를 지정하는 것.

시그널 집합

  • 복수의 시그널을 처리하기 위해 도입한 개념
  • 시그널 집합을 사용하면 여러 시그널을 지정해 처리할 수 있다

시그널 제어 함수

sigaction() 함수는 시그널을 받아 이를 처리할 시그널 핸들러를 지정할 분만 아니라 플래그를 설정해 시그널 처리 과정을 제어할 수도 있다.

시그널 보내기 : kill()

  • pid가 0보다 큰 수 : pid로 지정한 프로세스에 시그널을 전송
  • pid가 1이 아닌 음수 : 프로세스 그룹 ID가 pid의 절댓값인 프로세스 그룹에 속하고 시그널을 보낼 권한이 있는 모든 프로세스에 시그널을 전송
  • pid가 0 : 특별한 프로세스(스케줄러 등)를 제외하고 프로세스 그룹 ID가 시그널을 보내는 프로세스의 프로세스 그룹 ID와 같은 모든 프로세스에 시그널을 전송
  • pid가 1 : 시그널을 보내는 프로세스의 유효 사용자 ID가 root(수퍼 유저)가 아니면, 특별한 프로세스를 제외하고 프로세스의 실제 사용자 ID가 시그널을 보내는 프로세스의 유효 사용자 ID와 같은 모든 프로세스에게 시그널을 전송
kill(getpid(), SIGQUIT);

시그널 보내기 : raise()

시그널 보내기: abort()

  • 호출한 프로세스에 SIGABRT 시그널을 전송
  • SIGABRT 시그널 : 프로세스를 비정상적으로 종료시키고 코어 덤프 파일을 생성, 최소한 해당 프로세스가 연 파일은 모두 닫음
  • abort() 함수는 raise(SIGABRT) 와 같은 동작을 수행하지만 프로세스를 종료시키므로 리턴하지 않음

시그널 핸들러 지정 : signal()

  • 첫 번째 인자인 signum에는 SIGKILLSIGSTOP 시그널을 제외한 모든 시그널을 지정할 수 있음
  • handler 설정:
    • signal hander 주소
    • SIG_IGN : 시그널을 무시하도록 지정
    • SIG_DFL : 시그널의 기본 처리 방법을 수행하도록 지정
  • 버전 별 signal() 함수의 동작:
    • 시스템 V : 시그널을 처리한 후 시그널 처리 방법을 기본 처리 방법(SIG_DFL)으로 재설정, 따라서 시그널 처리를 계속하려면 signal() 함수를 호출해 시그널 처리 후 다시 설정해야함.
    • BSD : 시그널을 처리한 후 시그널 처리 방법을 기본 처리 방법(SIG_DFL) 으로 재설정하지 않음.
void sig_handler(int signo){
	psignal(signo, "Received Signal");
}

int main(){
	signal(SIGINT, sig_handler);
}

시그널 핸들러 지정 : sigset()

  • 얘도 SIGKILL, SIGSTOP 시그널은 못 옴.
  • sigset() 함수가 실패하면 SIG_ERR을 리턴

시그널 집합 비우기 : sigemptyset()

시그널 집합에 모든 시그널 설정 : sigfillset()

시그널 집합에 시그널 설정 추가 : sigaddset()

시그널 집합에서 시그널 설정 삭제 : sigdelset()

시그널 집합에 설정된 시그널 확인 : sigismember()

sigset_t st;

sigemptyset(&st);

sigaddset(&st, SIGINT);
sigaddset(&st, SIGQUIT);

sigismember(&st, SIGINT);

sigaction()

void sig_handler(int signo){
	
}

main(){
	struct sigaction act;
	
	sigemptyset(&act.sa_mask);
	sigaddset(&act.sa_mask, SIGQUIT);
	act.sa_flags = 0;
	act.sa_handler = sig_handler;

	sigaction(SIGINT, &act, (struct sigaction *)NULL);
}

**SIGINT → Ctrl + C, SIGQUIT → Ctrl + **

SA_RESETHAND

특정 시그널의 처리 방법이 핸들러 함수 처리 후 기본 처리 방법으로 재설정됨

void sig_handler(){

}

int main(){
	struct sigaction act;

	sigemptyset(&act.sa_mask);
	sigaddset(&act.sa_mask, SIGQUIT);
	act.sa_flags = SA_RESETHAND;
	act.sa_handler = sig_handler;
	sigaction(SIGINT, &act, (struct sigaction *)NULL);

}

시그널 발생 원인 검색

  • siginfo_t 구조체
    - si_signo : 관련된 시그널 번호
    - si_errno : 0 또는 시그널과 관련된 오류 번호
    - si_code : 시그널 발생 원인을 정의하는 코드
    void handler(int siig, siginfo_t info, void ucontext)

시그널 발생 원인 출력 함수 : psiginfo()

SA_SIGINFO 이용

void sig_handler(int signo, siginfo_t *st, ucontext_t *uc){
	psiginfo(st, "Received Signal");
}

int main(){
	struct sigaction act;

	act.sa_flags = SA_SIGINFO;
	act.sa_sigaction = (void (*)(int, siginfo_t *, void *)sig_handler;
	sigemptyset(&act.sa_mask);
	sigaction(SIGUSR1, &act, (struct sigaction *)NULL);
}

알람 시그널 생성 : alarm()

  • 인자로 지정한 시간이 지나면 SIGALRM 시그널이 생성되어 프로세스에 전달
  • 프로세스별로 알람시계가 하나밖에 없으므로 알람은 하나만 설정 가능
signal(SIGALRMM, sig_handler);

alarm(2);
sleep(3);

인터벌 타이머

  • ITIMER_REAL : 실제 시간 사용, 타이머 만료 시 SIGALRM 시그널
  • ITIMER_VIRTUAL: 프로세스가 사용하는 사용자 모드 CPU 시간, 만료 시 SIGVTALRM
  • ITIMER__PROF: 프로세스가 사용하는 시스템 모드 + 사용자 모드 CPU 시간, 만료 시 SIGPROF

타이머 정보 검색 : getitimer()

struct itimerval{
	struct timeval it_interval;
	struct timeval it_value;
};

struct timeval{
	time_t tv_sec;
	suseconds_t tv_usec;
};

타이머 설정 : setitimer()

void sig_handler(){

}

int main(){
	struct itimerval it;
	
	signal(SIGALRM, sig_handler);
	it.it_value.tv_sec = 3;
	it.it_value.tv_usec = 0;
	it.it_interval.tv_sec = 2;
	it.it_interval.tv_usec = 0;

	setitimer(ITIMER_REAL, &it, (struct itimerval *)NULL);

	while(1){
		getitimer(ITIMER_REAL, &it);
		printf("%d sec, ...);
		sleep(1);
	}
}

기타 시그널 처리 함수

  • 시그널 정보 출력 : psignal()
  • 시그널 정보 출력 : strsignal()
  • 시그널 블로킹과 해제 : sighold(), sigrelse();

시그널 집합 블로킹과 해제 : sigprocmask()

  • 첫 번째 인자인 how에 올 수 있는 값
    • SIG_BLOCK : set에 지정한 시그널 집합을 시그널 마스크에 추가
    • SIG_UNBLOCK : set에 지정한 시그널 집합을 시그널 마스크에서 제거
    • SIG_SETMASK : set에 지정한 시그널 집합으로 현재 시그널 마스크를 대체
int main(){
	sigset_t new;

	sigemptyset(&new);
	sigaddset(&new, SIGINT);
	sigaddset(&new, SIGQUIT);
	sigprocmask(SIG_BLOCK, &new, (sigset_t *)NULL);

	kill(getpid(), SIGQUIT);

	sigprocmask(SIG_UNBLOCK, &new, (sigset_t)*NULL);
}

시그널 기다리기 : sigsuspend()

  • 블로킹되지 않은 시그널이 도착할 때까지 프로세스의 수행을 멈추고 기다림.

시그널 무시처리 : sigignore()

profile
언젠간 전문가가 되겠지

0개의 댓글