시그널은 소프트웨어의 다양한 부분 사이에서 정보를 전달하는 데 사용되는 일종의 알림 시스템이다. 주로 프로세스 간의 통신(Inter-Process Communication, IPC) 및 시스템 호출(System Call)과 관련이 있다. 운영 체제는 프로세스가 실행 중일 때 다양한 이벤트에 대해 적절하게 반응할 수 있도록 시그널을 이용한다.
운영 체제에서 시그널은 프로세스 제어와 오류 처리, 사용자 인터럽트, 그리고 자원 관리 등 다양한 용도로 활용된다. 예를 들어, 데몬 프로세스는 SIGTERM 시그널을 받아 종료 루틴을 실행하거나, 로그 파일을 닫고 필요한 정리 작업을 수행할 수 있다. 또한, SIGCHLD 시그널은 자식 프로세스가 종료되었음을 부모 프로세스에 알리는 데 사용되며, 이는 부모 프로세스가 자식 프로세스의 종료 상태를 수집할 수 있도록 한다.
시그널은 기본적으로 비동기적이므로, 시그널이 언제 도착할지 예측하기 어렵다. 따라서 시그널 처리 코드 작성 시에는 항상 비동기적 특성을 고려해야 하며, 가능한 한 안전한 방식으로 프로그래밍해야 한다. 이는 특히 멀티스레드 환경에서 중요한데, 잘못된 시그널 처리는 레이스 컨디션(race condition)이나 데드락(deadlock) 같은 심각한 문제를 초래할 수 있다.
시그널 종류
운영 체제에서 사용하는 대표적인 시그널에는 여러 가지가 있으며, 각각의 시그널은 특정 상황이나 이벤트를 나타낸다.
SIGINT (Signal Interrupt): SIGINT는 사용자가 프로그램 실행을 중단하려고 할 때 발생하는 시그널로, 일반적으로 Ctrl+C 키 조합에 의해 트리거된다. 이 시그널을 받은 프로세스는 기본적으로 즉시 종료된다. 그러나 프로세스는 SIGINT 시그널을 처리하기 위해 사용자 정의 시그널 핸들러를 설정할 수 있으며, 이를 통해 특정 종료 루틴을 실행하거나 종료를 무시할 수 있다.
SIGTERM (Signal Terminate): SIGTERM은 프로세스를 정상적으로 종료시키기 위해 사용되는 시그널이다. 이는 프로그램이 자원을 정리하고 안전하게 종료할 수 있는 기회를 제공한다. 대부분의 경우, 프로세스는 이 시그널을 받아들여 종료하지만, 필요에 따라 SIGTERM 시그널을 무시하거나 사용자 정의 핸들러를 통해 특정 동작을 수행할 수 있다.
SIGKILL (Signal Kill): SIGKILL은 프로세스를 강제로 종료시키는 시그널이다. 이 시그널은 프로세스가 무시할 수 없으며, 커널에 의해 즉시 프로세스가 종료된다. 일반적으로 SIGTERM 시그널에 반응하지 않는 프로세스를 종료할 때 사용된다. 이는 프로세스가 자원을 정리하거나 데이터를 저장할 기회를 제공하지 않으므로, 최후의 수단으로 사용된다.
SIGSEGV (Signal Segmentation Violation): SIGSEGV는 프로세스가 접근 권한이 없는 메모리 영역에 접근하려고 할 때 발생하는 시그널이다. 이는 흔히 잘못된 포인터 접근이나 버퍼 오버플로우와 같은 메모리 접근 오류로 인해 발생한다. 이 시그널을 받은 프로세스는 기본적으로 종료되며, 디버깅 정보를 남기기도 한다. 프로세스는 SIGSEGV 핸들러를 설정하여 이 시그널을 처리할 수 있지만, 메모리 접근 오류는 보통 심각한 문제를 나타낸다.
SIGCHLD (Signal Child): SIGCHLD는 자식 프로세스가 종료되었을 때 부모 프로세스에 전달되는 시그널이다. 부모 프로세스는 이 시그널을 받아 자식 프로세스의 종료 상태를 확인하고 자원을 회수할 수 있다. 이는 고아 프로세스와 좀비 프로세스를 방지하기 위해 중요하다. 부모 프로세스는 이 시그널을 통해 자식 프로세스의 종료를 감지하고, wait() 시스템 호출을 통해 종료 상태를 수집한다.
SIGALRM (Signal Alarm): SIGALRM은 알람 시계(timer)에 의해 발생하는 시그널이다. 이는 프로세스가 특정 시간 후에 어떤 작업을 수행해야 할 때 사용된다. 예를 들어, 특정 작업이 시간 제한 내에 완료되지 않으면 SIGALRM 시그널이 발생하여 해당 작업을 중단시키거나 타임아웃 처리를 할 수 있다. 프로세스는 alarm() 시스템 호출을 통해 알람을 설정할 수 있으며, SIGALRM 핸들러를 통해 시그널을 처리할 수 있다.
SIGHUP (Signal Hangup): SIGHUP는 터미널 연결이 끊어졌을 때 발생하는 시그널이다. 이는 원래 모뎀 연결이 끊어졌을 때 발생하는 시그널이었으나, 현대의 시스템에서는 터미널이나 세션이 종료될 때 주로 사용된다. 데몬 프로세스는 SIGHUP 시그널을 받아 설정 파일을 다시 로드하거나 재시작하는 등의 작업을 수행할 수 있다.
SIGPIPE (Signal Pipe): SIGPIPE는 파이프에 쓰기 작업을 시도할 때, 읽기 쪽이 닫혀 있을 경우 발생하는 시그널이다. 이는 주로 파이프나 소켓을 통해 데이터 통신을 할 때 발생하며, 일반적으로 프로세스를 종료시킨다. 프로세스는 SIGPIPE 시그널을 무시하거나 사용자 정의 핸들러를 설정하여 이 상황을 처리할 수 있다.
요약
시그널(Signal) 개념: 시그널(signal)은 운영 체제에서 프로세스 간 통신(IPC)의 한 형태로, 비동기적 이벤트를 전달하여 예외 상황이나 특정 조건을 알린다. 하드웨어 인터럽트와 유사하지만 소프트웨어 레벨에서 발생한다.
시그널 처리 과정
시그널 발생: 사용자 입력이나 운영 체제, 다른 프로세스에 의해 시그널이 발생한다.
시그널 전달: 커널은 시그널을 프로세스에 전달하고 시그널 대기열에 추가한다.
시그널 핸들러 호출: 커널이 해당 시그널의 시그널 핸들러를 호출하여 처리한다.
시그널의 활용과 종류: 시그널은 프로세스 제어, 오류 처리, 자원 관리 등에 사용된다. 주요 시그널로는 SIGINT(중단), SIGTERM(종료), SIGKILL(강제 종료), SIGSEGV(메모리 오류), SIGCHLD(자식 프로세스 종료) 등이 있다. 비동기적 특성 때문에 시그널 처리 시 재진입성을 고려해야 한다.