컴퓨터 시스템 8장 시그널

2025. 4. 21. 14:21개념 공부

8.1.1 Exception Handling (예외 처리)

예외란?

프로그램의 일반적인 흐름과 다르게, 특별한 이벤트가 발생해서 실행 흐름이 바뀌는 것

  • 0으로 나누기 (Divide by zero)
  • 메모리 접근 오류
  • 타이머 인터럽트
  • I/O 완료 알림

핵심 구조: 예외 처리 흐름

예외 발생 → 예외 테이블(주소 찾기) → 예외 핸들러 실행 → 복귀 or 종료

예외가 발생하면 CPU는 Exception Table (예외 테이블)이라는 점프 테이블을 참고해서 해당 예외에 맞는 핸들러 함수를 호출함. 이 과정은 간접 프로시저 호출(indirect procedure call)로 이루어짐.

예외 처리 전체 흐름

  1. 이벤트 발생
  2. 예외 번호 k 결정
  3. Exception Table[k]에서 핸들러 주소 확인
  4. 해당 핸들러 코드로 점프!
  5. 핸들러가 예외 처리 수행
  6. 복귀 or 프로그램 종료

예외 번호 (Exception Number)

  • 예외마다 고유한 번호가 있음 (ex. 0번: divide by zero, 14번: page fault)
  • 이 번호를 index처럼 사용해서 Exception Table에서 해당 핸들러 주소를 찾음

Exception Table이란?

각 예외 번호에 대해, 해당 예외를 처리할 핸들러 주소를 저장한 테이블

예외 테이블의 시작 주소는 CPU의 특수 레지스터에 저장되어 있음 (ex: x86-64에서는 IDTR)

Exception number k = 14  →  Exception Table[14] → page_fault_handler 주소

예외 핸들러는 어떤 일 해?

  1. CPU는 예외 발생 시 현재 명령 상태(PC, EFLAGS 등)를 커널 스택에 저장
  2. 핸들러는 커널 모드에서 실행됨
  3. 다음 중 하나 수행:
    • ❶ 현재 명령으로 복귀
    • ❷ 다음 명령으로 이동
    • ❸ 프로그램 종료

예외 처리 시 스택에 저장되는 정보

  • 리턴 주소 (예외 발생 명령 or 다음 명령)
  • EFLAGS
  • 기타 CPU 상태 정보

8.1.2 예외의 종류 (Classes of Exceptions)

예외는 두 기준으로 분류돼:

  1. 동기(Synchronous) vs 비동기(Asynchronous)
  2. 복귀 가능 여부

📋 4가지 클래스

종류 원인 동기/비동기 복귀 방식
Interrupt I/O 장치가 보낸 외부 신호 비동기 Inext
Trap 의도된 예외 (시스템 호출) 동기 Inext
Fault 복구 가능한 에러 동기 Icurr
Abort 복구 불가 에러 동기 복귀 불가

8.2.2 Concurrent Flows (동시적인 흐름)

여러 흐름이 시간상 겹쳐서 실행되면 Concurrent 라고 해.

 예시:

  • A 프로세스: 1~3초 실행
  • B 프로세스: 2~5초 실행

Concurrent vs Parallel

용어 의미 예시
Concurrent 시간상 겹쳐서 실행 A → B → A → B
Parallel 진짜 동시에 실행 (멀티코어) A는 CPU1, B는 CPU2

8.2.3 Private Address Spaces (프로세스 독립 주소 공간)

  • 각 프로세스는 독립된 메모리 공간을 가짐
  • 서로의 변수/메모리에 접근 불가

주소 공간 구성:

  • 코드, 데이터, 힙, 스택
  • 공유 라이브러리
  • 시스템 콜 인터페이스

8.3 시스템 콜 에러 처리

시스템 콜은 항상 성공하진 않기 때문에 에러 처리를 꼭 해줘야 해

📌 래퍼 함수 예시:

pid_t Fork(void) {
    pid_t pid;
    if ((pid = fork()) < 0)
        unix_error("Fork error");
    return pid;
}

8.4.6 fork와 execve로 프로그램 실행하기

  1. 명령어 입력 받기
  2. 파싱하여 명령어/인자 분리
  3. fork()로 자식 생성
  4. execve()로 프로그램 실행

백그라운드 실행

  • 명령어 끝에 & 붙이면 wait() 하지 않고 다음 입력 받음

Program vs Process

용어 설명
Program 정적인 코드/데이터 파일
Process 실행 중인 프로그램 인스턴스

8.5.2 Sending Signals (시그널 보내기)

 시그널 보내기 방법

  • /bin/kill -9 [pid] → 프로세스 종료
  • kill(getpid(), SIGINT); → 자기 자신에게 보내기

 키보드 입력과 시그널

입력 시그널 동작
Ctrl+C SIGINT 종료
Ctrl+Z SIGTSTP 일시 정지

8.5.3 Receiving Signals (시그널 수신)

 언제 처리됨?

  • 시스템 콜 끝나고 사용자 모드 복귀할 때
  • 컨텍스트 스위치 직후

기본 동작

  • 종료, 무시, 중단 등

사용자 정의 핸들러

void sigint_handler(int sig) {
    printf("Ctrl+C 눌렀네!\n");
    exit(0);
}

int main() {
    signal(SIGINT, sigint_handler);
    while (1) pause();
}

시그널 큐잉 안 됨

  • 같은 시그널이 여러 번 와도 한 번만 pending

잘못된 예시

void handler1(int sig) {
    waitpid(-1, NULL, 0);  // 하나만 수거
    sleep(1);
}

정확한 처리

void handler(int sig) {
    while (waitpid(-1, NULL, 0) > 0)
        ;  // 반복해서 다 수거
}