Signal이란?
- software interrupt로 이해하면 된다.
- 본래 목적은 실행 프로세스를 중단시키는 것이 목표이며, 자료 전송보다는 비정상적인 상황을 알릴 때 사용한다.
(예) 프로그램 수행 중 “CTRL+C”를 누르면, 커널이 문자를 감지한 후 해당 세션에 있는 모든 프로세스에게 SIGINT라는 시그널을 보낸다. 모든 프로세스는 시그널을 받으면 종료한다. 단, shell process는 이를 무시한다.
- 시그널 종류 (자주 등장하는 것 위주로 정리)
2 | SIGINT | interrupt key(CTRL+C) 입력했을 때 |
9 | SIGKILL | 프로세스를 kill하기 위한 시그널 (catch or ingnore 될 수 없는 시그널) |
10 | SIGUSR1 | user defined signal1 |
12 | SIGUSR2 | user defined signal2 |
14 | SIGALRM | alarm 시스템 콜 후, timer가 expire된 경우 |
- 출처 : https://jangpd007.tistory.com/90
- 시그널의 기본처리
- 종료(시그널에 의한 종료)
- 코어덤프 후 종료(시그널에 의한 비정상 종료) : core file
- 중지
- 무시
- 시그널의 종료 상태 확인하기
pid = wait(&status);
// 정상종료인지 확인
if(WIFEXITED(status))
printf("정상적으로 종료");
// 시그널을 받고 종료
if(WIFSIGNALED(status))
printf("시그널%d에 의한 종료",WTERMSIG(status)); // WTERMSIG를 통해 시그널 번호 확인
Signal 사용하기
- 사용 헤더파일
#include <sys/types.h>
#include <signal.h>
< kill 시스템콜 >
int kill(pid_t pid, int sig);
- pid : signal을 받게 될 프로세스 지정
- sig : 보낼 시그널 저장
*** 단, pid를 사용하여 시그널을 받을 프로세스를 여러 방면으로 지정할 수 있음 ***
#1. pid > 0 : 해당 id의 프로세스에게 시그널 전달
#2. pid = 0 : sender와 같은 프로세스 그룹에 속하는 모든 프로세스(sender 포함)에게 시그널 전달 → 내가 속한 그룹
#3. pid = -1 : uid가 sender의 euid와 같은 모든 프로세스(sender 포함)에게 시그널 전달
#4. pid < 0 and pid ≠ -1 : 프로세스의 그룹 아이디가 pid의 절댓값과 같은 모든 프로세스에게 시그널 전달 → 내가 원하는 그룹 지정
다른 사용자의 프로세스에게 시그널을 보내면 -1 return
< raise 시스템콜 >
int raise(int sig);
- 호출 프로세스에게 시그널을 보냄
< Signal Handling - sigaction 시스템콜 >
- Signal Handling :
- 기본 동작 수행(default action) : 각 시그널을 기본 동작이 지정되어 있음
- 지정된 함수 수행(정의된 action) : 특정 함수 만들어서 실행
- 시그널 무시
- sigaction
→ sigaction 지정 : signal을 받았을 때의 취할 행동을 지정할 수 있다
(단, SIGSTOP, SIGKILL은 별도의 action을 지정할 수 없음)
// sigaction 방법
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
// sigaction 구조체
struct sigaction{
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
void (*sa_sigaction)(int, siginfo_t *, void *)
}
- void(*sa_handler)(int);
-signo를 수신하면 취할 행동을 지정
-행동 리스트
- SIG_DFL : default 행동 = 종료
- SIG_IGN : 무시
- 정의된 함수 : signal을 받으면 함수(사용자가 설정)로 제어 이동. 함수 실행 후, 시그널을 받기 직전의 처리 문장으로 return.
- sigset_t sa_mask;
-여기 정의된 시그널들은 sa_handler에 의해 지정된 함수가 수행되는 동안 blocking된다.
-당장 처리하지 않고 현재 처리 중인 것 끝내고 처리하겠다. 우선순위가 높은 시그널 우선 처리할 수 있도록 하게 함.
- int sa_flags
- SA_RESETHAND : handler로부터 복귀 시 signal action을 SIG_DFL로 재설정
- SA_SIGINFO : sa_handler 대신 sig_action 사용
(예제1) sigaction 사용
- 시그널 받았을 때 정의된 함수 실행시키는 법
#include <signal.h>
int main(int argc, char **argv) {
static struct sigaction act;
void catchint(int);
act.sa_handler = catchint; // 시그널을 받으면 사용자가 정의한 함수인 catchint로 액션 수행
sigaction(SIGINT, &act, NULL);
printf("sleep call\\\\n");
sleep(1);
printf("exiting\\\\n");
exit(0);
}
void catchint(int signo) {
printf("CATCHINT : %d\\\\n", signo);
psignal(signo, "[Received Signal]");
}
(예제2) 시그널 받으면 무시/종료 설정
// 1. 무시
act.sa_handler = SIG_IGN;
sigaction(SIGINT, &act, NULL); // 이 경우에는 컨트롤씨를 눌러도 어떠한 액션을 취하지 않음
// 2. 종료
act.sa_handler = SIG_DFL;
sigaction(SIGINT, &act, NULL);
- 여러 개의 시그널 무시
→ 한 프로세스에서 무시되는 시그널은 exec() 후에도 계속 무시됨.
왜?) exec로 실행하면 프로세스가 동일하기 때문에 시그널을 계속 무시하게 된다.
< 시그널 집합 지정하기 >
- sigemptyset → sigaddset : 전부 0으로 설정한 후 block할 시그널 설정
- sigfillset → sigdelset : 전부 1로 설정한 후 block하지 않을 시그널 설정
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_ *set, int signo);
int sigdelset(sigset_ *set, int signo);
sigset_t mask1, mask2;
sigemptyset(&mask1);
sigaddset(&mask1, SIGINT);
sigaddset(&mask1, SIGQUIT);
sigfillset(&mask2);
sigdelset(&mask2, SIGCHLD);
< 과거 설정 복원하기 >
sigaction(SIGTERM, NULL, &oact); // 과거 설정 저장
act.sa_handler = SIG_IGN;
sigaction(SIGTERM, &act, NULL);
// do anything!
sigaction(SIGTERM ,&oact, NULL)
Signal 사용하기 (2)
< 시그널 알람 설정 >
unsigned int alarm(unsigned int secs);
- secs : 초 단위의 시간 → 시간 종료 후 SIGALRM을 보냄
- alarm은 exec 후에도 계속 작동함 but! fork 후에는 자식 프로세스에ㅔ 대한 alarm은 작동하지 않음
- alarm(0) → alarm 끄기
- alarm은 누적되지 않는다 == 2번 사용되면 2번째 alarm으로 대체되는 것
- 2번째 알람의 return 값 : 첫 alarm의 잔여시간
< 시그널 blocking >
int sigprocmask(int how, const sigset_t *set, ingset_t *oset);
-oset은 봉쇄된 시그널들의 현재 mask → 관심 없으면 NULL로 설정
-시그널 집합을 사용해서 한 번에 여러 시그널을 블록할 수 있음
- how : 시그널을 블록할지 해제할지의 여부
- set : 블록하거나 해제할 시그널 집합의 주소
*** 시그널 블록 ***
- SIG_BLOCK
- SIG_UNBLOCK
- SIG_SETMASK
< pause 시스템 콜 >
int pause(void);
- signal 도착까지 실행을 일시 중단
- signal이 포착되면 처리 루틴 수행 or -1 return
'programming > Unix' 카테고리의 다른 글
[Unix Programming] 10. 파이프 (0) | 2025.01.16 |
---|---|
[Unix Programming] 9. 메모리 매핑 (0) | 2024.12.12 |
[Unix Programming] 7. 프로세스 생성과 실행 (0) | 2024.12.11 |
[Unix Programming] 6. 프로세스 정보 (0) | 2024.12.11 |
[Unix Programming] 5. 시스템 정보 (0) | 2024.12.11 |