7.시그널
7-1. 개요
signal은 software interrupt로 프로세스에 뭔가 발생했음을 알리는 간단한 메세지를 비동기적으로 보내는 것이다.
시그널은 0으로 나누기처럼 프로그램에서 예외적 상황이 일어나는 경우나, 프로세스가 시그널을 보낼 수 있는 함수를 사용해 다른 프로세스에 시그널을 보내는 경우에 발생한다.
보통 시그널로 전달된느 메세지는 무엇이 발생했는지를 표시하는 미리 정의된 상수를 사용한다.
시그널을 받은 프로세스는 시그널에 따른 기본 동작을 수행하거나 시그널을 무시하거나 시그널 처리를 위해 특별히 지정된 함수를 수행하도록 할 수 있다.
- 시그널 보내기 함수
int kill(pid_t pid, int sig);
int raise(int sig);
void abort(void);
int sigsend(idtype_t idtype, id_t id int sig);
프로세스가 시그널을 받을 때 기본 처리 방법은 프로세스를 종료하는 것이다. 프로세스가 종료하기 전에 처리할 작업이 남아있거나 특정 시그널에 대해서는 종료하고 싶지 않을 경우에 시그널을 처리하는 함수를 지정할 수 있다. 이런 함수를 signal handler라고 한다.
- 시그널 핸들러 지정 함수
void(*signal (int sig, void (*disp)(int)))(int);
void(*sigset(int sig, void(*disp)(int)))(int);
int sigignore(int sig);
유닉스 관련 표준 중 하나인 POSIX에서는 시그널을 개별적으로 처리하지 않고 복수의 시그널을 처리할 수 있게 한다. POSIX에서는 복수의 시그널을 처리하기 위해 도입한 개념을 시그널 집합(Signal set)이라고 한다. 시그널 집합을 사용하면 여러 시그널을 지정해 처리할 수 있다.
- 시그널 집합 관련 함수
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(sigset_t *set, int signo);
signal함수나 sigset함수가 단순히 시그널 핸들러만 지정할 수 있는데 비해 sigaction함수는 시그널을 받아 이를 처리할 시그널 핸들러를 지정할 뿐만 아니라 플래그를 설정해 시그널 처리 과정을 제어할 수도 있다. 또한 시그널 핸들러가 수행되는 동안 다른 시그널을 블록할 수도 있다.
- 시그널 처리 제어 함수
int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);
알람 시그널(alarm signal)은 일정한 시간이 지난 후에 자동으로 시그널이 발생하도록 한다. 일정한 시간 후에 한번 발생시킬 수도 있고, 일정 시간 간격을 두고 주기적으로 알람 시그널을 발생시킬 수도 있다.
- 알람 시그널 관련 함수
* 알람시그널 함수
unsigned int alarm(unsigned int sec);
* 인터벌 타이머 함수
int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
시그널의 정보를 출력하고, 시그널을 블록하거나 해제하는 시그널과 시그널을 받을 때까지 기다리는 함수도 있다.
- 기타 시그널 관련 함수
* 시그널 정보 출력
void psignal(int sig, const char *s);
char *strsignal(int sig);
* 시그널 블록과 해제
int sighold(int sig);
int sigrelse(int sig);
int sigprocmask(int how, const sigset_t *restrict set sigset_t *restrict oset);
* 시그널 대기
int sigpause(int sig);
int sigsuspend(const sigset_t *set);
int pause(void);
7-2. 시그널의 개념
signal은 프로세스에 무언가 발생했음을 알리는 간단한 메세지를 비동기적으로 보내는 것이다. 이 메세지는 무엇이 발생했는지 표시하는 미리 정의된 상수를 사용한다. 시그널을 받은 프로세스는 시그널의 종류에 따라 적절한 처리 방법을 지정할 수 있다.
7-2-1. 시그널의 발생
시그널은 software interrupt 이다. 시그널은 비동기적으로 발생하며, 유닉스 운영체제가 프로세스에 전달한다.
시그널 발생하는 경우
- 0으로 나누기처럼 프로그램에서 예외적 상황이 발생하는 경우
- 프로세스가 kill함수와 같이 시그널을 보낼 수 있는 함수를 사용해 다른 프로세스에 시그널을 보내는 경우
- 사용자가 ctrl+c 와 같은 인터럽트 키를 입력한 경우
7-2-2. 시그널 처리 방법
시그널을 받은 프로세스가 이를 처리하는 방법은 다음과 같이 4가지로 정리할 수 있다.
프로세스가 받은 시그널에 따라 default action을 수행한다. 각 시그널에는 기본 동작이 지정되어 있다. 대부분 시그널의 기본 동작은 프로세스를 종료하는 것이다. 이외에 시그널을 무시하거나 프로세스의 수행 일시 중지(suspend)/ 재시작(resume) 등을 기본 동작으로 수행한다.
프로세스가 받은 시그널을 무시한다. 프로세스가 시그널을 무시하기로 지정하면 유닉스는 프로세스에 시그널을 전달하지 않는다.
프로세스는 시그널의 처리를 위해 미리 함수를 지정해놓고 시그널을 받으면 해당 함수를 호출해 처리한다. 시그널 처리를 위해 지정하는 함수를 시그널 핸들러(signal handler)라고 한다. 시그널을 받으면 기존 처리 작업을 중지한 후 시그널 핸들러를 호출하며, 시그널 핸들러의 동작이 완료되면 기존 처리 작업을 계속 수행한다.
프로세스는 특정 부분이 실행되는 동안, 시그널이 발생하지 않도록 블록할 수 있다. 블록된 시그널은 큐에 쌓여있다가 시그널 블록이 해제되면 전달된다.
7-2-3. 시그널의 종류
시그널은 signal.h 파일에 정의 되어 있다. 기본 처리 중 종료 는 프로세스가 그냥 종료되는 것이고, core dump는 코어 파일을 만들고 종료하는 것이다.
7-3. 시그널 보내기
프로그램에서 시그널을 보내려면 kill, raise, abort 함수를 사용하면 된다. 이중 많이 사용하는 함수는 kill이다. kill은 명령도 있는데, 프로세스를 종료할 때 주로 사용한다.
- PID가 3255인 프로세스 강제 종료할 때
# kill -9 3255
kill명령은 인자로 지정한 프로세스에 시그널을 보내는 명령이다. 위의 예는 PID가 3255인 프로세스에 9번 시그널을 보내라는 의미이다. 9번 시그널은 SIGKILL이고 프로세스를 강제로 종료한다.
7-3-1. 시그널 보내기 함수
- 시그널 보내기 : kill(2)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
* pid : 시그널을 받을 프로세스의 ID
* sig : pid로 지정한 프로세스에 보내려는 시그널
kill함수는 pid에 대응하는 프로세스에 sig로 지정한 시그널을 보낸다. pid는 특정 프로세스 또는 프로세스 그룹을 말한다.
sig에 0(널 시그널)을 지정하면 실제로 시그널을 보내지 않고 오류를 확인한다. 예를 들면 pid가 정상인지 검사한다.
pid에 지정한 값에 따라 시그널을 어떻게 보낼 지 결정한다.
pid가 0보다 큰 수 : pid로 지정한 프로세스에 시그널을 보낸다.
pid가 -1 이 아닌 음수 : 프로세스 그룹 ID가 pid의 절대값인 프로세스 그룹에 속하고 시그널을 보낼 권한을 가지고 있는 모든 프로세스에게 시그널을 보낸다.
pid가 0 : 특별한 프로세스(스케줄러)를 제외하고 프로세스그룹ID가 시그널을 보내는 프로세스의 프로세스 그룹 ID와 같은 모든 프로세스에게 시그널을 보낸다.
pid가 -1 : 시그널을 보내는 프로세스의 유효 사용자 ID가 root(슈퍼 유저)가 아니면 특별한 프로세스를 제외하고 프로세스의 실제 사용자 ID가 시그널을 보내는 프로세스의 유효 사용자 ID와 같은 모든 프로세스에게 시그널을 보낸다.
- 시그널 보내기 : raise(3)
#include <signal.h>
int raise(int sig);
* sig: 보내려는 시그널 번호
* 성공시 0, 실패시 -1 리턴
이 함수는 호출한 프로세스에 인자로 지정한 시그널을 보낸다. 만약 시그널 핸들러가 호출되면 시그널 핸들러의 수행이 끝날때까지 리턴하지 않는다.
- 시그널 보내기 : abort(3)
#include <stdlib.h>
void abort(void);
이 함수는 이를 호출한 프로세스에 SIGABRT시그널을 보낸다. 이 시그널을 프로세스를 비정상적으로 종료시키고 코어 덤프 파일을 생성하며 최소한 해당 프로세스가 연 파일은 모두 닫는다. 이 함수는 프로세스를 종료시키므로 리턴하지않는다.
7-4. 시그널 기본 처리
프로세스가 시그널을 받을 때 수행하는 기본적인 처리는 대부분 프로세스를 종료하는 것이다.
만일 프로세스를 종료하기 전에 처리할 작업이 남아있거나, 특정 시그널에 대해 종료하고 싶지 않으면, 시그널을 받을 때 수행할 함수(시그널 핸들러, signal handler) 를 지정하면 된다. 이렇게 시그널을 확인해 처리하는 일을 시그널 붙잡기(catching a signal)이라고 한다.
7-4-1. 시그널 핸들러 함수
- 시그널 핸들러 지정 : signal(3)
#include <signal.h>
void (*signal (int sig void (*disp)(int)))(int);
* sig : 시그널 핸들러로 처리하려는 시그널
* disp : 시그널 핸들러의 함수명
이 함수를 사용하면 시그널을 받을 때 해당 시그널을 처리할 함수나 상수를 지정할 수 있다.
첫번째 인자인 sig에는 SIGKILL, SIGSTOP 시그널을 제외한 모든 시그널을 지정할 수 있다.
두번째 인자인 disp에는 sig로 지정한 시그널을 받았을 때 처리할 방법을 지정한다. disp 인자에는 다음 세가지 중 하나를 설정해야한다.
- 시그널 핸들러의 주소
- SIG_IGN : 시그널을 무시하도록 지정
- SIG_DFL : 시그널의 기본 처리 방법을 수행하도록 지정
이 함수는 시그널 핸들러의 주소를 리턴한다. 이 함수가 실패하면 SIG_ERR를 리턴한다. 만약 두번째 인자인 disp가 함수 주소고, sig가 SIGKILL, SIGTRAP, SIGPWR이 아니면 이 함수는 시그널을 처리한 후 시그널 처리 방법을 기본 처리 방법(SIG_DFL)로 재 설정한다. 따라서 시그널 처리를 계속 하려면 이 함수를 호출해 시그널을 처리한 후 다시 signal 함수를 설정해야한다.
- 시그널 핸들러 지정 : sigset(3)
#include <signal.h>
void (*sigset(int sig, void(*disp)(int)))(int);
* return : 시그널 핸들러 함수의 주소, 실패시 SIG_ERR
sigset함수의 인자 구조는 signal 함수와 동일하다. 이 함수가 signal함수와 다른 점은 시그널 핸들러가 한번 호출된 후에 기본동작으로 재설정 하지 않고 시그널 핸들러를 자동으로 재지정한다는 것이다.
7-5. 시그널 집합
시그널은 보통 개별적으로 처리된다. 하지만 POSIX 표준에서 시그널과 관련해 정의한 함수중 상당수는 시그널을 개별적으로 처리하지 않고, 복수의 시그널을 처리할 수 있게 한다. POSIX에서는 복수의 시그널을 처리하기 위해 도입한 개념을 signal set이라 한다.
7-5-1. 시그널 집합의 개념
시그널 집합은 시그널을 bit mask로 표현한다. 시그널 하나가 비트 하나를 가리킨다.
각 비트가 특정 시그널과 1:1로 연결되어있다.
만일 비트값이 1이면 시그널이 설정된 것이고 0이면 설정되지 않은 것이다.
유닉스에서는 시그널 집합의 처리를 위해 sigset_t라는 구조체를 제공한다. 이 구조체는 sys/signal.h에 정의되어있고, 이 구조체는 크기가 4인 unsigned int 배열을 이용한다.
typedef struct {
unsigned int __sigbits[4];
} sigset_t
7-5-2. 시그널 집합 처리 함수
- 시그널 집합 비우기 : sigemptyset(3)
#include <signal.h>
int sigemptyset(sigset_t *set);
* set : 비우려는 시그널 집합의 주소
이 함수는 시스템에서 정의한 모든 시그널을 배제해 인자로 지정한 시그널을 빈 집합으로 만든다. 즉 시그널 집합의 모든 비트를 0으로 설정한다.
- 시그널 집합에 모든 시그널 설정 : sigfillset(3)
#include <signal.h>
int sigfillset(sigset_t *set);
이 함수는 인자로 받은 시그널 집합을 시스템에서 정의한 모든 시그널을 포함하는 집합으로 만든다. 즉 시그널 집합의 모든 비트를 1로 설정한다.
- 시그널 집합에 시그널 설정 추가 : sigaddset(3)
#include <signal.h>
int sigaddset(sigset)t *set, int signo);
이 함수는 signo로 지정한 시그널을 set으로 지정한 시그널 집합에 추가한다.
- 시그널 집합에서 시그널 설정 삭제 : sigdelset(3)
#include <signal.h>
int sigdelset(sigset_t *set, int signo);
이 함수는 signo로 지정한 시그널을 set으로 지정한 시그널 집합에서 제거한다.
- 시그널 집합에 설정된 시그널 확인: sigismember(3)
#include <signal.h>
int sigismember(sigset_t *set, int signo);
이 함수는 signo로 지정한 시그널이 set으로 지정한 시그널 집합에 포함되어있으면 1을 없으면 0을 리턴한다.
7-6. sigaction 함수의 활용
sigaction 함수는 signal이나 sigset 함수처럼 시그널을 받았을 때 이를 처리할 수 있는 함수를 지정할 수 있게 한다. 이 함수는 훨씬 다양하게 시그널을 제어할 수 있다.
7-6-1. sigaction 구조체
이 구조체는 sys/signal.h에 정의되어 있다. 구조체의 멤버는 시그널 처리를 위한 시그널 핸들러 주소, 시그널 핸들러가 수행하는 동안 블록될 시그널, 추가적인 기능을 설정할 수 있는 플래그로 구성되어 있다.
struct sigaction {
int sa_flags;
union{
void (*sa_handler)();
void (*sa_sigaction)(int, siginfo_t *, void *);
} _funcptr;
sigset_t sa_mask;
}
* sa_flags : 시그널 전달 방법을 수정할 플래그를 지정한다. 지정 값은 sys/signal.h에 정의되어 있다. (SA_ONSTACK : 0x00000001 등) 해당 값들을 OR연산자로 연결 지정할 수 있다.
* sa_handler와 sa_sigaction : 이 두 인자는 메모리가 중첩된다. 만일 sa_flags에 SA_SIGINFO가 설정되어있지 않으면 sa_handler에는 시그널을 처리할 동작을 지정하고 설정되어 있으면 sa_sigaction 멤버를 사용한다.
* sa_mask : 시그널 핸들러가 동작 중일 때 블록할 시그널을 시그널 집합으로 지정한다. 시그널 핸들러가 시작되어 시그널을 전달할 때 이미 블록된 시그널 집합에 sa_mask로 지정한 시그널 집합을 추가한다. sa_flags에는 SA_NODEFER를 설정하지 않으면 시그널 핸들러를 호출하게 한 시그널도 블록된다.
7-6-2. sigaction 함수
sigaction(2) 함수는 시그널을 받아 이를 처리할 시그널 핸들러를 지정할 뿐 아니라, 플레그를 설정해 시그널을 처리하는 과정을 제어할 수 있다. 또한 시그널 핸들러가 수행되는 동안 다른 시그널을 블록할 수 있다.
#include <signal.h>
int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);
* sig : 처리할 시그널
* act : 시그널을 처리할 방법을 지정한 구조체 주소
* oact : 기존에 시그널을 처리하는 방법을 저장할 구조체 주소
이 함수는 sig에 저장한 시그널을 받았을 때 처리할 방법을 sigaction 구조체인 act로 받는다.
첫번째 인자로 SIGKILL과 SIGSTOP 시그널을 제외한 어떤 시그널도 사용가능하다.
두번째 세번째 인자는 sigaction 구조체를 사용해 지정한다.
두번째 인자로는 NULL 또는 지정된 시그널을 받았을 때 처리할 방법을 지정한 구조체 주소를 지정하고 세번째 인자에는 NULL 또는 기존 처리 방법이 저장된다.
7-6-3. 시그널 발생 원인 검색
sa_flags에 SA_SIGINFO 플래그를 지정하면 시그널이 발생한 원인을 알 수 있다. 이 플래그를 지정하면 sigaction 구조체에서 시그널 핸들러를 지정할 때 sa_handler 대신 sa_sigaction을 사용한다. SA_SIGINFO 플래그를 설정하면 시그널 핸들러는 다음과 같이 인자 세개를 받는 형태로 정의된다.
void handler(int sig, siginfo_t *sip, ucontext_t *ucp);
* sig : 시그널 핸들러를 호출할 시그널
* sip : 시그널이 발생한 원인을 담은 siginfo_t 구조체 포인터
* ucp : 시그널이 전달될 때 시그널을 받는 프로세스의 내부 상태를 나타내는 ucontext_t 구조체 포인터
- siginfo_t 구조체
sys/siginfo.h에 정의되어있고, 다음과 같은 항목으로 구성되어 있다.
typedef struct {
int si_signo; //시스템에서 제공하는 시그널 번호를 저장한다.
int si_errno; //0또는 시그널고 관련된 오류번호를 저장한다.
int si_code; //시그널 발생원인을 정의하는 코드를 저장한다. SI_NOINFO면 si_signo만 의미가 있고, 나머지 멤버는 사용되지 않는다.
union sigval si_value;
union {
...
}__data; //시그널의 종류에 따라 값이 저장된다. union의 세부 내용은 <sys/siginfo.h> 파일에 있다.
} siginfo_t;
- 사용자 프로세스에 의한 시그널 발생원인 코드
st_code의 값이 0과 같거나 작다면 사용자 프로세스가 kill, raise, abort 등의 함수로 시그널을 생성한 것이다.
사용자 프로세스에서 시그널을 생성하면 si_code은 다음과 같은 정의된 값들이 저장된다. 이들 코드는 sys/siginfo.h에 정의되어있으며
man -s 3HEAD sigino.h
명령으로 확인할 수 있다.
[표- 사용자 프로세스가 시그널을 생성했을 때 si_code 값]
code | 값 | 의미 |
---|---|---|
SI_USER | 0 | kill(2),sigsend(2),raise(2),abort(3) 함수가 시그널을 보냄 |
SI_LWP | -1 | _lwp_kill(2) 함수가 시그널을 보냄 |
SI_QUEUE | -2 | sigqueue(3) 함수가 시그널을 보냄 |
SI_TIMER | -3 | timer_settime(3) 함수가 생성한 타이머가 만료되어 시그널을 보냄 |
SI_ASYNCIO | -4 | 비동기 입출력 요청이 완료되어 시그널을 보냄 |
SI_MESGQ | -5 | 빈 메세지 큐에 메시지가 도착했음을 알리는 시그널을 보냄 |
- 시스템 프로세스에 의한 시그널 발생 원인 코드
si_code의 값이 양수면 시스템에서 시그널을 생성한 것이다. 시스템에서 시그널을 생성하는 이유는 여러가지가 있다.
man -s 3HEAD siginfo.h
명령으로 시그널별 발생 원인을 나타낸 코드를 볼 수 있다.
이는 sys/machsig.h 에 정의되어 있다.
- 시그널 발생 원인 출력 : psiginfo(3)
#include <siginfo.h>
void psiginfo(siginfo_t *pinfo, char *s);
* pinfo: 시그널 발생 원인에 대한 정보를 저장하고 있는 구조체 포인터
* s: 출력할 문자열
이 함수는 siginfo_t 구조체 포인터를 인자로 받아 시그널이 발생한 원인을 표준 오류로 출력한다. 첫번째 인자인 pinfo에는 시그널 핸들러의 두번째 인자로 받은 siginfo_t의 구조체의 주소를 지정한다.
함수를 실행하면 두번째 인자인 s에 지정한 문자열이 먼저 출력되고 시그널 정보가 출력된다.
7-7. 알람 시그널
일정한 시간이 지난 후에 자동으로 시그널이 발생하려면 Alarm signal을 사용한다.
알람 시그널은 일정 시간 후에 한번 발생시킬 수도 있고 일정 간격을 두고 주기적으로 발생시킬 수도 있다.
7-7-1. 알람 시그널 함수
- 알람 시그널 생성 : alarm(2)
#include <unistd.h>
unsigned int alarm(unsigned int sec);
* sec : 알람을 발생시킬 때까지 남은 시간(초단위)
이 함수는 인자로 초 단위 시간을 받는다. 인자로 지정한 시간이 지나면 SIGALRM시그널이 생성되어 프로세스에 전달된다.
프로세스별로 알람시계는 하나밖에 없으므로 알람은 하나만 설정가능하다.
알람 시그널을 생성하기 전에 다시 alarm 함수를 호출하면 이전 설정은 없어지고 재설정된다.
인자로 0을 지정하면 이전에 설정한 알람 요청은 모두 취소된다.
alarm 함수는 이전에 호출한 alarm 함수의 시간이 남아있으면 해당 시간을 리턴하고 그렇지 않으면 0을 리턴한다.
7-7-2. 인터벌 타이머
알람 시그널은 정해진 시간에 한번 시그널을 보내고 이를 개선해 일정 시간 간격을 두고 타이머 역할을 할 수 있다.
- 타이머의 종류
유닉스 시스템은 프로세스별로 4개의 타이머를 제공한다. 타이머의 정보는 sys/time.h에 정의되어 있다.
각 타이머가 사용하는 시간의 유형에 따라 각기 다른 시그널이 생성된다.
ITMER_REAL : 실제 시간을 사용한다. 이 타이머가 만료되면 SIGALRM 시그널이 생성된다.
ITMER_VIRTUAL : 프로세스의 가상 시간을 사용한다. 이 시간은 프로세스가 동작 중일 때만 작동한다. 이 시간이 만료되면 SIGVTALRM 시그널이 생성된다.
ITIMER_PROF : 시스템이 프로세스를 위해 실행 중인 시간과 프로세스의 가상 시간을 모두 이용한다. 이 타이머가 만료되면 SIPROF 시그널이 생성된다.
ITIMER_REALPROF : 실제 시간을 사용한다. 이는 멀티스레드 프로그램의 실제 실행 시간을 측정할 때 사용한다. 이와 관련된 시그널은 SIGPROF이다.
- 타이머 정보 검색 : getitimer(2)
#include <sys/time.h>
int getitimer (int which, struct itimerval *value);
* which : 검색할 타이머의 종류
* value : 타이머 정보를 저장할 구조체 타이머
이 함수는 타이머 정보를 검색하는 함수이다. interval 구조체는 sys/time.h에 정의되어 있다.
- itimerval 구조체
struct itimerval{
struct timeval it_interval; // 타이머 간격 정보
struct timeval it_value; // 타이머 만료될 때까지 남은 시간
}
it_interval이 0이면 타이머 기능이 멈추게 된다. 이 값이 0이면 다음번에 타이머가 만료될 때 타이머 기능이 멈춘다.
이 시간 정보들은 timeval 구조체에 정의된다.
- timeval 구조체
struct timeval{
time_t tv_sec;
suseconds tv_usec;
}
timeval 구조체에는 초와 마이크로초 단위로 시간을 저장한다. 즉 타이머에 1/1,000,000초단위 정확도를 부여할 수 있다.
- 타이머 설정 : settimer(2)
#include <sys/time.h>
int setitimer(int which, const sturct itimerval *value, struct itimerval *ovalue);
* which : 설정할 타이머의 종류
* value : 설정할 타이머의 정보를 저장한 구조체 포인터
* ovalue : 이전 타이머 정보를 저장할 구조체 포인터
이 함수는 타이머를 설정하는 함수이다. ovalue 값에는 NULL 또는 이전 설정값을 저장한다.
7-8. 기타 시그널 처리 함수
유닉스에는 시그널 정보를 출력하거나, 시그널이 올때까지 기다리거나 시그널을 보내는 등 시그널 처리와 관련있는 기타 함수를 제공한다.
7-8-1. 시그널 정보 출력
시그널 정보를 출력하려면 psignal이나 strsignal 함수를 사용한다.
- 시그널 정보 출력 : psignal(3)
#include <siginfo.h>
void psignal(int sig, const char *s);
* sig : 정보를 출력할 시그널
* s: 출력할 문자열
이 함수는 두번째 인자에 지정한 문자열을 출력후 첫번째 인자에 지정한 시그널을 가리키는 이름을 붙여 표준 오류로 출력한다.
- 시그널 정보 출력 : strsignal(3)
#include <string.h>
char *strsignal(int sig);
* sig : 정보를 출력할 시그널
이 함수는 인자로 받은 시그널을 가리키는 이름을 문자열로 리턴한다. 인자로 받은 시그널이 없으면 NULL을 리턴한다.
7-8-2. 시그널 블록킹과 해제
signal blocking함수를 사용하면 프로세스가 동작하는 동안에 특정 시그널들을 받지 않도록 블록하거나 해제할 수 있다.
#include <signal.h>
int sighold(int sig); // 인자로 받은 시그널을 프로세스의 signal mask에 추가한다. 시그널 마스크에 추가된 시그널은 블록되어 해당 시그널을 받지 않는다.
int sigrelse(int sig); //프로세스의 시그널 마스크에서 시그널을 해제한다.
* sig: 블록하거나 해제할 시그널
- 시그널 집합 블록과 해제 : sigprocmask(2)
#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restirct oset);
* how: 시그널을 블록할 것인지 해제할 것인지 여부
* set: 블록하거나 해제할 시그널 집합의 주소
* oset: NULL 또는 이전 설정값을 저자알 시그널 집합의 주소
이 함수는 set에 지정한 시그널 집합을 블록할 것인지 해제할 것인지를 how에 지정해 호출한다.
how 지정 값 종류
- SIG_BLOCK: set에 지정한 시그널 집합을 시그널 마스크에 추가함
- SIG_UNBLOCK : 1번과 반대로 제거함.
- SIG_SETMASK : set에 지정한 시그널 집합으로 현재 시그널 마스크를 대체함.
두번째 인자인 set은 블록하거나 해제할 시그널 집합을 가리키고, 세번째 인자인 oset은 NULL이 아니면 이전 설정값이 저장된다.
7-8-3. 시그널 기다리기
pause 함수 외에 시그널이 도착하기를 기다릴 때 사용할 수 있는 함수이다.
- 시그널 대기 : sigpause(3)
#include <signal.h>
int sigpause(int sig);
* sig : 시그널이 올때까지 대기할 시그널
이 함수는 인자로 지정한 시그널을 프로세스의 시그널 마스크에서 제거하고 프로세스가 시그널을 받을 때까지 기다린다.
- 시그널 기다리기 : sigsuspend(2)
#include <signal.h>
int sigsuspend(const sigset_t *set);
* set : 기다리려는 시그널을 지정한 시그널 집합의 주소
이 함수는 인자로 지정한 시그널 집합에 설정된 시그널들로 프로세스의 시그널 마스크를 교체하고, 블록되지 않은 시그널이 도착할 때까지 프로세스의 수행을 멈추고 기다린다.
시그널이 도착하면 프로세스의 시그널 마스크는 이전 설정으로 되돌아간다.
7-8-4. 기타 시그널 관련 함수
- 시그널 보내기 : sigsend(2)
#include <signal.h>
int sigsend(idtype_t idtype, id_t id, int sig);
* idtype : id에 지정한 값의 종류
* id : 시그널에 받을 프로세스나 프로세스 그룹
* sig : 보내려는 시그널
지정한 시그널을 id에 지정한 프로세스나 프로세스 그룹에 보낸다. idtype은 id에 지정한 값의 의미를 알려준다.
sigsend가 kill함수와 다른 점은 특정 프로세스 뿐아니라 프로세스 그룹등 시그널을 받을 수 있는 대상을 다양하게 지정했다는 것이다.
sigsend의 idtype 값의 종류는 지정되어 있다.
PID가 0인 프로세스는 시그널을 보내는 대상에서 항상 제외된다. P_PID로 직접 지정할 때를 제외하고는 PID가 1인 프로세스에서 시그널을 보내는 것도 제외된다.
- 시그널 무시 처리 : sigignore(3)
#include <signal.h>
int sigignore(int sig);
*sig: 무시할 시그널
이 함수는 인자로 지정한 시그널의 처리 방법을 SIG_IGN으로 설정한다.