크래프톤 정글 (컴퓨터 시스템: CSAPP)/8장 예외적 제어 흐름

컴퓨터 시스템 : CSAPP 8장 정리 - 8.6 ~ 마지막 까지

고웅 2025. 4. 19. 10:55

8.6 Nonlocal Jumps (비지역 점프)

C 언어에서 제공하는 비지역 점프(nonlocal jump)라는 고급 제어 흐름 기능을 설명한다.
이는 함수 호출과 반환의 일반적인 흐름을 무시하고, 한 함수에서 다른 함수의 실행 지점으로 직접 점프하는 기능이다.

핵심 함수: setjmp와 longjmp

#include <setjmp.h>

int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);

 

  • setjmp는 현재 호출 환경(PC, SP, 레지스터 등)을 저장하고 0을 반환
  • longjmp는 setjmp로 저장된 위치로 되돌아감. 이때 setjmp는 val 값을 반환하게 됨
  • 즉, setjmp는 한 번 호출되지만 여러 번 반환될 수 있음

주요 활용: 에러 복구

  • 함수 호출이 깊이 중첩된 상황에서, 특정 지점으로 빠르게 돌아가고 싶은 경우 유용
  • 예제:
jmp_buf buf;

void foo() {
    if (error)
        longjmp(buf, 1);
}

int main() {
    if (setjmp(buf) == 0) {
        foo();
    } else {
        printf("Error handled\n");
    }
}

 

→ foo에서 에러 감지 시, main의 setjmp로 복귀하여 중앙에서 처리

주의사항

  • 중간 함수들에서 동적 할당 메모리를 해제하는 코드가 있다면 그 코드를 건너뛰게 되어 메모리 누수 발생 가능
  • 이로 인해 자원 관리에 부주의하면 부작용 발생

시그널 핸들러와의 연동: sigsetjmp와 siglongjmp

#include <setjmp.h>

int sigsetjmp(sigjmp_buf env, int savesigs);
void siglongjmp(sigjmp_buf env, int val);
  • sigsetjmp는 시그널 마스크 상태까지 저장할 수 있는 버전
  • 시그널 핸들러에서 안전하게 제어 흐름을 이동시키는 데 사용됨

예제: Ctrl+C 눌렀을 때 재시작

sigjmp_buf buf;

void handler(int sig) {
    siglongjmp(buf, 1);
}

int main() {
    if (!sigsetjmp(buf, 1)) {
        signal(SIGINT, handler);
        printf("starting\n");
    } else {
        printf("restarting\n");
    }

    while (1) {
        sleep(1);
        printf("processing...\n");
    }
}

→ 사용자 Ctrl+C 입력 시 SIGINT 발생 → 핸들러에서 siglongjmp 호출로 메인으로 점프 → “restarting” 출력 후 루프 재시작​.

요약

함수 용도
setjmp, longjmp 일반 함수 간 비지역 점프
sigsetjmp, siglongjmp 시그널 처리 포함한 비지역 점프
장점 에러 복구, 신속한 흐름 제어
단점 메모리 누수, 제어 흐름 복잡성 증가

8.7 Tools for Manipulating Processes (프로세스를 조작하기 위한 도구들)

리눅스 시스템에서 프로세스를 모니터링하고 제어하는 데 유용한 명령어 도구들을 소개한다. 이 도구들은 프로세스의 상태, 메모리 사용량, 시스템 콜 활동 등을 분석하는 데 매우 유용하다.

주요 도구 목록

strace

  • 실행 중인 프로그램 및 그 자식 프로세스들이 수행하는 모든 시스템 콜을 추적
  • 시스템 콜의 입력과 반환값까지 상세히 출력
  • 예: 파일 열기, 읽기, 쓰기, 포크, 종료 등 모든 시스템 호출
  • 정적 링크(static linking)로 컴파일하면, 불필요한 공유 라이브러리 관련 출력 없이 깔끔한 추적 가능

ps

  • 현재 시스템에서 실행 중인 프로세스 목록을 출력
  • 좀비 프로세스를 포함해 상태, PID, CPU 사용량, 메모리 사용량 등 다양한 정보 확인 가능

top

  • 실시간으로 시스템의 리소스 사용 현황을 보여줌
  • CPU, 메모리, 각 프로세스의 리소스 점유율 등 모니터링 가능

pmap

  • 특정 프로세스의 메모리 맵을 출력
  • 각 영역의 주소, 크기, 속성, 맵핑된 파일 경로 등을 확인할 수 있음\

/proc 파일 시스템

  • 가상 파일 시스템으로, 커널 데이터 구조를 텍스트 형태로 노출
  • /proc/<pid>/ 디렉터리를 통해 개별 프로세스의 상태, 명령행, 파일 디스크립터 등 접근 가능
  • 예: cat /proc/loadavg → 현재 시스템의 평균 부하(load average) 확인 가능

요약

도구 기능 요약
strace 시스템 콜 추적
ps 현재 프로세스 목록
top 실시간 리소스 모니터링
pmap 메모리 맵 조회
/proc 프로세스 및 시스템 정보 접근 가상 파일 시스템

이러한 도구들은 시스템 프로그래머가 디버깅, 성능 분석, 자원 추적에 있어 강력한 무기를 제공하며, 프로세스의 내부 동작을 눈으로 확인할 수 있는 수단을 마련해 준다.


8.8 Summary (요약)

Chapter 8에서는 컴퓨터 시스템 전반에 걸쳐 발생하는 예외적 제어 흐름(ECF, Exceptional Control Flow)에 대해 다루었다. 이 개념은 단순히 프로그램 흐름을 제어하는 것을 넘어서, 동시성(concurrency)을 실현하고 시스템 수준의 상호작용을 가능하게 하는 기반 메커니즘이다.

하드웨어 수준의 ECF

  • 예외(exception)는 프로세서에서 발생하는 제어 흐름의 갑작스러운 변화다.
  • 유형:
    • 인터럽트(interrupt): 외부 장치가 CPU에 이벤트 발생을 알릴 때 (비동기)
    • 폴트(fault): 복구 가능한 오류 (예: 페이지 폴트)
    • 어보트(abort): 복구 불가능한 오류
    • 트랩(trap): 시스템 콜 같은 의도적 예외 (동기)

운영체제 수준의 ECF

  • 운영체제는 ECF를 이용해 프로세스라는 추상 개념을 제공한다.
  • 각 프로세스는:
    1. 논리적 제어 흐름(logical control flow)을 가지고, CPU를 독점하는 것처럼 행동
    2. 개인 주소 공간(private address space)을 가지며, 메모리 고립 보장

사용자 수준의 ECF

  • 프로그램은 시스템 콜을 통해 프로세스를 생성, 기다림(wait), 종료, 다른 프로그램 실행, 시그널 처리 등을 수행한다.
  • 시그널 핸들링은 시스템마다 동작이 다를 수 있으므로 주의 깊은 구현이 필요

애플리케이션 수준의 ECF

  • C 언어의 setjmp, longjmp 함수는 함수 호출의 일반적인 규칙을 무시하고, 다른 함수로 직접 점프할 수 있게 해 줌
  • 예외 처리, 오류 복구 등에 사용 가능

핵심 개념 요약

계층 주요 ECF 메커니즘
하드웨어 인터럽트, 폴트, 어보트, 트랩
OS 프로세스 생성/전환, 시스템 콜
애플리케이션 시그널, 비지역 점프