signal handler란 프로세스가 실행되고 있는 중에 signal이 발생했을 시, '프로세스가 해당 signal에 어떻게 대응할 것인가?'를 선언해놓은 것이다.
우선 기본적인 signal handler 함수인 signal func에 대해 알아보자.
signal func의 함수 원형은 다음과 같다.
int signal(SIGNAL, sig_handler)
여기서 SIGNAL은 signal을 나타내는 상수값이고,
sig_handler는 SIGNAL이 발생했을 때, 호출할 함수이다.
1.하나의 signal을 처리하는 동안, 다른 signal이 도착할 경우 처리하지 못함.
2.signal에 대한 자세한 정보를 알지 못함
signal func의 단점을 보완한 new style signal handler로
1. 어떤 signal을 처리할 것인지
2. 해당 signal을 어떻게 처리할 것인지
3. signal을 처리하는 도중 다른 signal이 발생하면 어떻게 처리할 것인지
설정할 수 있다.
sigaction func의 함수원형
#include <signal.h>
int res = sigaction(int signum,
coust struct sigaction* action,
struct sigaction* prevaction);
ARGS:
1. signum: SIGNAL 상수, 처리할 Signal 정의(ex: SIGINT, SIGTERM, SIGKILL 등)
2. action: sigaction struct type. signum 발생 시 처리 동작 정의
3. prev: 이전에 등록된 신호 처리 동작 정보를 저장할 포인터(NULL로 처리 가능)
결국에 action이라는 argument가 해당 함수를 지배하는데,,
sigaction struct 원형
struct sigaction
{
void (*sa_handler)(int);// Old style
void (*sa_sigaction)(int, siginfo_t*, void*);// New style
sigset_t sa_mask;
int sa_flags;
}
Old style을 사용할 거면 그냥, signal func를 사용하면 된다. 굳이 sigaction을 사용할 필요가 없다.
sigaction 함수를 사용하는 이유는 해당 signal이 발생했을 때, 세세한 처리가 가능하기 때문이다. 이런 '세세한 처리'는 sigaction struct에 의해서 정의된다.
void (*sa_handler)(int) : 이거 쓸거면 나가라
void (sa_sigaction)(int, siginfo_t, void*):
이 자리에 함수가 들어가야 한다.
해당 함수는
1. return값이 void여야 하며,
2. args는 아래 형식을 따라야 한다
int : signum
siginfo_t : 신호와 관련된 상세 정보를 담고있는 구조체
void : 그냥 원하는 거 넣으면 된다. 출력한 txt라던가..
sa_mask: 신호를 처리하는 동안 차단(sa_flags에 따라 동작 결정)할 신호들의 집합
sigemptyset(): 신호 집합 초기화.
sigaddset(): 신호 추가.
sa_flags: 신호 처리 도중, 발생한 Signal에 대한 처리를 정의
SA_RESTART: 미뤘던 signal, handler 수행 이후 재시작
SA_SIGINFO: sa_sigaction 활성화.
SA_NODEFER: 해당 signal을 처리하는 중에 다시 같은 signal이 발생하면, kernel이 자동으로 blocking 하지 못하도록 설정
SA_RESETHAND: signal을 수신하고 handler를 호출한 이후, 해당 signal을 SIG_DFL로 설정
siginfo_t 구조체 원형
signal handler에 전달되는 siginfo에는 다음과 같은 정보가 담겨져 있다.
typedef struct {
int si_signo; // Signal number
int si_errno;
int si_code; // signal이 발생한 원인
pid_t si_pid;
uid_t si_uid;
void *si_addr;
int si_status;
union sigval si_value;
} siginfo_t;
sigaction의 args : int signum, sigaction struct* handler, prev
sigaction struct 멤버: sa_handler, sa_mask, sa_flags
예제
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <pwd.h>
#define INPUTLEN 100
char *uid_to_name(uid_t uid)
{
struct passwd *pw_ptr;
static char numstr[10];
if((pw_ptr = getpwuid(uid))==NULL)
{
sprintf(numstr, "%d", uid);
return numstr;
}else{
return pw_ptr->pw_name;
}
}
void int_handler(int sig, siginfo_t *siginfo, void *context)
{
printf("error value: %d, signal code: %d\n", siginfo->si_errno,siginfo->si_code);
printf("sending UID %-8s\n",uid_to_name(siginfo->si_uid));
printf("Called with signal %d\n",sig);
sleep(sig);
printf("done handling signal %d\n", sig);
}
int main()
{
struct sigaction new_handler;
sigset_t blockSet;
char x[INPUTLEN];
new_handler.sa_sigaction = int_handler;
new_handler.sa_flags = SA_RESETHAND | SA_SIGINFO | SA_RESTART;
sigemptyset(&blockSet);
sigaddset(&blockSet, SIGQUIT);
new_handler.sa_mask = blockSet;
if(sigaction(SIGINT, &new_handler, NULL) ==-1)
{
perror("sigaction err");
exit(EXIT_FAILURE);
}else{
while(1)
{
fgets(x, INPUTLEN, stdin);
printf("input: %s", x);
}
}
return 0;
}
SIGINT 발생시 new_handler의 sa_sigaction에 저장된 int_handler func 호출
int_handler 실행 도중, SIGQUIT signal 발생시, block 되었다가 int_handler가 종료되면 SIGQUIT 수행.
int_handler는 siginfo를 통해 signal에 대한 정보를 가지고, 이를 활용하여 다양한 task(uid, signal 정보, 등등) 수행 가능
critical section에 대해서 Signal을 수신하지 않도록 제어하기 위한 함수
sigprocmask 함수 원형
#include <signal.h>
int res = sigprocmask(int how, const sigset_t *sigs, sigset_t *prev);
ARGS
how:
sigs: signal들의 집합(data type: sigset_t)
prev: 안써도됨 걍 NULL
About sigset_t struct
sigset_t struct를 처음 선언한 이후,
sigemptyset(sigset_t* sigset)으로 초기화를 해준 뒤,
sigaddset(sigset_t *setp, int signum)으로 집합에 signal들을 추가해주면 된다.
예제
int main(void)
{
sigset_t sig_set;
int count;
sigemptyset(&sig_set);
sigaddset(&sig_set, SIGINT);
sigprocmask(SIG_BLOCK, &sig_set, NULL);
for(count =3; count>0; count --)
{
printf("count %d\n", count);
sleep(1);
}
printf("Unblocking SIGINT\n");
sigprocmask(SIG_UNBLOCK, &sig_set, NULL);
printf("Press Ctrl-C while count, this sentence will not be printed.\n");
while(1);
exit(0);
}