-> 유닉스 시스템이 혹은 프로세스가 다른 프로세스를 제어 할 수 있음. 제어를 하려 할 때 작은 메시지 형태로 이벤트가 발생했을 알리는 것이 시그널 임.
- 비동기적으로 발생, 즉 호출함: Ctrl + C(인터럽트 + 시그널(KILL))
- 자동으로 실행될 수도: 잘못된 인스트럭션, 메모리 참조시 발생
- PID: 프로세스 고유 할당 숫자.
- PGID: 프로세스 그룹 고유 할당 숫자.
setpgid함수를 통해 그룹을 변경할 수 있음. setpgid(pid, pgid)
(0,0)으로 호출한다면, 현재 실행중인 프로세스의 pid로 id가 설정된 pgid가 만들어짐.
- 시그널을 통해 pid로 명령을 보내면,
- pid가 양수일 경우: 해당 프로세스에게 명령을 보냄.
- pid가 음수일 경우: 해당 그룹에게 명령을 보냄.
시그널은 프로세스와 동일한 전역변수를 사용할 수도 있고, 이로인해 시스템 충돌이 발생할수도 있기에 시그널 블록이 사용됨.
1. 묵시적 블록 방법: 커널은 핸들러가 처리하고 있는 유형의 모든 대기 시그널들의 처리를 막음. 다른 시그널이 들어온다면, pending. 이후 핸들러가 리턴하면 수신이 된다.
2. 명시적 블록법: sigprocmask함수 & 도움함수를 사용해 특정시그널을 블록, 변경 가능. 예시) 736쪽 함수 3개.
앞서 서술했듯 핸들러와 프로세스는 동일한 전역데이터를 사용해 충돌할 수 있으니, 시그널을 안전히 처리하기 위해 몇가지 지침이 있음
- 핸들러는 간단하게 작성, 유지하라
- 핸들러에서 비동기성-시그널-안전한 함수만 사용해라.(핸들러 호출중에도 안전하게 실행가능한 함수. 핸들러 실행중에도 중단없이 작동. 그림 8.33)
write:ok, printf:nope- errno 사용. -> 에러를 핸들러와 공유하지 않도록.
- 모든 시그널을 블록시켜 공유된 데이터들을 보호. : 자료구조에 접근하는동안 일시적으로 시그널들을 블록시켜 데이터를 보호해야 함.
- volatile 선언 사용. 핸들러가 어떤 전역변수를 계속 변경하고, 프로세스는 그 전역변수를 계속 읽어와야 할 때(캐시에서), 두 변수는 동기화가 되어야 하므로, volatile을 사용해 메모리에서 직접 읽어올수 있도록 선언.
sig_atomic_t사용. sig_atomic_t의 사용 용도는 시그널 핸들러에서 안전하게 변수를 읽고 쓰기 위해 사용됨.
핸들러가 작업을 진행중일때, 동일한 유형의 시그널이 들어오면, 그 시그널은 대기하지 않고 버려짐. 예시 741페이지 .
SIGCHLD 시그널은 3개가 보내지지만, 한 시그널이 수신되고 두번째 시그널은 대기되며, 한개의 시그널은 버려지므로 두 개의 자식만 버려짐.
서로 다른 시스템이 서로 다른 시그널 처리 방식을 갖는다.
- signal함수의 의미가 다르다.
- system call은 중단될 수 있다. ->read wait accept같이 잠재적으로 시그널을 오랫동안 블록할 가능성이 있는 시스템 콜들은 느린 시스템 콜이라 불리며, 시그널 핸들러가 리턴할때 다시 시작하지 않고 사용자에게 즉시 리턴함. ->read함수가 실행중일때 시그널이 수신된다면(이벤트가 발생한다면), 핸들러가 처리되고 나서 다시 실행되는 것이 아닌 다음 인스트럭션으로 넘어간다는 말인듯.
-> 이런 이슈들을 처리하기위해
sigaction함수를 사용함.
-> 시그널이 발생했을 때 실행할 동작을 정의하는데 사용됨.