시그널(Signal)
비동기적으로 프로세스에 무언가 발생했음을 알리는 표준 신호
시그널 종류
•
Ctrl + C 입력 시 SIGTERM 신호가 전달된다.
•
과제에서 허용된 시그널은 SIGUSR1, SIGUSR2뿐 이다.
Table
Search
시그널 동작 방식
1.
signal() 또는 sigaction() 함수로 시그널 핸들러를 등록한다.
2.
유저 모드에서 인터럽트가 발생하면 커널 모드로 진입하여 등록된 시그널 핸들러를 수행한다.
3.
모든 처리가 완료되면 다시 정상 프로그램 흐름으로 돌아간다.
시그널 객체
sig_atomic_t
비동기 신호가 발생하는 경우에도 원자 엔티티로 접근할 수 있는 정수 유형
typedef int __sig_atomic_t;
typedef __sig_atomic_t sig_atomic_t;
C
복사
•
C 언어는 sig_atomic_t 자료형에 대해 원자형(atomic) 읽기, 쓰기를 보장한다.
•
flag++ 같이 다수의 명령을 필요하는 동작은 안전성을 보장하지 않으므로 단순 플래그 및 객체 참조 목적으로 사용해야 한다.
sigaction
•
시그널 핸들러에 대한 정보를 담고 있는 자료 구조체
struct sigaction {
union __sigaction_u __sigaction_u; /* signal handler */
sigset_t sa_mask; /* signal mask to apply */
int sa_flags; /* see signal options below */
};
union __sigaction_u {
void (*__sa_handler)(int);
void (*__sa_sigaction)(int, siginfo_t *, void *);
};
#define sa_handler __sigaction_u.__sa_handler
#define sa_sigaction __sigaction_u.__sa_sigaction
int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);
C
복사
•
__sigaction_u 공용체
◦
sa_handler : signal 함수를 위한 간단한 함수 포인터
◦
sa_sigaction : sigaction 함수를 위한 상세한 함수 포인터
•
sa_mask 시그널 집합
핸들러 실행 중 블록될 시그널 집합을 설정한다.
◦
sa_mask를 지정하지 않으면 핸들러가 실행되는 도중 핸들러가 다시 실행된다. (데이터 꼬임!)
◦
sa_mask를 지정하면 핸들러가 실행되는 도중 블럭처리가 되어 무시된다.
▪
무시된 시그널은 대기열에 등록된다.
▪
단, 동일한 시그널이 대기열에 등록중이라면 그 시그널은 정말로 무시된다. (시그널 누락!)
•
sa_flags 플래그
SA_ONSTACK
(0x00000001) | sigaltstack()에 설치된 대체 스택을 사용해 이 시그널에 대한 핸들러를 실행한다. |
SA_ONESHOT
SA_RESETHAND
(0x00000002) | 시그널의 기본 처리 방법은 SIG_DFL로 재설정되고 시그널이 처리되는 동안 시그널을 블록하지 않는다. |
SA_NOMASK
SA_NODEFER
(0x00000010) | 시그널이 처리되는 동안 유닉스 커널에서 해당 시그널을 자동으로 블록하지 않는다. |
SA_RESTART
(0x00000004) | 시그널 핸들러에 의해 중지된 함수를 재시작한다. |
SA_SIGINFO
(0x00000008) | 시그널에 대한 더 많은 정보를 제공하는 추가적인 인자로 시그널 핸들러를 실행한다.
- siginfo_t 구조체와 context 정보가 같이 전달된다. |
SA_NOCLDWAIT
(0x00010000) | SIGCHLD인 경우에, 자식들이 제거될 때 좀비 프로세스로 만들지 않는다. |
SA_NOCLDSTOP
(0x00020000) | SIGCHLD라면, 자식 프로세스가 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU등을 받아서 중단되었을 때 부모 프로세스에 SIGCHLD 시그널을 전달하지 않는다. |
siginfo_t
•
시그널에 대한 정보를 담고 있는 자료 구조
void ft_handler(int sig, siginfo_t *info, void *ucontext) { ... }
siginfo_t {
int si_signo; /* 시그널 번호*/
int si_errno; /* 시그널 관련 오류번호 */
int si_code; /* 시그널 발생 원인을 정의하는 코드 */
int si_trapno; /* Trap number that caused hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address (since Linux 2.6.32) */
void *si_lower; /* Lower bound when address violation occurred (since Linux 3.19) */
void *si_upper; /* Upper bound when address violation occurred (since Linux 3.19) */
int si_pkey; /* Protection key on PTE that caused fault (since Linux 4.6) */
void *si_call_addr; /* Address of system call instruction (since Linux 3.5) */
int si_syscall; /* Number of attempted system call (since Linux 3.5) */
unsigned int si_arch; /* Architecture of attempted system call (since Linux 3.5) */
}
C
복사
프로세스 구조
요약
•
sighand의 각 시그널 번호에 핸들러 등을 포함한 sigaction 구조체가 등록된다.
•
특정 프로세스의 시그널이 보류되는 경우 pending에 저장된다.
•
스레드 그룹의 시그널이 보류되는 경우 signal→shared_pending에 저장된다.
•
struct task_struct : 프로세스와 관련된 모든 정보를 담고 있는 디스크립터
Type | Name | 설명 |
struct signal_struct * | signal | 시그널 디스크립터 |
struct sighand_struct * | sighand | 핸들러 디스크립터 |
sigset_t | blocked | 블록된 시그널 마스크 |
sigset_t | real_blocked | 임시로 블록된 시그널 마스크 (rt_sigtimedwait() 시스템콜 사용) |
struct sigpending | pending | private 보류 신호를 저장하는 자료 구조 |
unsigned long | sas_ss_sp | 대체 시그널 핸들러 스택 주소 |
size_t | sas_ss_size | 대체 시그널 핸들러 스택 크기 |
int (*) (void *) | notifier | 프로세스의 일부 시그널을 차단하기 위한 장치 드라이버 용 함수 포인터 |
void * | notifier_data | notifier 함수에서 사용하는 데이터 (테이블의 이전 필드) |
sigset_t * | notifier_mask | notifier 함수를 사용하여 장치 드라이버에 의해 차단된 시그널의 비트 마스크 |
•
struct sigpending 관련
위치 | 이름 | 설명 | 관련 함수 |
시그널 디스크립터 | shared_pending | shared 보류 신호 큐는 스레드 그룹의 보류 신호를 저장 | kill, rt_sigqueueinfo |
프로세스 디스크립터 | pending | private 보류 신호 큐는 특정 프로세스의 보류 신호를 저장 | tkill, tgkill |