System Call - Signal

Hyungseop Lee·2023년 11월 27일
0
post-thumbnail

Signal Concepts

  • Signal : are SW interrupts and provide a way to handle asynchronous events
    (비동기식 프로그램을 수행하기 위한 하나의 수단..)

  • HW는 clock에 의해 동기적으로 수행, SW는 왜 비동기적인가?
    OS에서 HW를 추상화시키기 때문에 우리가 program을 짤 때, clock의 개념이 사라진다.

  • Signal이 발생하면, 그 Signal은 해당 Process에게 전달되고,
    그 process는 signal에 대한 action을 취한다.

    • action
    1. ignore it : 하지만 몇몇 signal은 무시되지 못함
    2. catch it : Signal handler를 호출하여 처리
    3. accept the default
      • Ignored
      • Terminated
      • Core dump :
        A core dump file.swp(process의 regiser, memory값들을 작성) is generated,
        and the process is terminated
      • Stopped
      • Resumed

Linux Signals

  • Each signal is defined as a unique integer. (defined in signal.h)
  • See also signal(2)/signal(7) for deatils of the signals
    • Core : Core dump
      Stop : 일시 정지
      Cont : 재개
      Term : 종료
      Ign : 무시
  • 기본적으로 알아야 하는 SIGNAL
    • SIGALRM : 특정 시간이 지나면 알람
    • SIGCHILD : child process가 끝나면 parent process한테 가는 signal
    • SIGCONT : process가 중지되어 있을 경우, 재개
    • SIGSEGV : 잘못된 memory 접근
    • SIGSTOP : process 일시 정지 (= Ctrl + Z)
    • SIGTERM : process 종료 (= Ctrl + C)
  • handler를 등록할 수 없는 signal : SIGKILL, SIGSTOP

Dispatching Signals : Kill(2), raise(3)

  • kill(2) :
    명시적으로 지정한 process에게 signal을 보낼 수 있다.
    kill(pid, SIGTERM)
    • pid > 0 : signal is sent to process with process ID pid
    • pid = 0 : sender와 같은 gid를 갖는 process에게 모두 signal = broadcasting
  • raise(3) : sends a signal to itself

Example

SIGINT = Ctrl + C

  • SIGINT :
  • Ctrl + C :

SIGSTOP = Ctrl + Z

  • SIGSTOP :
  • Ctrl + Z :

SIGQUIT = Ctrl + \

  • SIGQUIT :

  • Ctrl + \ :

SIGKILL = 9

  • kill -SIGKILL <pid> :

  • kill -9 <pid> :

Signal delivery and handler execution


gdb

  • gdb : The GNU Debugger
    • gcc -g : debug용으로 compile하는 옵션
    • gdb ./(실행파일)
    • break = b : breakpoint 설정
    • r : 실행
    • n : 한줄씩 실행 / 그냥 enter : 이전 명령어(n) 실행
    • step = s : 해당 함수로 들어가라
    • list = l : 현재 어디에 있는지 확인하기
    • backtrace :
      (goo함수에 들어왔으니)

      (foo함수의 마지막 코드인 return; 뒤 '}'에서 backtrace)
    • Ctrl + d : debugger 종료

Setting up a Signal Handler : signal(2)

  • signal(2) :
    signal은 UNIX가 개발되었을 때부터 사용되었던 오래된 system call임.
    그런데 thread 같이 새로운 것들이 Linux에 점점 추가되면서
    signal을 더 정교하게 사용해야할 필요가 있어졌다.
    그래서 이제는 signal(2)보다 sigaction(2)을 더 많이 사용한다.

sigaction(2)

  • sigaction(2) :
    signal(2)과 유사하게 해당 signal에 대한 signal handler를 설정하는데,
    더욱 정밀하게 할 수 있다. (thread, Real time signal 등)
    • int signum ➡️ void(*sa_handler)(int) : signal handler에 전달되는 값
    • const struct sigaction ➡️ sigset_t sa_mask : sa_mask에 지정한 signal이 오면, signal handler가 그 signal에 영향을 받지 않음.

