학습목표 시그널의기본개념을이해한다. 시그널을보내는방법을이해한다. 시그널을받아서처리하는기본적인방법을이해한다. 시그널집합의개념과사용방법을이해한다. sigaction 함수를사용해시그널을처리하는방법을이해한다. 알람시그널의처리방법을이해한다. 시그널관련기타함수들의사용방법을이해한다. 시그널 IT CookBook, 유닉스시스템프로그래밍 2/38 목차 시그널의개념 시그널의종류 시그널보내기 시그널핸들러함수 시그널집합 sigaction 함수의활용 알람시그널과인터벌타이머 기타시그널관련함수 시그널의개념 시그널 소프트웨어인터럽트프로세스에뭔가발생했음을알리는간단한메시지를비동기적으로보내는것 발생사유 0으로나누기처럼프로그램에서예외적인상황이일어나는경우 kill 함수처럼시그널을보낼수있는함수를사용해서다른프로세스에시그널을보내는경우 사용자가 Ctrl+C와같이인터럽트키를입력한경우 시그널처리방법 각시그널에지정된기본동작수행. 대부분의기본동작은프로세스종료 시그널을무시 시그널처리를위한함수 ( 시그널핸들러 ) 를지정해놓고시그널을받으면해당함수호출 시그널이발생하지않도록블록처리 3/38 4/38
시그널의종류 시그널보내기 [1] kill 명령 프로세스에시그널을보내는명령 예 : 3255 번프로세스에 9 번시그널 (SIGKILL) 보내기 -> 프로세스강제종료 # kill 9 3255 시그널보내기 : kill(2) #include <sys/types.h> 이외에도시그널의종류는다양함 ( 표 7-7 참조 ) int kill(pid_t pid, int sig); pid 가 0 보단큰수 : pid 로지정한프로세스에시그널발송 pid 가 -1 이아닌음수 : 프로세스그룹 ID 가 pid 의절대값인프로세스그룹에속하고시그널을보낼권한을가지고있는모든프로세스에시그널발송 pid 가 0 : 특별한프로세스를제외하고프로세스그룹 ID 가시그널을보내는프로세스의프로세스그룹 ID 와같은모든프로세스에게시그널발송 pid 가 -1 : 시그널을보낸는프로세스의유효사용자 ID 가 root 가아니면, 특별한프로세스를제외하고프로세스의실제사용자 ID 가시그널을보내는프로세스의유효사용자 ID 와같은모든프로세스에시그널발송 5/38 6/38 [ 예제 7-1] kill 함수사용하기 ex7_1.c 시그널보내기 [2] 01 #include <sys/types.h> 02 #include <unistd.h> 03 04 #include <stdio.h> 05 06 int main(void) { 07 printf("before SIGCONT Signal to parent.\n"); 08 09 kill(getppid(), SIGCONT); 10 11 printf("before SIGQUIT Signal to me.\n"); 13 kill(getpid(), SIGQUIT); 14 15 printf("after SIGQUIT Signal.\n"); 16 17 return 0; 18 } SIGQUIT 의기본동작은코어덤프 # ex7_1.out Before SIGCONT Signal to parent. Before SIGQUIT Signal to me. 끝 (Quit)( 코어덤프 ) 시그널보내기 : raise(2) int raise(int sig); 함수를호출한프로세스에시그널발송 시그널보내기 : abort(3) #include <stdlib.h> void abort(void); 함수를호출한프로세스에 SIGABRT 시그널발송 SIGABRT 시그널은프로세스를비정상적으로종료시키고코어덤프생성 7/38 8/38
시그널핸들러함수 [1] [ 예제 7-2] signal 함수사용하기 ex7_2.c 시그널핸들러 시그널을받았을때이를처리하기위해지정된함수 프로세스를종료하기전에처리할것이있거나, 특정시그널에대해종료하고싶지않을경우지정 시그널핸들러지정 : signal(3) void (*signal(int sig, void (*disp)(int)))(int); disp : sig 로지정한시그널을받았을때처리할방법 시그널핸들러함수명 SIG_IGN : 시그널을무시하도록지정 SIG_DFL : 기본처리방법으로처리하도록지정 signal 함수는시그널이들어올때마다시그널핸들러를호출하려면매번시그널핸들러를재지정해야함. 9/38 08 printf("signal Handler Signal Number : %d\n", signo); 09 psignal(signo, "Received Signal"); 10 } 11 int main(void) { 13 void (*hand)(int); 14 15 hand = signal(sigint, handler); 16 if (hand == SIG_ERR) { 17 perror("signal"); 18 exit(1); 19 } 20 21 printf("wait 1st Ctrl+C : SIGINT\n"); 22 pause(); 23 printf("after 1st Signal Handler\n"); 24 printf("wait 2nd Ctrl+C : SIGINT\n"); 25 pause(); 26 printf("after 2nd Signal Handler\n");27 28 return 0; 29 } # ex7_2.out Wait 1st Ctrl+C : SIGINT ^CSignal Handler Signal Number : 2 Received Signal: Interrupt After 1st Signal Handler Wait 2nd Ctrl+C : SIGINT ^C# 두번째 Ctrl+C는처리못함 10/38 [ 예제 7-3] 시그널핸들러재지정하기 ex7_3.c 08 void (*hand)(int); 09 hand = signal(sigint, handler); 시그널핸들러재지정 10 if (hand == SIG_ERR) { 11 perror("signal"); exit(1); 13 } 14 15 printf("signal Handler Signal Number: %d\n", signo); 16 psignal(signo, "Received Signal"); 17 } # ex7_3.out Wait 1st Ctrl+C : SIGINT ^CSignal Handler Signal Number: 2 Received Signal: Interrupt After 1st Signal Handler 두번째 Ctrl+C도처리 Wait 2nd Ctrl+C : SIGINT ^CSignal Handler Signal Number: 2 Received Signal: Interrupt After 2nd Signal Handler 시그널핸들러함수 [2] 시그널핸들러지정 : sigset(3) void (*sigset(int sig, void (*disp)(int)))(int); disp : sig 로지정한시그널을받았을때처리할방법 시그널핸들러함수명 SIG_IGN : 시그널을무시하도록지정 SIG_DFL : 기본처리방법으로처리하도록지정 sigset 함수는 signal 함수와달리시그널핸들러가한번호출된후에기본동작으로재설정하지않고, 시그널핸들러를자동으로재정한다. 11/38 /38
[ 예제 7-4] sigset 함수사용하기 ex7_4.c 시그널집합 08 printf("signal Handler Signal Number : %d\n", signo); 09 psignal(signo, "Received Signal"); 10 } 11 int main(void) { 13 if (sigset(sigint, handler) == SIG_ERR) { 14 perror("sigset"); 15 exit(1); 16 } 17 18 printf("wait 1st Ctrl+C : SIGINT\n"); 19 pause(); 시그널핸들러를재지정하지않아도됨 20 printf("after 1st Signal Handler\n"); 21 printf("wait 2nd Ctrl+C : SIGINT\n"); # ex7_4.out 22 pause(); 23 printf("after 2nd Signal Handler\n"); 24 25 return 0; 26 } Wait 1st Ctrl+C : SIGINT ^CSignal Handler Signal Number: 2 Received Signal: Interrupt After 1st Signal Handler Wait 2nd Ctrl+C : SIGINT ^CSignal Handler Signal Number: 2 Received Signal: Interrupt After 2nd Signal Handler 시그널집합의개념 시그널을개별적으로처리하지않고복수의시그널을처리하기위해도입한개념 POSIX 에서도입 시그널집합의처리를위한구조체 sigset_t typedef struct { unsigned int sigbits[4]; } sigset_t; 시그널을비트마스트로표현. 각비트가특정시그널과 1:1 로연결 비트값이 1 이면해당시그널이설정된것이고, 0 이면시그널설정안된것임 13/38 14/38 시그널집합처리함수 [1] 시그널집합비우기 : sigemptyset(3) int sigemptyset(sigset_t *set); 시그널집합에서모든시그널을 0으로설정 시그널집합에모든시그널설정 : sigfillset(3) int sigfillset(sigset_t *set); 시그널집합에서모든시그널을 1로설정 시그널집합처리함수 [2] 시그널집합에서시그널설정삭제 : sigdelset(3) int sigdelset(sigset_t *set, int signo); signo로지정한시그널을시그널집합에서삭제 시그널집합에설정된시그널확인 : sigismember(3) int sigismember(sigset_t *set, int signo); signo로지정한시그널이시그널집합에포함되어있는지확인 시그널집합에시그널설정추가 : sigaddset(3) int sigaddset(sigset_t *set, int signo); signo 로지정한시그널을시그널집합에추가 15/38 16/38
[ 예제 7-5] 시그널집합처리함수사용하기 ex7_5.c 01 02 #include <stdio.h> 03 04 int main(void) { 05 sigset_t st; 06 07 sigemptyset(&st); 시그널집합비우기 08 09 sigaddset(&st, SIGINT); 시그널추가 10 sigaddset(&st, SIGQUIT); 11 if (sigismember(&st, SIGINT)) 시그널설정확인 13 printf("sigint is setting.\n"); 14 15 printf("** Bit Pattern: %x\n",st. sigbits[0]); 16 17 return 0; 18 } 6 은 2 진수로 00000110 이므로오른쪽에서 2 번, 3 번비트가 1 로설정 SIGINT 는 2 번, SIGQUIT 는 3 번시그널 # ex7_5.out SIGINT is setting. ** Bit Pattern: 6 sigaction 함수의활용 [1] sigaction 함수 signal 이나 sigset 함수처럼시그널을받았을때이를처리하는함수지정 signal, sigset 함수보다다양하게시그널제어가능 sigaction 구조체 struct sigaction { int sa_flags; union { void (*sa_handler)(); void (*sa_sigaction)(int, siginfo_t *, void *); } _funcptr; sigset_t sa_mask; }; sa_flags : 시그널전달방법을수정할플래그 ( 다음쪽참조 ) sa_handler/sa_sigaction : 시그널처리를위한동작지정 sa_flags 에 SA_SIGINFO 가설정되어있지않으면 sa_handler 에시그널처리동작지정 sa_flags 에 SA_SIGINFO 가설정되어있으면 sa_sigaction 멤버사용 sa_mask : 시그널핸들러가수행되는동안블록될시그널을지정한시그널집합 17/38 18/38 sigaction 함수의활용 [2] sa_flags 에지정할수있는값 (sys/signal.h) sigaction 함수의활용 [3] sigaction 함수 int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact); sig : 처리할시그널 act : 시그널을처리할방법을지정한구조체주소 oact : 기존에시그널을처리하던방법을저장할구조체주소 첫번째인자로 SIGKILL 과 SIGSTOP 을제외한어떤시그널도올수있음 19/38 20/38
[ 예제 7-6] sigaction 함수사용하기 (1) ex7_6.c [ 예제 7-7] sigaction 함수사용하기 (SA_RESETHAND) ex7_7_arg.c 08 psignal(signo, "Received Signal:"); 09 sleep(5); 10 printf("in Signal Handler, After Sleep\n"); 11 } 13 int main(void) { 14 struct sigaction act; 15 sa_mask 초기화 16 sigemptyset(&act.sa_mask); 17 sigaddset(&act.sa_mask, SIGQUIT); SIGQUIT 시그널을블록시키기위해추가 18 act.sa_flags = 0; 19 act.sa_handler = handler; 시그널핸들러지정 20 if (sigaction(sigint, &act, (struct sigaction *)NULL) < 0) { 21 perror("sigaction"); 22 exit(1); 23 } 24 25 fprintf(stderr, "Input SIGINT: "); 26 pause(); 시그널받기위해대기 (pause함수) 27 fprintf(stderr, "After Signal Handler\n"); 28 29 return 0; 30 } # ex7_6.out Input SIGINT: ^CReceived Signal:: Interrupt ^\In Signal Handler, After Sleep 끝 (Quit)( 코어덤프 ) 21/38 08 psignal(signo, "Received Signal:"); 09 sleep(5); 10 printf("in Signal Handler, After Sleep\n"); 11 } 13 int main(void) { 14 struct sigaction act; 15 16 sigemptyset(&act.sa_mask); 17 sigaddset(&act.sa_mask, SIGQUIT); 18 act.sa_flags = SA_RESETHAND; 19 act.sa_handler = handler; SA_RESETHAND 지정 20 if (sigaction(sigint, &act, (struct sigaction *)NULL) < 0) { 21 perror("sigaction"); 22 exit(1); 23 } 24 25 fprintf(stderr, "Input SIGINT: "); 26 pause(); 27 fprintf(stderr, "After Signal Handler\n"); 28 29 return 0; 30 } 시그널핸들러가한번호출된후에시그널처리방법이기본처리방법으로재설정 # ex7_7.out Input SIGINT: ^CReceived Signal:: Interrupt ^CIn Signal Handler, After Sleep # 22/38 sigaction 함수의활용 [4] sa_flags 에 SA_SIGINFO 플래그를지정하면시그널발생원인을알수있다. 시그널핸들러의형식 sigaction 함수의활용 [5] 시그널발생원인코드 void handler (int sig, siginfo_t *sip, ucontext_t *ucp); sip : 시그널이발생한원인을담은 siginfo_t 구조체포인터 ucp : 시그널을받는프로세스의내부상태를나타내는구조체포인터 siginfo_t 구조체 typedef struct { int si_signo; int si_errno; int si_code; union sigval si_value; union { } data; } siginfo_t; si_signo : 시그널번호 si_errno : 0 또는오류번호 si_code : 시그널발생원인코드 data : 시그널의종류에따라값저장 시그널발생원인출력 : psiginfo(3) #include <siginfo.h> void psiginfo(siginfo_t *pinfo, char *s); pinfo : 시그널발생원인정보를저장한구조체, s: 출력할문자열 23/38 24/38
[ 예제 7-8] 시그널발생원인검색하기 ex7_8.c 알람시그널 08 void handler(int signo, siginfo_t *sf, ucontext_t *uc) { 09 psiginfo(sf, "Received Signal:"); 10 printf("si_code : %d\n ±, sf >si_code); 11 } 13 int main(void) { 14 struct sigaction act; 15 16 act.sa_flags = SA_SIGINFO; 17 act.sa_sigaction = (void (*)(int, siginfo_t *, void *))handler; 18 sigemptyset(&act.sa_mask); 19 if (sigaction(sigusr1, &act, (struct sigaction *)NULL) < 0) { 20 perror("sigaction"); 21 exit(1); 22 } 23 24 pause(); 25 26 return 0; 27 } SA_SIGINFO 플래그설정 sigaction 함수설정 오류메시지출력 # ex7_8.out& [1] 2515 SIGUSR1 시그널보내기 # kill USR1 2515 # Received Signal: : User Signal 1 ( from process 1579 ) si_code : 0 알람시그널 일정한시간이지난후에자동으로시그널이발생하도록하는시그널 일정시간후에한번발생시키거나, 일정간격을두고주기적으로발송가능 알람시그널생성 : alarm(2) #include <unistd.h> unsigned int alarm(unsigned int sec); sec : 알람이발생시킬때까지남은시간 ( 초단위 ) 일정시간이지나면 SIGALRM 시그널발생 프로세스별로알람시계가하나밖에없으므로알람은하나만설정가능 25/38 26/38 [ 예제 7-9] alarm 함수사용하기 01 #include <unistd.h> 02 03 #include <siginfo.h> 04 #include <stdio.h> 05 06 void handler(int signo) { 07 psignal(signo, "Received Signal"); 08 } 09 10 int main(void) { 11 sigset(sigalrm, handler); 13 alarm(2); 14 printf("wait\n"); 15 sleep(3); 16 17 return 0; 2 초설정 18 } # ex7_9.out Wait Received Signal: Alarm Clock ex7_9.c 인터벌타이머 타이머의종류 ITIMER_REAL : 실제시간사용. SIGALRM 시그널발생 ITIMER_VIRTUAL : 프로세스의가상시간사용. SIGVTALRM 시그널발생 ITIMER_PROF : 시스템이프로세스를위해실행중인시간과프로세스의가상시간을모두사용. SIGPROF 시그널발생 ITIMER_REALPROF : 실제시간사용. 멀티스레드프로그램의실제실행시간측정시사용. SIGPROF 시그널발생 타이머정보검색 : getitimer(2) #include <sys/time.h> int getitimer(int which, struct itimerval *value); 타이머설정 : setitimer(2) #include <sys/time.h> int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue); 27/38 28/38
인터벌타이머 [ 예제 7-10] 인터벌타이머설정하기 ex7_10.c which : 타이머종류 value : 타이머정보구조체포인터 struct itimerval { struct timeval it_interval; struct timeval it_value; }; struct timeval { time_t tv_sec; suseconds_t tv_usec; }; 29/38 11 int main(void) { struct itimerval it; 13 14 sigset(sigalrm, handler); 타이머간격 : 2초 15 it.it_value.tv_sec = 3; 타이머에현재남은시간 : 3초 16 it.it_value.tv_usec = 0; 17 it.it_interval.tv_sec = 2; 3초후에최초시그널발생 18 it.it_interval.tv_usec = 0; 이후 2초간격으로시그널발생 19 20 if (setitimer(itimer_real, &it, (struct itimerval *)NULL) == 1) { 21 perror("setitimer"); 22 exit(1); 23 } 24 # ex7_10.out 25 while (1) { 2 sec, 999997 msec. 26 if (getitimer(itimer_real, &it) == 1) { 1 sec, 999998 msec. 27 perror("getitimer"); 0 sec, 992047 msec. 28 exit(1); Timer Invoked.. 29 } 1 sec, 991565 msec. 30 printf("%d sec, %d msec.\n", (int)it.it_value.tv_sec, 0 sec, 982071 msec. 31 (int)it.it_value.tv_usec); Timer Invoked.. 32 sleep(1); 1 sec, 991433 msec. 33 } 남은시간정보출력 0 sec, 981829 msec. 34 Timer Invoked.. 35 return 0; 1 sec, 9918 msec. 36 } 30/38 기타시그널처리함수 [1] 기타시그널처리함수 [2] 시그널정보출력 : psignal(3) 시그널블록킹과해제 #include <siginfo.h> void psignal(int sig, const char *s); s에지정한문자열을붙여정보출력 시그널정보출력 : strsignal(3) #include <string.h> char *strsignal(int sig); 인자로받은시그널을가리키는이름을문자열로리턴 int sighold(int sig); int sigrelse(int sig); 인자로받은시그널을시그널마스크에추가하거나해제 시그널집합블록과해제 : sigprocmask(2) int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset); how : 시그널을블록할것인지, 해제할것인지여부 SIG_BLOCK : set 에지정한시그널집합을시그널마스크에추가 SIG_UNBLOCK : set 에지정한시그널집합을시그널마스크에서제거 SIG_SETMASK : set 에지정한시그널집합으로현재시그널마스크대체 set : 블록하거나해제할시그널집합주소 oset : NULL 또는이전설정값을저장한시그널집합주소 31/38 32/38
[ 예제 7-11] 시그널블록함수사용하기 08 char *s; 09 시그널이름리턴 10 s = strsignal(signo); 11 printf("received Signal : %s\n", s); } 13 14 int main(void) { 15 if (sigset(sigint, handler) == SIG_ERR) { 16 perror("sigset"); 17 exit(1); 18 } 19 20 sighold(sigint); 21 22 pause(); 23 24 return 0; 25 } SIGINT 블록설정 시그널핸들러설정 SIGINT 시그널을안받는다 # ex7_11.out ^C^C^C^C^C ex7_11.c 33/38 [ 예제 7-] sigprocmask 함수사용하기 ex7_.c 05 int main(void) { 06 sigset_t new; 07 08 sigemptyset(&new); 09 sigaddset(&new, SIGINT); 10 sigaddset(&new, SIGQUIT); 11 sigprocmask(sig_block, &new, (sigset_t *)NULL); 13 printf("blocking Signals : SIGINT, SIGQUIT\n"); 14 printf("send SIGQUIT\n"); 15 kill(getpid(), SIGQUIT); SIGQUIT 시그널보내기 16 17 printf("unblocking Signals\n"); 18 sigprocmask(sig_unblock, &new, (sigset_t *)NULL); 19 20 return 0; 21 } 블록해제후시그널을받아종료 시그널집합에 SIGINT, SIGQUIT 설정 시그널집합블록해제 시그널집합블록설정 # ex7_.out Blocking Signals : SIGINT, SIGQUIT Send SIGQUIT UnBlocking Signals 끝 (Quit)( 코어덤프 ) 34/38 기타시그널처리함수 [3] [ 예제 7-13] sigsuspend 함수사용하기 ex7_13.c 시그널대기 : sigpause(3) int sigpause(int sig); sig : 시그널이올때까지대기할시그널 시그널기다리기 : sigsuspend(2) int sigsuspend(const sigset_t *set); set : 기다리려는시그널을지정한시그널집합 06 void handler(int signo) { 07 psignal(signo, "Received Signal:"); 08 } 09 10 int main(void) { 11 sigset_t set; 13 sigset(sigalrm, handler); 14 15 sigfillset(&set); 16 sigdelset(&set, SIGALRM); 17 18 alarm(3); 19 20 printf("wait\n"); 21 22 sigsuspend(&set); 23 24 return 0; 25 } 알람시그널설정 시그널기다리기 기다릴시그널설정 # ex7_13.out Wait ^C^CReceived Signal:: Alarm Clock 35/38 36/38
기타시그널처리함수 [4] 시그널보내기 : sigsend(2) int sigsend(idtype_t idtype, id_t id, int sig); idtype : id 에지정한값의종류 id : 시그널을받을프로세스나프로세스그룹 sig : 보내려는시그널 기타시그널처리함수 [5] 시그널무시처리 : sigignore(3) int sigignore(int sig); sig : 무시할시그널번호 인자로지정한시그널의처리방법을 SIG_IGN으로설정 37/38 38/38 IT CookBook, 유닉스시스템프로그래밍