Signal and signal processing
프로세스가 다른 프로세스에게 signal을 보낼 수 있다. signal을 받은 프로세스는 signal에 대한 action을 취하며, signal이 여러가지 비동기식 이벤트를 처리하는 방법을 제공한다.
Signal Concepts
$ cc verybigprog.c #long time compiling
^C (Ctrl-C, interrupt key)
위 verybigprog.c는 굉장히 컴파일하는데 오래 걸린다고 하자. 도중에 Ctrl+C 나 interrupt key를 통해 중단할 수 있다. 이때 signal을 이용한다.
Ctrl + C나 interrupt key를 keyboard로 input 하면, kernel이 foreground로 작동 중인 모든 process들에게 SIGINT라고 하는 signal을 보낸다.
cc 프로세스가 이 signal을 받으면, 기본적으로 정해진 default action을 취한다. SIGINT에 대한 default action은 비정상종료이다.
process를 실행하다가 signal을 받아 user handler를 실행하고 난 후 다시 process를 돌아오는 것은 interrupts 방식이다.
다시 말해 signal은 software interrupt와 같이 작동한다.
signal은 asynchronous events (비동기식 이벤트)를 다루는 방식으로 제공된다.
process에게 signal이 왔다는 사실은 kernel이 process에게 알려준다.
모든 singal은 각각 SIG로 시작하는 이름을 가지고 있다.(eg. SIGABRT) signal 들은 양의 정수인 상수로 이루어져 있고 <signal.h>에 정의되어 있다.
signal 발생 방법
- terminal-generated signals (Control + C → SIGINT)
- hardware exception이 signal을 발생 (0으로 나누기 등)
- kill(2) system call
- shell에서의 kill(1) command ($ kill -9 #pid)
옵션 없이 kill 명령어를 실행하면 SIGTERM signal이 전달되어 종료
SIGNTERM signal로 종료되지 않으면 옵션 -9를 추가하여 SIGKILL을 전달함 - software conditions (SIGURG, SIGPIPE, SIGALRM 등)
kill의 옵션의 종류는 다음과 같다
[root@localhost root]# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 33) SIGRTMIN 34) SIGRTMIN+1 35) SIGRTMIN+2 36) SIGRTMIN+3 37) SIGRTMIN+4 38) SIGRTMIN+5 39) SIGRTMIN+6 40) SIGRTMIN+7 41) SIGRTMIN+8 42) SIGRTMIN+9 43) SIGRTMIN+10 44) SIGRTMIN+11 45) SIGRTMIN+12 46) SIGRTMIN+13 47) SIGRTMIN+14 48) SIGRTMIN+15 49) SIGRTMAX-14 50) SIGRTMAX-13 51) SIGRTMAX-12 52) SIGRTMAX-11 53) SIGRTMAX-10 54) SIGRTMAX-9 55) SIGRTMAX-8 56) SIGRTMAX-7 57) SIGRTMAX-6 58) SIGRTMAX-5 59) SIGRTMAX-4 60) SIGRTMAX-3 61) SIGRTMAX-2 62) SIGRTMAX-1 63) SIGRTMAX
상당히 많지만 주로 쓰는 범주는 1~31 까지이다.
이 중에서 SIGHUP은 SIGHangUp으로 exit명령어를 실행시 모든 프로세스에게 전달되어 종료시키는 역할을 한다. 이전 포스트에서 언급했었던 nohup의 경우 이 SIGHUP 신호를 막는 것이다.
Signal Types
- SIGABRT : generated by calling the abort function
abort함수를 실행시 프로세스를 종료시키기 위해 보내는 signal - SIGALRM : generated when a timer set with the alarm expires.
지정된 timer의 만료시 보내는 signal - SIGCHLD : whenever a process terminates or stops, the signal is sent to the parent.
child process가 종료되거나 중단되는 경우 parent process에게 보내는 signal - SIGCONT : this signal sent to a stopped process when it is continued.
중단된 process가 동작을 시작하도록 보내는 signal - SIGFPE : signals an arithmetic exception, such as divide-by-0, floating point overflow, and so on
0으로 나누거나, 부동소수점 overflow가 발생하는 등 계산적 오류시 보내는 signal - SIGILL : indicates that the process has executed an illegal hardware instruction.
잘못된 하드웨어 명령을 내렸을 때 보내는 signal - SIGINT : generated by the terminal driver when we type the interrupt key and sent to all processes in the foreground process group.
Ctrl+C와 같은 종료키를 눌렀을 때, foreground로 동작하는 모든 process에게 interrupt하도록 보내는 signal
강조하지만 signal은 kernel이 process에게 보내준다.
※ SIGINT와 SIGQUIT라는 유사한 signal이 있는데 이 둘의 차이는 SIGINT는 coredump를 남기지 않고, SIGQUIT는 coredump를 남긴다는 점이다.
- SIGKILL : can’t be caught or ignored. a sure way to kill any process.
kill 명령어에 -9 옵션을 주면 보내는 무시할 수 없는 종료 signal, 일반적으로 SIGTERM으로 종료할 수 없을 때 사용 - SIGPIPE : if we write to a pipeline but the reader has terminated, SIGPIPE is generated.
-- pipe RPC에 대한 내용 이후에 알아보자 - SIGSEGV : indicates that the process has made an invalid memory reference. (→ core dumped)
메모리 참조 오류 발생시 보내는 signal - SIGTERM : the termination signal sent by the kill(1) command by default.
kill(1)명령어를 기본으로 실행하면 보내는 종료 signal - SIGTSTP : Cntl-Z from the terminal driver which is sent to all processes in the foreground process group.
Ctrl + Z를 통해 모든 foreground process 에게 중단하도록 보내는 signal - SIGUSR1 : user defined signal 1
사용자 정의 signal - SIGUSR2 : user defined signal 2
사용자 정의 signal - SIGSTOP : job control signal. can’t be caught or ignored.
process의 동작을 잠시 중단하도록 보내는 signal
stop이나 사용자 정의 signal등의 일부 signal을 제외하고 나머지 signal은 대부분 default action이 종료이다.
Signal Lifecycle
- signal is a software notification to a process of an event.
signal은 process에 event가 발생하였다는 비동기적 알림이다 - signal is generated when the event that causes the signal occurs.
signal이 생성되고 - signal is delivered when the process takes action based on that signal.
signal이 process로 전달된다 - The lifetime of a signal is the interval between its generation and its delivery.
- signal that has been generated but not yet delivered is said to be pending.
signal이 전달되지 못하고 pending되는 경우가 있다. - process catches a signal if it executes a signal handler when the signal is delivered.
process가 전달되는 signal을 catch하지 못하면 default action으로 종료되나, catch하게 되면 사전에 정의된 signal handler를 interrupt 방식으로 실행한다. - program installs a signal handler by calling sigaction with the name of a user-written function.
해당 signal handler를 등록하는 것을 install이라고 하고, sigaction system call을 통해 install을 진행한다.
Normal and abnormal termination
#include <sys/wait.h>
void
pr_exit(int status)
{
if (WIFEXITED(status))
printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("abnormal termination, signal number = %d%s\n",WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? " (core file generated)" : "");
#else
"");
#endif
else if (WIFSTOPPED(status))
printf("child stopped, signal number = %d\n", WSTOPSIG(status));
}
위 코드는 정상종료 혹은 비정상 종료를 판별하는 코드이다.
child process가 종료되면 parent process의 wait(&status)를 통해 exit status를 받게된다.
WIFEXITED의 매개변수로 exit status를 전달하여 process가 정상종료하였는지를 판별한다.
만약 WIFSIGNALED가 true를 반환하면, signal을 받아 종료한 것이다.
stop signal을 통해서 child process가 잠시 중단되더라도 parent의 wait로 exit status가 전달되는데, 이 때는 WIFSTOPPED를 통해서 child가 stop되었음을 확인할 수 있다.
WEXITSTATUS를 통해 exit status의 값을 확인할 수 있고, 만약 WIFSIGNALED를 통해 signal로 인해 종료된 것임을 확인하면 WTERMSIG를 통해서 signal number를 확인할 수 있다.
signal을 받고 종료하였을 때, coredump를 하였나 확인하기 위해서 WCOREDUMP를 사용할 수 있다.
Signal handling
signal을 받으면 다음 세 가지 중 하나를 하게 된다.
- Ignore action (무시)
but two signals can never be ignored: SIGKILL and SIGSTOP
SIGKILL과 SIGSTOP은 무시하지 못함
- User-defined action. (사용자 정의)
To do this, we tell the kernel to call a function of ours whenever the signal occurs. (signal handler)
process가 signal을 catch하여 종료 대신 사용자가 정의한 signal handler를 실행하고 프로세스를 재개한다.
Note that the two signals SIGKILL and SIGSTOP can't be caught.
SIGKILL과 SIGSTOP은 catch하지 못함
- Default action. (SIG 고유 default action)
Every signal has a default action,
The default action is normally to terminate process
다음 5개를 제외한 대부분의 경우 default action이 프로세스 종료
default action : SIGSTOP(stop), SIGTSTP(stop), SIGCONT(continue), SIGUSR1(ignore), SIGUSR2(ignore)
Signal handling : User-defined action
위 그림은 어떤 process q가 실행 중에 signal을 받는 상황이다.
process가 signal을 catch하게 되면, signal handler를 실행하고 handler가 끝나면 다시 원래 위치로 돌아와서 q process를 실행한다.
signal을 catch하고 handler를 실행하고 돌아오는 동안 process가 실행하지 않는다. 이와 같은 방식이 interrupt한 방식이다.
signal handler가 종료하였을 때, process가 signal을 catch하였던 위치로 돌아가 process를 재개한다.
asynchronous하기 때문에, signal handler에서 process가 signal을 catch하여 실행된 위치가 어딘지는 모른다.