시그널

  • software interrupts
  • 비동기적으로 발생하는 이벤트를 처리하기 위한 매커니즘을 제공

Interrupt

  • 예상되지 않고 외부에서 발생된 이벤트

Interrupt Handling

  • 인터럽트 발생
  • 프로세스 중단(커널에 의해서)
  • 인터럽트 처리
  • 인터럽트 발생 장소, 원인 파악
  • 인터럽트 서비스 할 것인지 결정
  • 인터럽트 서비스 루틴 호출

Life cycle of a signal

  • 발생
    • 프로그램에서 발생한 예외적 상황 ex) divide by zero
    • 사용자의 입력 ex) ctrl+c
    • process 또는 kernel에서 생성/전달
  • 보관
    • signal 전달 전까지, kernel이 보관
    • 전달 가능해지면, 해당 process에게 전달
  • 처리
    • 지정된 방법에 따라 signal 처리
      • ignore
      • catch
      • default action

Signals in Unix/Linux

  • Symbolic constant(map to a number)
  • Pending signal : 아직 처리되지 않은 signal

Signal handler

  • 특정 signal을 처리하기 위해 지정된 함수
  • default handler를 대체 할 수 있음
  • 단, 다음 signal에 대한 handler는 대체 불가능
    • SIGKILL
    • SIGSTOP

registering a signal handler

#include <signal.h>
typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t handler);
  • signum : 처리할 signal 번호
  • handler : signal handler의 function pointer
    • SIG_IGN : signal 무시
    • SIG_DFL : system의 default handler로 처리
  • return
    • 기존 handler의 function pointer
    • SIG_ERR : error

print signal message

#include <signal.h>

void psignal(int sig, const char* msg);
char* strsignal(int sig);
extern const char* const sys_siglist[];

Example

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void sigint_handler(int signo)
{
    printf("Caught SIGINT!\n");
    psignal(signo, "Received signal");
}

int main(void) {
    if (signal(SIGINT, sigint_handler) == SIG_ERR) {
        fprintf(stderr, "Cannot handle SIGINT!\n");
        exit(EXIT_FAILURE);
    }

    for (;;) pause();
    return 0;
}

Inherited signal behavior

  • on fork() : signal handler 상속 받음, pending signal 상속 받지 않음
  • on exec() : signal handler 상속 받지 않음, pending signal 상속

sending a signal

#include <sys/types.h>
#include <signal.h>

int kill (pid_t pid, int signo);
  • pid : signal을 보낼 대상
    • 0 : 자신이 속한 process group 내 모든 process
    • -1 : 현재 process가 가진 권한으로 signal을 보낼 수 있는 모든 process
    • < -1 : GID == | pid | 인 process group
  • signo : 보낼 시그널 번호
  • return
    • 0 : success
    • -1 : fail
      • errno = EINVAL : 유효하지 않은 signo
      • errno = EPERM : signal을 보낼 권한이 없음
      • errno = ESRCH : 대상 process가 존재하지 않음(or zombie)

Permission for sending a signal

  • 다른 프로세스에게 signal을 보내기 위해서는 적합한 권한을 가지고 있어야 함
  • 필요 권한
    • Sender's (RUID or EUID) == (RUID or SUID) of the receiver
    • root는 모든 process에게 signal 전달 가능
  • 권한 체크 방법
    • NULL signal (=0) 활용
    • 실제 시그널을 전달하지 않으나, error checking은 수행
int ret;
ret = kill(1722, 0);
if (ret); // lack of permission
else; // we have permission

Example

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>

extern int errno;

int main(void) {
        int targetPID = 0;

        while (1) {
                printf("Enter PID to kill : ");
                scanf("%d", &targetPID);
                if (kill(targetPID, SIGKILL) == -1) {
                        switch (errno) {
                                case EPERM:
                                        printf("Not enough permission!\n");
                                        break;
                                case ESRCH:
                                        printf("Cannot find the process %d\n", targetPID);
                                        break;
                                }
                }
                else {
                        printf("Bang! -> %d\n", targetPID);
                }
        }
        return 0;
}

