본문 바로가기
Unix

Unix 시스템에서 시그널(Signal) 함수(비동기적인 이벤트를 처리)

by mdesign 2024. 9. 1.

Unix 시스템에서 시그널(Signal) 함수는 프로세스 간에 비동기적인 이벤트를 처리하는 데 사용되는 다양한 함수들을 포함합니다. 이 함수들은 시그널을 설정, 변경, 확인, 블록하는 데 도움을 주며, 시그널이 발생했을 때의 동작을 제어합니다.


 주요 시그널 관련 함수

1. `signal()`

- 기능: 시그널에 대한 핸들러를 설정하거나 기본 동작으로 복원합니다.
- 형식: 

  void (*signal(int sig, void (*func)(int)))(int);


- 매개변수:
  - `sig`: 설정할 시그널의 번호 (예: `SIGINT`, `SIGTERM` 등).
  - `func`: 시그널이 발생했을 때 호출될 핸들러 함수의 포인터. `SIG_IGN`으로 설정하면 시그널을 무시하고, `SIG_DFL`로 설정하면 기본 동작으로 복원합니다.
- 반환값: 이전의 시그널 핸들러 함수 포인터를 반환합니다. 오류 발생 시 `SIG_ERR`를 반환합니다.

예제:

#include 
#include 
#include 

void signal_handler(int signum) {
    printf("Caught signal %d\n", signum);
    exit(1);
}

int main() {
    // SIGINT 시그널에 대한 핸들러 설정
    if (signal(SIGINT, signal_handler) == SIG_ERR) {
        perror("signal");
        exit(1);
    }

    // 무한 루프
    while (1) {
        printf("Program running...\n");
        sleep(1);
    }

    return 0;
}


2. `sigaction()`

- 기능: 시그널에 대한 보다 세밀한 제어를 제공합니다. 시그널 핸들러의 동작 방식을 설정할 수 있습니다.
- 형식:

  int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);


- 매개변수:
  - `signum`: 설정할 시그널 번호.
  - `act`: 새로운 시그널 동작을 정의하는 `struct sigaction` 구조체의 포인터.
  - `oldact`: 이전 시그널 동작을 저장할 `struct sigaction` 구조체의 포인터. 이 매개변수는 `NULL`일 수 있습니다.
- 반환값: 성공 시 0을 반환하며, 실패 시 -1을 반환하고 `errno`를 설정합니다.

`struct sigaction`:

struct sigaction {
    void (*sa_handler)(int);   // 시그널 핸들러 함수 포인터
    void (*sa_sigaction)(int, siginfo_t *, void *);  // 대체 핸들러 함수 포인터 (sigaction() 호출 시만 사용)
    sigset_t sa_mask;          // 시그널 마스크, 핸들러 실행 중 블록할 시그널 집합
    int sa_flags;              // 동작 플래그
    void (*sa_restorer)(void); // 복원 함수, 현재는 사용되지 않음
};


예제:

#include 
#include 
#include 
#include 

void signal_handler(int signum) {
    printf("Caught signal %d\n", signum);
    exit(1);
}

int main() {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;

    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }

    // 무한 루프
    while (1) {
        printf("Program running...\n");
        sleep(1);
    }

    return 0;
}

 

3. `sigemptyset()`, `sigfillset()`, `sigaddset()`, `sigdelset()`

- 기능: 시그널 집합을 초기화하고 수정하는 함수들입니다.
- 형식:
  - `sigemptyset(sigset_t *set)`: 시그널 집합을 빈 집합으로 초기화합니다.
  - `sigfillset(sigset_t *set)`: 시그널 집합을 모든 시그널을 포함하는 집합으로 초기화합니다.
  - `sigaddset(sigset_t *set, int signum)`: 시그널 집합에 시그널을 추가합니다.
  - `sigdelset(sigset_t *set, int signum)`: 시그널 집합에서 시그널을 제거합니다.

예제:

#include 
#include 
#include 

int main() {
    sigset_t sigset;

    sigemptyset(&sigset);
    sigaddset(&sigset, SIGINT);

    // 현재 시그널 마스크를 시그널 집합으로 설정
    if (sigprocmask(SIG_SETMASK, &sigset, NULL) == -1) {
        perror("sigprocmask");
        exit(1);
    }

    // 무한 루프
    while (1) {
        printf("Program running, SIGINT blocked...\n");
        sleep(1);
    }

    return 0;
}

4. `sigprocmask()`

- 기능: 현재 프로세스의 시그널 마스크를 설정하거나 얻습니다.
- 형식:

  int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);


- 매개변수:
  - `how`: 시그널 마스크를 변경하는 방법을 지정. `SIG_BLOCK`, `SIG_UNBLOCK`, `SIG_SETMASK` 중 하나.
  - `set`: 새 시그널 마스크를 설정할 시그널 집합의 포인터.
  - `oldset`: 이전 시그널 마스크를 저장할 `sigset_t` 구조체의 포인터. 이 매개변수는 `NULL`일 수 있습니다.
- 반환값: 성공 시 0을 반환하며, 실패 시 -1을 반환하고 `errno`를 설정합니다.

예제:

#include 
#include 
#include 

int main() {
    sigset_t newmask, oldmask;

    sigemptyset(&newmask);
    sigaddset(&newmask, SIGINT);

    // SIGINT 시그널을 블록
    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) == -1) {
        perror("sigprocmask");
        exit(1);
    }

    // 무한 루프
    while (1) {
        printf("Program running, SIGINT blocked...\n");
        sleep(1);
    }

    return 0;
}

 

5. `sigpending()`

- 기능: 현재 프로세스에 대해 대기 중인 시그널 집합을 반환합니다.
- 형식:

  int sigpending(sigset_t *set);


- 매개변수:
  - `set`: 대기 중인 시그널을 저장할 `sigset_t` 구조체의 포인터.
- 반환값: 성공 시 0을 반환하며, 실패 시 -1을 반환하고 `errno`를 설정합니다.

예제:

#include 
#include 
#include 

int main() {
    sigset_t pending;

    sigemptyset(&pending);

    // SIGINT 시그널을 블록
    sigaddset(&pending, SIGINT);
    if (sigprocmask(SIG_BLOCK, &pending, NULL) == -1) {
        perror("sigprocmask");
        exit(1);
    }

    // 대기 중인 시그널 확인
    if (sigpending(&pending) == -1) {
        perror("sigpending");
        exit(1);
    }

    if (sigismember(&pending, SIGINT)) {
        printf("SIGINT is pending\n");
    }

    return 0;
}

 

 요약

- 시그널은 비동기적 이벤트 알림 메커니즘입니다.
- 시그널 함수는 시그널을 처리하고 제어하는 데 사용됩니다.
  - `signal()`: 간단한 시그널 핸들러 설정.
  - `sigaction()`: 세밀한 시그널 핸들러 제어.
  - `sigemptyset()`, `sigfillset()`, `sigaddset()`, `sigdelset()`: 시그널 집합 조작.
  - `sigprocmask()`: 시그널 마스크 설정 및 확인.
  - `sigpending()`: 대기 중인 시그널 확인.

이러한 함수들은 프로세스의 시그널 처리 및 제어를 효율적으로 수행할 수 있게 해줍니다.