[Linux]Signal

공부기록·2023년 10월 20일
0
post-thumbnail

🔊 Signal의 정의

  • 가정

    • ^C 입력시 : interrupt character
      • 키보드로 interrupt character을 입력하면 kernel은 모든 process에게 SIGINT라는 signal을 전송한다.
      • SIGINT의 default action은 종료이므로 종료된다.
  • Signal이란 소프트웨어 인터럽트로 비동기적 event를 다룬다.

  • signals

	$ kell -l
    2) SIGINT(^C)
    3) SIGQUIT(^\)
    6) SIGABRT
    8) SIGKILL
    15) SIGALRM
    15) SIGTERM
    17) SIGCHLD
  • 정의
    • SIGABRT : abort()호출
    • SIGALRM : timer 만료
    • SITCHLD : child가 중단되거나 종료되면 parent에게 보내는 signal
    • SIGCOUNT : 중단된 process를 다시 실행시키는 신호
    • SIGFPE : 수학적 오류 발생 신호
    • SIGILL : 허용되지않은 하드웨어 실행 신호
    • SIGINT : foreground에서 실행중인 process를 모두 종료시키는 신호
    • SIGKILL : default action 변경 불가
    • SIGTERM : kill(1)으로부터 온 종료 시그널로 default action은 종료이다.
    • SIGTSTP : Cntl-Z
    • SIGSTOP : default action 변경 불가
    • SIGUSR1,2 : 유저가 정의한 SIGNAL

🔊 Signal Handling

  • ignore action : sigkill이나 sigstop은 안됨
  • user-defined action : 이하동문
  • default action : 주로 종료로 설정된 것이 많음

🔈 Process signal mask - process attribute

  • signal mask는 block될 시그널의 리스트를 가지고있다.
  • process는 fork 또는 exec 후에 signal mask를 상속한다.

🔈 signal( )

    #include <signal.h>

    void (*signal(int signo, void (*func)(int)))(int);
	
    /* 성공시 , 실패시 SIG_ERR 반환 */
  • signo : signal 이름
  • *func : SIG_IGN, SIG_DFL, signal handler
    int main(void) {
        if (signal(SIGUSR1, sig_usr) == SIG_ERR)
            fatal("can't catch SIGUSR1");
        if (signal(SIGUSR2, sig_usr) == SIG_ERR)
            fatal("can't catch SIGUSR2");
        for ( ; ; )
            pause();
    }

    static void sig_usr(int signo){ /* argument is signal number */
        if (signo == SIGUSR1)
            printf("received SIGUSR1\n");
        else if (signo == SIGUSR2)
            printf("received SIGUSR2\n");
        else {
            printf("received signal %d\n", signo);
            exit(1);
        }
    }

- SIGINT(^C) 발생시 실행할 코드
    #include <signal.h>
    void sig_int(int signo){
       printf("in SIGINT handler()\n");
    }

    int main(){
       signal(SIGINT, sig_int);
       printf("step 1\n");
       pause(); //interrupt종료, 여기로 SIGINT 날라옴
       printf("step 2\n");
       pause();
       printf("step 3\n");
       pause();
       printf("step 4\n");
       pause();
    }
    $ ./a.out
    step 1 ^C
    in SIGINT handler()
    step 2 ^C
    in SIGINT handler()
    step 3 ^C
    in SIGINT handler()
    step 4 ^C
    in SIGINT handler()

🔈 Signal block

  • process signal mask : block될 signal의 리스트
    #include <signal.h>

    void sig_int(int signo)
    {
       printf("in SIGINT handler()\n");
       sleep(5); 
    }

    int main()
    {
       signal(SIGINT, sig_int);
       printf(" 1 pause()\n");
       pause();
       printf(" 2 pause()\n");
       pause();
    }
  • sleep 동안에 받은 SIGINT를 계속 받음. 같은 SIGNAL이 들어오지 못하도록 차단시킨다.
  • process signal mask에 들어가면 차단됨.
  • 맨 마지막 하나만 pending됨

🔈exec 실행시의 signal handling

  • default이거나 ignore(SIGUSR1, SIGUSR2)이다.
  • SIGSTOP, SIGTSTP, CONT 제외 거의 다 종료
  • child가 세팅 그대로 상속받는데 child가 exec해버리면 child 실행 프로그램이 바뀌면서 parent의 signal handler를 못찾게된다. 그냥 child는 signal-catching function 그대로다.
    /* main.c */
    #include <signal.h>	
    #include <unistd.h>
    /* signal_exec */
    int main(int argc, char** argv)
    {
       void sig_int(int signo);
       signal(SIGINT, sig_int);

       pause();
       execl(argv[1], argv[1], (char*)0);

       return 0;
    }

    void sig_int(int signo){
       printf("SIGINT!! %d\n", signo);
    }

    ---

    /* exec.c */
    #include <unistd.h>
    /* exprog */
    int main()
    {
       printf("executed program\n");
       while(1)
          pause();
    }
	# ./signal_exec exprog
    ^C
    SIGINT!! 2
    executed program
    ^C
    #
  • 실습2
	/* main.c */
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/wait.h>

    void sig_usr1(int signo)
    {
       printf("BEFORE EXEC : in SIGUSR handler\n");
    }
    int main(int argc, char** argv)
    {
       /*
       argv[1] : exec filename 
       */

       signal(SIGINT, SIG_IGN); //SIG_INT 무시함
       signal(SIGUSR1, sig_usr1); //USR1은 원래 무시가 디폴트 벗 함수 정의
       printf("BEFORE EXEC : puase()\n");
       pause(); //시그널받음

       execl(argv[1], argv[1], (char*)0);  
    }
    
   /* exec.c */
    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/wait.h>

    int main()
    {
       printf("EXEC : START PROGRAM\n");
       printf("EXEC : RUN pause()\n");   
       pause();
    }

    $ gcc main.c –o main
    $ gcc exec.c –o exec
    $
    $ ./main exec &
    [1] 1828
    BEFORE EXEC : puase()    
    $ kill –INT 1828 //ignore SIGINT 
    $ ps
     PID TTY          TIME CMD
    1306 pts/1    00:00:00 bash
    1828 pts/1    00:00:00 main
    1829 pts/1    00:00:00 ps

    $ kill –USR1 1828 //handler 실행
    BEFORE EXEC : in SIGUSR handler
    EXEC : START PROGRAM
    EXEC : RUN pause()

    $ kill -INT 1828 //pause()실행 상태에서 SIGINT 전송
    $ ps(결과를 작성하시오) //무시되지않음. 1828(main)이 죽는다.
    $ kill –USR1 1828
    $ ps(결과를 작성하시오) //없는 곳에 kill보내니 위의 결과와 같음


0개의 댓글

관련 채용 정보