sending a signal to yourself

#include <signal.h>

int raise(int sig);
  • 자신에게 signal 전달
  • sig : 보낼 signal 번호
  • return 
    • 0 : success
    • otherwise : fail
#include <unistd.h>

unsigned int alarm(unsigned int seconds);
  • 지정된 시간 후에 SIGALRM 발생

Example

#include <unistd.h>
#include <stdio.h>
#include <signal.h>

void handler(int signo) {
        psignal(signo, "Received Signal");
}

int main(void) {
        signal(SIGALRM, handler);

        alarm(2);
        printf("Wait...\n");
        sleep(3);

        return 0;
}

Blocking signals

  • signal은 임의의 순간에 발생
  • kernel은 임의의 순간에 process를 중지
  • signal handling 작업 수행
  • 중요한 작업 수행 중 signal이 온다면?
  • critical region 보호를 위해 signal blocking 필요

signal set

  • 복수 개의 signal을 처리하기 위해 사용
  • sigset_t(=bit mask) : 각 bit가 signal number와 1:1 mapping
#include <signal.h>

int sigemptyset(sigset_t* set);
int sigfillset(sigset_t* set);

int sigaddset(sigset_t* set, int signum);
int sigdelset(sigset_t* set, int signum);

int sigismember(const sigset_t* set, int signum);

blocking signals

#include <signal.h>

int sigprocmask(int how, const sigset_t* set, sigset_t* oldset);
  • how : 지정 방법
    • SIG_SETMASK : set을 blocking mask로 적용
    • SIG_BLOCK : blocking 대상 추가
    • SIG_UNBLOCK : blocking 대상에서 제거
  • set : 적용할 signal set
    • NULL : how를 무시(signal mask 유지), 현재 signal mask -> oldset
  • oldset : 적용 전 signal set 반환
  • return
    • 0 : success
    • -1 : fail
  • 막힌 signal은 pending되고, pending signal들은 blocking이 풀리면 전달됨

Example

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

void handler_SIGINT(int _signo)
{
        printf("Received signal : %s\n", strsignal(_signo));
}

int main(void) {
        sigset_t new;

        if (signal(SIGINT, handler_SIGINT) == SIG_ERR) {
                perror("signal SIGINT");
                exit(1);
        }

        sigemptyset(&new);
        sigaddset(&new, SIGINT);
        sigaddset(&new, SIGQUIT);
        sigprocmask(SIG_BLOCK, &new, (sigset_t*)NULL);

        sleep(5); //critical section
        printf("UnBlocking signals\n");
        sigprocmask(SIG_UNBLOCK, &new, (sigset_t*)NULL);

        return 0;
}

waiting signals

#include <signal.h>

int sigsuspend(const sigset_t* mask);
  • signal mask를 임시로 교체 후, block 되지 않은 signal이 도착할 때까지 대기
  • mask : 교체할 signal set의 주소
  • return
    • 항상 -1
    • errno = EINTR : signal에 의해 interrupt 발생

Example

#include <unistd.h>
#include <signal.h>
#include <stdio.h>

void handler(int signo) {
        psignal(signo, "Received Signal:");
}

int main(void){
        sigset_t set;

        signal(SIGALRM, handler);

        sigfillset(&set);
        sigdelset(&set, SIGALRM);

        alarm(3);

        printf("Wait...\n");

        sigsuspend(&set);

        return 0;
}

'💻 Computer Science > System' 카테고리의 다른 글

[System] Named Pipe  (1) 2024.01.26
[System] 메모리 맵핑  (1) 2024.01.26
[System] 프로세스 관리  (1) 2024.01.25
[System] 프로세스  (0) 2024.01.25
[System] 시스템 정보  (0) 2024.01.24