[OS] Signal 동작
Process간 통신을 하기 위해 signal을 사용한다. 우리가 평소에 자주 사용하는 많은 명령어들이 signal로 process에게 전달된다.
- Ctrl+c
- Ctrl+z
- kill 명령어
- 잘못된 메모리 참조
우리가 인위적으로 signal을 줄 수 있는 것들을 보는 방법은 다음과 같다.
$ 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 16) SIGSTKFLT 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 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX
Signal 중에 1 ~ 31까지는 RT가 안 붙고, 34번부터 RT
가 붙는데 이런 signal들은 Real Time 의 약자로 network 관련 프로그램에 사용된다.
Signal 전체를 다 외울 필요는 없고, 대표적인 signal을 보면 된다.
Number | Name | Return | Event Condition |
---|---|---|---|
1 | SIGHUP | 종료 | 터미널과 연결이 끊어졌을 때 |
2 | SIGINT | 종료 | 인터럽트로 Ctrl+c 입력 시 |
3 | SIGQUIT | Core dump | Ctrl+\ 입력 시 |
4 | SIGILL | Core dump | 잘못된 명령 사용 |
5 | SIGTRAP | Core dump | trace, breakpoint에서 trap 발생 |
6 | SIGABRT | Core dump | abort 함수에 의해 발생 |
9 | SIGKILL | 종료 | 강제 종료시 (Handler 설정 불가) |
10 | SIGUSR1 | 종료 | 사용자 정의 signal 1 |
11 | SIGSEGV | Core dump | Segmentation fault시 |
12 | SIGUSR2 | 종료 | 사용자 정의 signal 2 |
13 | SIGPIPE | Core dump | 파이프 처리 잘못 했을 때 |
14 | SIGALRM | Core dump | Alarm에 의해 발생 |
15 | SIGTERM | 실행 프로그램 종료 | |
17 | SIGCHLD | 무시 | Child process 상태 변할 시 |
18 | SIGCONT | 무시 | 중지 된 process 실행 시 |
19 | SIGSTOP | 중지 | 이 signal 받을 시 SIGCONT signal 받을 때 까지 process 중지 (Handler 설정 불가) |
20 | SIGSTP | 중지 | Ctrl+z 입력 시 |
Signal의 처리 방식은 크게 4가지로 나뉜다.
- 종료: 특별한 처리 방법을 선택하지 않음
- 무시
- 미리 등록한 handler 처리
- Core dump
Example
#include <signal.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> void catchint(int signo) { printf(" SIGINT Receive\n"); } int main() { signal(SIGINT,catchint); printf("sleep call #1\n"); sleep(1); printf("sleep call #2\n"); sleep(1); printf("sleep call #3\n"); sleep(1); printf("sleep call #4\n"); sleep(1); printf("Exiting"); return 0; }
$ ./a.out sleep call #1 ^C SIGINT Receive sleep call #2 ^C SIGINT Receive sleep call #3 ^C SIGINT Receive sleep call #4 ^C SIGINT Receive
위 프로그램은 Ctrl+c
를 눌러 SIGINT
signal이 왔을 때 handler를 호출하는 프로그램이다.
사용자 정의 Signal
사용자가 임의로 signal을 등록하는 프로그램은 다음과 같다. 사용자 정의는 10번 또는 12번이다.
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> void handler(int sig){ printf("signal no(%d) Received\n",sig); } int main() { if(signal(SIGUSR1,handler)==SIG_ERR) { fprintf(stderr,"cannot set USR1\n"); exit(1); } if(signal(SIGUSR2,handler)==SIG_ERR) { fprintf(stderr,"cannot set USR2\n"); exit(1); } for(;;) pause(); return 0; }
$ ./a.out signal no(10) Received signal no(12) Received ---------------------------------------------------- shumin@mercury:~$ ps -ef | grep a.out | grep -v grep shumin 30292 30034 0 21:46 pts/14 00:00:00 ./a.out shumin@mercury:~$ kill -10 30292 shumin@mercury:~$ kill -12 30292
위 프로그램을 실행시키고 난 뒤에 다른 터미널에서 해당 process ID를 통해 signal을 전달한 결과, 우리가 등록한 handler를 호출했다.
Example (kill 사용)
Source code에서도 kill을 system call 함수인 kill()
을 통해 사용할 수 있다.
// parent.c #include <signal.h> #include <stdio.h> #include <unistd.h> #define NUMCHILD 3 int main(int argc, char *argv[]) { int pid; int chpid[NUMCHILD]; int i, status; for(i=0;i<NUMCHILD;i++) { if((pid=fork())==0) execlp("./child","./child", (char *)0); chpid[i] = pid; } printf("parent : %d child process run\n",NUMCHILD); sleep(5); for(i=0;i<NUMCHILD;i++) kill(chpid[i],SIGINT); return 0; }
#include <signal.h> #include <stdio.h> #include <sys/types.h> #include <unistd.h> void sig(int sig) { printf("child die(%d)\n",getpid()); } int main() { signal(SIGINT,sig); pause(); return 0; }
$ ./sig_parent sig_parent : 3 child process run child die(30596) child die(30597) child die(30595)
위 프로그램은 3 개의 child process를 생성한 뒤에 5초동안 sleep 한 뒤에 모든 child process를 종료시킨다.