signal set(sigset_t)

  • signal을 하나씩 지정해주지 않고, set으로 지정해주고 싶을 때

example

  • SIGINT(ctrl + C), SIGQUIT(ctrl + \) 에 대한 signal handler 등록하기

  • SIGALRM signal에 대한 handler 등록하기


sigprocmask(2), sigpending(2)

  • sigprocmask(2) :
    • SIG_BLOCK : set에 등록된 signal들과 현재 block된 signal을 합산(union)하여 block
    • SIG_UNBLOCK : 막혀있는 signal 중에서 set에 등록된 signal들의 block을 해제
    • SIG_SETMASK : set에 지정한 signal들을 block
  • sigpending(2) :
    현재 pending되고 있는 signal이 무엇이 있는지 set에 반환.

example

  • sigaction example 1 :
    ➡️ Ctrl+C를 여러번 눌러도 딱 하나만 pending된다.

  • sigaction example 2 :
    왜 (0, 1) 또는 (1, 0)이라는 값이 들어갈까?
    구조체끼리 대입 연산을 할 때, 실제로 한번에 연산되는 것이 아니라
    machine code를 보면 구조체 안에 있는 변수를 각각 대입한다.
    예를 들어
    0 0인 상태에서 1 1을 대입하려고 할 때,
    1 0, 1 1 이러한 순서로 대입이 된다.
    하지만 1 0에서 alarm이 오면 끊고나서, 1 1이 들어가지 않고 1 0이 들어가는 상황이 생기게 된다.
    마찬가지로 반대의 경우 0 1도...

    이러한 오류를 막기 위해서 sigprocmask()를 통해 구조체끼리 대입 연산을 하는 동안 signal을 받지 않도록 해야 한다.


alarm(2)

  • alarm(2) :
    지정한 시간이 지나면, SIGALRM signal이 들어온다.
    alarm(2)은 process에서 딱 1개만 설정할 수 있어서 제약점이 많다.
    그래서 여러 개의 alarm설정, 정밀한 작업을 위해 POSIX interval timer도 만들어졌다.

example


sleep(2), nanosleep(2)

  • sleep(3) :
    지정된 시간 동안 program 실행을 중지
  • nanosleep(2) :
    만약 1초 100ms를 sleep하고 싶다면,
    tv_sec에 1,
    tv_nsec에 100,000,000 (ms = 10310^{-3}, ns = 10910^{-9})

Summary

간단하게 정리하자면
sigaction(2)은 기존의 Signal에 대한 action을 다르게 지정할 수 있는 system call.
sigprocmask(2)는 특정 signal이 들어오는 것을 blocking할 수 있는 system call.


core dump file 확인하기

  • SIGQUIT, SIGSEGV 같은 signal들은 default action으로 core dump file을 생성한다.
    gdb를 이용하여 core dump file을 확인해보자.

core dump file 생성 허가

  • 우선 Linux는 저장공간을 절약하기 위해 default로 core dump file 생성을 막아놨다.
    core dump file 생성을 허가하고, 크기를 제한하고 싶다면 다음 명령어를 사용한다.
ulimit -c unlimited


이제 core dump file을 생성할 수 있고, 만들어지는 크기는 제한이 없다.

core dump file 생성 & gdb

  • SIGQUIT(Ctrl + )을 이용하여 core dump file을 생성해보자.

    이제 core dump file을 찾아서 debugging해보자.
    • WSL에서는 core dump file이 /mnt/wslg/dumps 밑에 만들어진다고 한다.
    • 내 system은 Ubuntu Desktop인데, 현재 디렉터리에 생기지 않아 어디에 생겼는지 찾느라 고생했다..
      찾아보니 /var/lib/apport/coredump/ 밑에 만들어졌다.
  • 이제 만들어진 core dump file을 gdb를 이용하여 debugging해보자.
gdb [원래실행파일명] [만들어진 core dump file명]

SIGQUIT signal로 인해 program이 종료되었다는 msg를 확인할 수 있다.

profile
Efficient Deep Learning Model, Compression

0개의 댓글