Signal
✅ 개요
- 프로세스 또는 시스템에게 이벤트 발생을 전달하는 신호를 말함.
- 많은 부분이 비동기이지만 일부는 동기적임.
- 동기 : 이벤트가 있어야 발생, 비동기 : 예측불가
- 예) 사용자가 누르는것 (ctrl+c와 같이)
- divide zero는 인터럽트일수도 있고 시그널일수도 있음.
🤿 정리
시그널의 발생은 두가지로 나뉨. -> 비동기(예측불가), 동기(예측가능)
시그널의 처리는 오로지 비동기임.
😫 왜 쓸까?
- 특정 이벤트가 발생했음을 알려주는 알림메세지의 기능을 하기 위해 쓴다.
- 예를 들어 프로세스가 무한루프를 돌고 있는데 이걸 꺼야한다. → 그때 sigint를 보내서 강제 종료를 시켜버린다.
- 특정 프로세스를 강제종료 시키고 싶다 → 터미널에 sigkill -9 {프로세스 이름}을 명령어로 입력해 강제 종료 시켜버린다.
📍 Signal이 동적인 상황은?
- 프로세스가 프로세스에게 시그널을 보내거나 사용자가 시그널을 보내는 경우.
- 이벤트는 비동기적으로 발생할 수 있으며 시그널을 전달받은 프로그램은 시그널을
시그널 핸들러
를 통해 비동기적으로 처리할 수 있음.
✅ 중단된 프로세스의 상태는 누가, 어떻게 관리할까? - 커널이 관리함. 프로그램 카운터, 레지스터 값, 스택 포인터 값을 관리하고 있다가 나중에 시그널 발생으로 인해 중단된 지점에서 재개
📍 리눅스의 주요 시그널
이름 | 설명 |
---|---|
SIGALRM | alram()으로 설정한 타이머가 만료되었을때 발생. |
SIGBUS | 하드웨어 고장에 해당하는 시그널. |
SIGCHILD | 프로세스가 종료 또는 중단되면 부모에게 이 시그널 전달. 기본적으로 무시되기 때문에 자식의 상태가 변할 때 마다 그 사실을 알아야 한다면 부모는 반드시 이 시그널을 캐치해야함. |
SIGINT | 사용자가 DELETE 또는 Ctrl+C를 눌렀을때 터미널 드라이버가 이 시그널 발생. |
SIGKILL | 무시하거나 캐치 불가. sigkill -9 {프로세스 번호} 이면 강적조합. |
SIGSTOP | 무시하거나 캐치할 수 없는 두 시그널 중 하나로 프로세스 중단 |
SIGTSTP | 사용자가 터미널에서 Ctrl+Z(일시정지 키) 를 눌렀을때 터미널 드라이버가 이 시그널 발생 |
SIGUSR1, SIGUSR2 | 사용자 정의 시그널 |
📍 커널의 시그널 처리 방식
- 시그널 무시
- 어떤 액션도 취하지 않는다.
- 디폴트 액션 실행
- 사용자 지정 핸들러
- 대부분 프로세스 종료
- 시그널 캐치하여 실행
- 함수를 새로 만든다.
- 커널은 프로세스의 현재 코드의 실행을 중단하고 이전에 등록했던 시그널 처리함수로 넘어가서 그 코드를 실행.
- 시그널 처리함수가 리턴되면 시그널이 발생하기 전 위치로 돌아감
📍 Signal(2)
#include <signal.h>
sighandler_t signal(int signum , sighandler_t handler);
- signum 자리에는 시그널의 이름을 쓴다
- handler 인자에는 시그널 발생시 호출될 함수의 주소를 넣는다.
📍 task_struct
- 아래는 리눅스의 task_struct의 예시.
- 프로세스를 나타내는 자료구조이다.
- pending은 bit별로 시그널을 구분한다.
- handler는 시그널의 불려지면 디폴트로 호출된다.
- blocked는 masked와 같은 의미로 프로세스와 관련된 block은 전부 mask시킨다.
✅ PCB와 task_struct의 관계
- 운영체제를 배우면
PCB
라는 말을 익히 듣는다.- Process Control Block의 약자로, 프로세를 표현하기 위한 자료구조이며 커널안에 존재한다.
궁금하다면 직접 찾아가보도록 하자
- Process Control Block의 약자로, 프로세를 표현하기 위한 자료구조이며 커널안에 존재한다.
- 리눅스에서 PCB를 task_struct라는 친구가 대체하고 있는것이다
- task_struct안에 시그널 핸들러도 들어간다!
🧩 인터럽트와 시그널의 차이?
- 이쯤이면 궁금해질것이다. 인터럽트와 시그널의 차이가 무엇인지!
- 간단히 말하면 인터럽트는 바로 실행할 수 있지만, 시그널은 프로세스에게 보내는 것이기에 바로 실행되지 못한다!
- 후술하겠지만 시그널은 Signal은 pending이 될 수 있다. 딴일하느라 안볼 수도 있다.
인터럽트
- 인터럽트 크게 하드웨어 인터럽트와 소프트웨어 인터럽트로 나뉜다.
- 하드웨어 인터럽트
- 외부 디바이스에서 발생
- CPU가 현재 실행중인 작업 멈추고 → 인터럽트 핸들러 실행
- 소프트웨어 인터럽트
- 동기적 : 시스템콜
- 비동기적 : trap
- divide in zero
- page fault
시그널
- os나 프로세스가 특정 프로세스에게 보내는 비동기적 이벤트
- 프로세스가 실행중일 때만 처리
🤝Recap
인터럽트는 CPU와 커널 중심, 시그널은 실행중인 프로세스 중심
📍 kill(2)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
- pid에게 signal을 보낸다
- kill()은 프로세스 그룹에 시그널 보내는 시스템콜 함수
- % kill -9 1093 ⇒ 1093번 프로세스에게 SIGKILL을 보낸다
- % kill 1093 ⇒ 1093번 프로세스에게 SIGTERM을 보낸다 (무시,catch가능)
'Linux' 카테고리의 다른 글
[Linux] Linux의 Signal을 알아보자(2) (0) | 2025.01.17 |
---|