Signal
- 시그널의 정의
- 시그널갯수 - 64개
signal related data structure
시그널을 보내고 받는것은 주로 태스크이다. 따라서 시그널과 관련된 자료구조가 task_struct 구조체에 존재한다.
struct task_struct {
int exit_code, exit_signal;
int pdeath_signal; /* The signal sent when the parent dies */
/* signal handlers */
struct signal_struct *signal;
struct sighand_struct *sighand;
sigset_t blocked, real_blocked;
sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
struct sigpending pending;
unsigned long sas_ss_sp;
size_t sas_ss_size;
- sighand_struct
- 태스크에 설치된 시그널 핸들러를 관리하기 위한 자료구조
- 구조체를 구성하는 필드
- atomit_t count - sighand_struct를 공유하는 쓰레드개수를 관리
- clone()시에 시그널을 공유하도록 설정하면 공유함
- struct k_sigaction action[_NSIG] - 시그널마다 설치된 핸들러정보를 담고 있는 배열
- atomit_t count - sighand_struct를 공유하는 쓰레드개수를 관리
- sigset_t blocked, real_blocked
- 태스크가 block하는 시그널목록
- struct sigpending pending
- 전달되었지만 처리되지 않은 signal의 linked list
- list의 element는 sigqueue
- sas_ss_sp, sas_ss_size
- sigaltstack API를 통해 시그널핸들러가 실행되는 스택을 지정할 수 있음.
- 보통은 유저의 스택영역을 사용함.
send signal to task
유저스페이스에서 태스크에게 시그널을 보내는 방법중 하나는 kill 명령어를 사용하는 것이다. 커널은 이 명령어를 어떻게 처리하는지 알아보자.
SYSCALL_DEFINE2(kill..)
-> siginfo 구조체를 하나 설정함
-> kill_something_info()
->-> kill_pid_info(signal, siginfo, pid)
->->-> pid와 매핑된 태스크의 task_struct 찾기
->->-> group_send_sig_info(signal, siginfo, task_struct)
->->->-> check permission
->->->-> do_send_sig_info(sig, info, p, group)
->->->->-> send_signal()
->->->->->-> __send_signal()
kill 명령어를 실행하면 결국 __send_signal()를 호출하게 된다.
static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
int group, int from_ancestor_ns)
{
struct sigpending *pending;
struct sigqueue *q;
int override_rlimit;
int ret = 0, result;
...
pending = group ? &t->signal->shared_pending : &t->pending;
...
q = __sigqueue_alloc(sig, t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE,
override_rlimit);
if (q) {
list_add_tail(&q->list, &pending->list);
switch ((unsigned long) info) {
...
default:
copy_siginfo(&q->info, info);
...
out_set:
signalfd_notify(t, sig);
sigaddset(&pending->signal, sig);
complete_signal(sig, t, group);
sigqueue를 연결할 태스크의 sigpending 구조체를 결정한다. 쓰레드그룹이라면 signal->shared_pending을 아니라면 pending을 사용한다. sigqueue를 할당받는다. sigqueue를 sigpending 구조체에 연결한다. sigqueue의 info에 인자로 전달된 info를 copy한다. info에는 signal번호, signal을 보낸 프로세스의 pid정보등이 있다. sigpending 구조체에 새로운 signal이 기다리고 있음을 설정함.
default action for signal
시그널을 처리할 핸들러가 등록되지 않으면 시그널마다 설정되는 기본동작이 달라진다.
- ignore(아무일도 하지않음)
- SIGCONT SIGCHILD SIGWINCH SIGURG
- terminate(프로세스를 죽임)
- SIGHUP SIGINT SIGKILL SIGUSR1 SIGUSR2 SIGALRM SIGTERM SIGVTALRM SIGPROF SIGPOLL SIGIO SIGPWR RTSIG??
- stop(프로세스를 TASK_STOPPED상태로 만듬)
- SIGSTIP SIGTSTP SIGTTIN SIGTTOU
- core dump(coredump를 생성하고 죽임)
- SIGQUIT SIGILL SIGTRAP SIGABRT SIGBUS SIGFPE SIGSEGV SIGXCPU SIGXFSZ SIGSYS SIGEMT
자세한 정리는 include/linux/signal.h를 보고 다시 정리해야 함