익명 사용자
로그인하지 않음
계정 만들기
로그인
youngwiki
검색
Signal 문서 원본 보기
youngwiki
이름공간
문서
토론
더 보기
더 보기
문서 행위
읽기
원본 보기
역사
←
Signal
문서 편집 권한이 없습니다. 다음 이유를 확인해주세요:
요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다:
사용자
.
문서의 원본을 보거나 복사할 수 있습니다.
상위 문서: [[Signals and Nonlocal jumps]] ==개요== signal이란 시스템에서 어떤 종류의 이벤트가 발생했음을 프로세스에 알리는 작은 메시지이다. signal은 이를 위해서 kernel에서 process로 보내지며, signal type은 1~30의 정수로 식별된다. 이때 어떤 signal에 저장된 정보는 해당 ID와 그 signal이 도착했다는 사실 뿐이다. 아래는 몇가지 signal ID와 그에 대응되는 signal들을 나타낸 표이다. {| class="wikitable" |+ !ID !Name !Default Action !Corresponding Event |- |2 |SIGINT |Terminate |User typed ctrl-c |- |9 |SIGKILL |Terminate |Kill program(cannot override or ignore) |- |11 |SIGSEGV |Terminate |Segmentation violation |- |14 |SIGALRM |Terminate |Timer Signal |- |17 |SIGCHLD |Ignore |Child stopped or terminated |} ==Signal Concepts== [[파일:SignalHandling.png|섬네일|400x400픽셀|signal handler가 signal을 캐치하는 기본적인 흐름]] 시그널이 대상 프로세스로 전달되는 과정은 다음 두 가지의 명확한 단계로 이루어진다. # Sending a signal #* 커널은 destination 프로세스의 context 일부 상태를 업데이트해 해당 프로세스에 시그널을 보낸다. 다음은 signal이 전달되는 경우이다. #*# 커널이 0으로 나누기 오류나 자식 프로세스의 종료와 같은 시스템 이벤트를 감지했을 때 #*# 한 프로세스가 kill 함수를 호출하여 명시적으로 커널에게 대상 프로세스에 signal을 보내도록 요청했을 때 #* 프로세스는 자기 자신에게 시그널을 보낼 수도 있다. # Receiving a signal #* destination 프로세스는 커널이 해당 시그널의 전달에 반응하도록 강제할 때 시그널을 받는다. 프로세스는 시그널에 대해 다음 세 가지 중 하나의 반응을 할 수 있다: #*#signal을 무시(Ignore) #*# 프로세스를 종료(Terminate) #*# 사용자 수준 함수인 signal handler을 실행하여 시그널을 catch하여 처리 #Pending and Blocked Signal #* Pending signal은 전송되었지만 수신이 완료되지 않은 signal을 의미한다. #** 특정한 유형의 pending signal은 최대 하나만 존재할 수 있다. 만약 프로세스가 특정 유형(k)의 pending signal을 가지고 있다면, 그 프로세스에 대해 이후에 보내지는 동일한 유형(k)의 signal는 대기열에 쌓이지 않고 단순히 버려진다. #* 프로세스는 특정한 유형의 signal 수신을 block할 수 있다. #** 이때 signal이 전달될 수는 있으나, 해당 signal은 pending signal이 되어 프로세스가 해당 유형의 signal을 unblock하기 전까지는 수신되지 않는다. #* 커널은 각 프로세스의 context에서 pending signal과 blocked signal에 대한 bit vector를 가지고 있다. #** pending: pending signal들의 집합을 나타내는 bit vector이다. #*** 커널은 유형이 k인 signal이 전달되면 pending vector에 k bit를 설정한다. #*** 커널은 유형이 k인 signal이 수신되면 pending vector에서 k bit를 지운다. #** blocked: block된 signal들의 집합을 나타내는 bit vector이다. #*** signal mask라고도 불린다. #*** sigprocmask 함수를 통해서 특정 유형의 signal을 block하거나 unblock할 수 있다. ==Sending Signal== ===Process Group=== [[파일:ProcessGroup.png|섬네일|400x400픽셀|Process group example]] 모든 프로세스는 단 하나의 process group(프로세스 그룹)에 속한다. 이 그룹은 양의 정수인 process group ID로 식별된다. 현재 프로세스의 process group ID를 알기 위해서는 이를 반환하는 getpgrp()함수를 사용할 수 있다. <syntaxhighlight lang="c"> #include <unistd.h> pid_t getpgrp(void); </syntaxhighlight> 기본적으로 child process는 parent process와 동일한 프로세스 그룹에 속한다. 이때 프로세스는 setpgid() 함수를 사용하여 자신이나 다른 프로세스의 프로세스 그룹을 변경할 수 있다. <syntaxhighlight lang="c"> #include <unistd.h> int setpgid(pid_t pid, pid_t pgid); </syntaxhighlight> setpgid 함수는 프로세스 pid의 프로세스 그룹의 ID를 pgid로 변경한다. 만약 pid가 0이면, 현재 프로세스의 PID가 사용된다. pgid가 0이면, pid로 지정된 프로세스의 PID가 프로세스 그룹 ID로 사용됩니다. 다음은 PID가 15213인 프로세스에서 setpgid()함수를 호출한 예시이다. <syntaxhighlight lang="c"> setpgid(0, 0); </syntaxhighlight> 위 함수의 실행은 process group ID가 15213인 프로세스 그룹이 이미 존재한다면 PID가 15213인 프로세스를 해당 그룹에 추가한다. 만약 process group ID가 15213인 프로세스 그룹이 존재하지 않는다면 그러한 프로세스 그룹을 만들고 ID가 15213인 프로세스를 해당 그룹에 추가한다. ===/Bin/kill 프로그램을 사용해 signal 보내기=== /bin/kill 프로그램은 다른 프로세스나 프로세스 그룹에 임의의 신호를 보낸다. 예를 들어, <syntaxhighlight lang="perl"> linux> /bin/kill -9 15213 </syntaxhighlight> 위 명령은 process 15213에 signal -9(SIGKILL)을 보낸다. 이때 PID로 음수를 사용하면 해당 process group 15213에 존재하는 모든 프로세스에 해당 signal을 보낸다. 예를 들어, <syntaxhighlight lang="perl"> linux> /bin/kill -9 -15213 </syntaxhighlight> 위 명령은 process group 15213에 있는 모든 프로세스에 SIGKILL 신호를 보낸다. ===키보드로 signal 보내기=== [[파일:ProcessGroup.png|Process group example|섬네일|300x300픽셀]]Unix shell은 하나의 명령어를 evaluate해 생성된 process를 job이라는 abstraction으로 나타낸다. 이때 어떠한 시점에서든 하나의 foreground job과 여러 background job이 존재할 수 있다. 예를 들어, <syntaxhighlight lang="shell"> linux> ls | sort </syntaxhighlight> 이 명령은 Unix pipe<ref>두 개의 명령어를 연결하여, 첫 번째 명령어의 출력 결과를 두 번째 명령어의 입력으로 전달하는 메커니즘이다.</ref>를 통해 연결된 두 개의 process로 구성된 foreground job<ref>알파벳 순으로 정렬된 파일 목록을 얻는 job이다.</ref>을 만든다. 두 프로세스 중 하나는 ls 프로그램<ref>현재 디렉토리의 파일과 디렉토리 목록을 출력하는 명령어이다.</ref>을 실행하고, 다른 하나는 sort 프로그램<ref>sort는 정렬을 의미하는 명령어로, 텍스트 데이터를 정렬하는 데 사용한다.</ref>을 실행한다. Shell은 각 job마다 별도의 프로세스 그룹을 생성하며, 이때의 process group ID는 job 내의 parent PID 중 하나에서 따온다. 예를 들어 오른쪽의 그림은 하나의 foreground job과 두개의 background job을 가진 shell을 보여준다. 전경 잡의 부모 프로세스는 PID가 20이고, process group ID도 20이다. 부모 프로세스는 두 개의 자식 프로세스를 생성했으며, 이들 또한 프로세스 그룹 20에 속한다. 키보드에서 Ctrl+C를 누르면 커널은 foreground group에 있는 모든 프로세스에 SIGINT<ref> * SIGINT: 프로세스가 종료를 거부하거나 신호를 처리할 수 있는 기회를 제공한다. 기본적으로 사용자가 인터럽트 키인 Ctrl+C를 눌렀을 때 발생한다. * SIGKILL: 프로세스를 즉시 강제 종료시키는 신호이다. 프로세스가 이를 거부하거나 처리할 수 없으며 무조건 종료된다. </ref> 신호를 보낸다. 즉, foreground job을 종료(terminate)한다. 마찬가지로 Ctrl+Z를 누르면 커널은 foreground 프로세스 그룹에 있는 모든 프로세스에 SIGTSTP 신호를 보낸다. 즉, foreground job을 suspend한다. ====키보드로 signal 보내기 예시==== 아래는 Ctrl+C와 Ctrl+Z의 예시이다. <syntaxhighlight lang="shell"> bluefish> ./forks 17 Child: pid=28108 pgrp=28107 Parent: pid=28107 pgrp=28107 <types ctrl-z> Suspended bluefish> ps w PID TTY STAT TIME COMMAND 27699 pts/8 Ss 0:00 -tcsh 28107 pts/8 T 0:01 ./forks 17 28108 pts/8 T 0:01 ./forks 17 28109 pts/8 R+ 0:00 ps w bluefish> fg ./forks 17 <types ctrl-c> bluefish> ps w PID TTY STAT TIME COMMAND 27699 pts/8 Ss 0:00 -tcsh 28110 pts/8 R+ 0:00 ps w </syntaxhighlight> 위에서 STAT은 다음과 같이 표현된다. * First letter: ** S: sleeping ** T: stopped **R: running * Second letter: ** s: session<ref>사용자와 그 사용자에 의해 시작된 여러 프로세스를 관리하는 논리적인 단위이다.</ref> leader<ref>session을 생성하는 첫번째 프로세스이며, 해당 session 내 다른 프로세스들을 관리하는 역할을 한다.</ref> ** +: foreground proc group ===kill 함수를 통해 signal 보내기=== 프로세스는 kill 함수를 호출하여 프로세스(자기 자신을 포함)에게 signal을 보낼 수 있다. <syntaxhighlight lang="c"> #include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig); </syntaxhighlight> * pid > 0: kill 함수는 signal number가 sig인 signal을 process pid에 보낸다. * pid = 0: kill 함수는 호출 프로세스가 속한 프로세스 그룹에 있는 모든 프로세스(호출 프로세스 자신 포함)에게 signal number가 sig인 signal을 보낸다. * pid < 0: kill 함수는 process group |pid|(pid의 절대값)에 속한 모든 프로세스에게 signal number가 sig인 signal을 보낸다. <syntaxhighlight lang="c"> void fork12() { pid_t pid[N]; //자식 프로세스의 PID를 저장하는 배열 int i; int child_status; //자식 프로세스 생성 for (i = 0; i < N; i++) { if ((pid[i] = fork()) == 0) { while(1); //자식 프로세스는 무한 루프를 유지한다. } } for (i = 0; i < N; i++) { printf("Killing process %d\n", pid[i]); kill(pid[i], SIGINT); //자식 프로세스에 대한 종료 요청 } for (i = 0; i < N; i++) { pid_t wpid = wait(&child_status); //자식 프로세스의 종료상태를 확인한다. if (WIFEXITED(child_status)) //WIFEXITED(child_status)를 통해 정상적으로 종료되었는지 확인 //정상적으로 종료되었다면 자식 프로세스의 exit status를 출력한다. printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status)); else printf("Child %d terminated abnormally\n", wpid); } } </syntaxhighlight>[[파일:KillExample.png|테두리|프레임없음|300x300픽셀]] 위는 N을 5로 설정하였을 때<ref>#define N = 5</ref>의 예시 결과이다. 이때 child process가 왜 abnormally하게???? ==Receiving Signals= 커널이 프로세스 p를 kernel mode에서 user mode로 전환할 때<ref>system call에서 돌아오거나 context switch를 완료할 때 등</ref>, 커널은 p에 대해 unblocked이고 pending 상태인 sognal의 집합(pending & ~blocked)을 확인한다. 이 집합이 비어 있으면(일반적인 경우), 커널은 p의 logical control flow에서 다음 instruction(I<sub>next</sub>)로 control을 넘긴다. 그러나 이 집합이 비어 있지 않으면, 커널은 집합에서 signal k를 하나 선택하고<ref>일반적으로 가장 작은 signal number k</ref>, p가 signal k를 수신하도록한다. signal을 수신하면 해당 프로세스는 특정 작업을 수행한다. 작업을 완료한 후, p의 logical control flow에서 다음 instruction(I<sub>next</sub>)로 control을 넘긴다. 각 signal 유형은 기본 동작이 있으며, 다음은 기본 동작을 모두 나열한 것이다. * 프로세스를 terminate / ex: SIGKILL * 프로세스를 terminate, core를 dump<ref></ref> * 프로세스를 SIGCONT signal에 의해 재개될 때까지 suspend(stop) * 프로세스를 signal을 무시하도록 한다.<ref>프로세스가 해당 신호를 수신해도 아무 일도 일어나지 않게 처리된다.</ref> / ex: SIGCHLD<ref>SIGCHLD 신호는 자식 프로세스의 종료나 상태 변경을 알리는 신호이며, 기본적으로 무시된다. 즉, 부모 프로세스는 자식 프로세스가 종료되었을 때 특별히 처리할 필요가 없다면 이 신호를 무시할 수 있다.</ref> 프로세스가 신호를 무시합니다. ==각주== [[분류:컴퓨터 네트워크]]
Signal
문서로 돌아갑니다.
둘러보기
둘러보기
대문
최근 바뀜
임의의 문서로
미디어위키 도움말
위키 도구
위키 도구
특수 문서 목록
문서 도구
문서 도구
사용자 문서 도구
더 보기
여기를 가리키는 문서
가리키는 글의 최근 바뀜
문서 정보
문서 기록