Thursday, May 22, 2008

Signals, advanced management

signal()을 통한 signal 처리는 기본적인 것이다. 조금 진보된 형태의 signal 처리로 sigaction()이 있다.

#include <signal.h>
int sigaction (int signo, const struct sigaction *act, struct sigaction *oldact);

sigaction()은 핸들러가 돌아가는 동안에 특정 signal을 block할 수도 있고, 핸들러가 프로세스의 상태에 대한 여러 정보들을 제공받을 수도 있다. 위에서는 signo에 해당하는 signal에 대한 핸들을 act로 바꿔주며, 이전의 핸들(behavior)을 oldact에 담아준다. 핸들을 등록할 떄 사용하는 sigaction struct에 대해 간단히 알아보자.

struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void); /* OBSOLETE */
}

이 구조체에서는 두가지 형태의 핸들러를 등록할 수 있다. sa_handler는 signal()에서 등록하던 핸들러와 같은 형태이고, sa_sigaction은 sa_flags에 SA_SIGINFO 가 켜져있는 경우 사용하는 핸들러인데 아래와 같은 형식을 취한다. 이 flag에 따라 둘 중 하나의 핸들러를 사용하기 때문에 어떤 시스템의 경우에는 이 부분을 union으로 정의하기도 하므로 두개의 핸들러를 모두 등록하는 일은 되도록 피하자. sa_flags에 SA_NODEFER가 켜져있지 않는 한 처리하고 있는 signal과 동일한 signal은 block되며 다른 signal의 block은 sa_mask를 통해 추가할 수 있다(물론 SIGKILL, SIGSTOP은 block안된다).

void handler(int signo, siginfo_t *si, void *ucontext);

인자로 signal 번호뿐 아니라 siginfo_t도 받고, void *인 ucontext도 받는다. 다시 sigaction 구조체로 돌아가서 sa_flag 얘기를 더하면, 아래와 같은 flag들을 사용할 수 있다.

  • SA_NOCLDSTOP child가 stop, resume되어도 noti안한다.

  • SA_NOCLDWAIT child 에 대해 wait() 안하겠다...

  • SA_ONSTACK signal이 왔을 때 alternative signal stack을 쓰겠다는 것인데... 잘모르겠다.

  • SA_RESETHAND 'one-shot' 모드이다. 현재 핸들러를 이번 한번만 쓰고 다음에는 default 핸들러를 쓰겠다는...

  • SA_RESTART signal에 의해 인터럽된 system call을 BSD style로 restart하겠다는 건데..ㅡ.ㅡ;.


SA_SIGINFO 일때 사용하는 핸들러에 전달해 주는 siginfo_t 구조체에 어떤 정보들이 있는지 살펴보자

typedef struct siginfo_t {
int si_signo;
int si_errno;
int si_code;
pid_t si_pid;
uid_t si_uid; /* process real UID */
int si_status;
clock_t si_utime;
clock_t si_stime;
sigval_t si_value; /* payload */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
void *si_addr; /* dault시 memory location */
int si_band;
int si_fd;
}



  • si_signo받은 signal number

  • si_errno이 signal과 관련된 error code

  • si_pid종료된 프로세스의 pid(SIGCHLD signal인 경우 사용)

  • si_uid(SIGCHLD signal인 경우 사용)

  • si_statusexit status (SIGCHLD signal인 경우 사용)

  • si_utime종료된 프로세스가 소비한 user time(SIGCHLD signal인 경우 사용)

  • si_stime종료된 프로세스가 소비한 system time(SIGCHLD signal인 경우 사용)

  • si_valueunion of si_int, si_ptr

  • si_intpayload type이 int인 상태에서 sigqueue()에 보내진 signals

  • si_ptrpayload type이 void *인 상태에서 sigqueue()에 보내진 signals

  • si_addrSIGBUS,SIGFPE,SIGILL,SIGESV 등인 경우 fault가 일어난 address를 가지고 있음

  • si_band OOB 인 경우 fd의 oob, priority info를 가지고 있음

  • si_fd SIGPOLL 일때 작업이 완료된 파일의 fd를 가지고 있음



siginfo_t의 다른 원소인 si_code는 signal을 누가 발생 시켰는지, 왜 발생했는지에 대한 정보를 알려주는데, 몇개만 살펴보면 아래와 같다.

  • SI_ASYNCIOasynchronous I/O 끝나서 발생

  • SI_KERNEL커널이 보냈음

  • SI_TIMERPOSIX timer expired

  • SI_USER사용자가 kill(), raise()로 보냈음

  • SIGCHLD 인경우에는 아래의 si_code 들이 넘어온다.

  • CLD_CONTINUED child stopped but resumed.

  • CLD_DUMPED child terminated abnormally.

  • CLD_EXITED child terminated via exit().

  • CLD_KILLED child was killed.

  • CLD_STOPPED child stopped.

  • CLD_TRAPPED child hit a trap.

  • POLL_ERR I/O error

  • POLL_HUP device hung up or disconnect

  • POLL_IN available to read

  • POLL_MSG message is available

  • POLL_OUT available to write

  • POLL_PRI available high-priority data to read


그외에 SIGFPE, SIGBUS, SIGILL 등의 경우는 넘어가자.

No comments:

Post a Comment