[운체] 오늘의 삽질 - 0729

방법이있지·2025년 7월 29일
post-thumbnail

키워드 정리

커널

  • 운영체제의 핵심 기능을 담당하는 부분
    • 프로세스 관리, CPU/메모리 등 자원 접근 및 할당, 파일 시스템 관리...ㄴ
  • 운영체제 서비스 중 커널에 포함되지 않는 서비스도 있음
    • e.g., GUI(그래픽 유저 인터페이스)

사용자 / 커널 모드

  • 사용자 프로그램이 하드웨어 자원에 접근하기 위해선, 운영체제를 통해서 접근해야 함
    • CPU, 메모리, 하드 디스크 등 하드웨어 자원의 보호 목적
    • 운영체제 코드를 실행하여 접근이 이루어짐
  • CPU는 명령어를 사용자 모드 OR 커널 모드로 실행 가능
    • 플래그 레지스터 내 슈퍼바이저 플래그의 값에 따라 모드 결정
  • 사용자 모드: 운영체제 서비스를 제공받을 수 없음
    • 일반적인 사용자 프로그램이 실행되는 모드
    • 커널 영역의 코드를 실행할 수 없음
    • 입출력 명령어 등, 하드웨어 자원에 접근하는 명령어를 실행할 수 없음
  • 커널 모드: 운영체제 서비스를 제공받을 수 있음
    • 운영체제 코드가 실행되는 모드
    • 커널 영역의 코드를 실행할 수 있음

시스템 콜

  • 운영체제 서비스를 제공받기 위해, 사용자 -> 커널 모드로 전환하는 요청
  • 사용자 모드로 실행되는 프로그램은, 시스템 콜을 커널 모드로 전환하여 운영체제 서비스를 제공받음
  • 일종의 인터럽트: 하드웨어 인터럽트(타이머 인터럽트 등)와 비교해서 소프트웨어 인터럽트로도 불림
  • e.g., 하드 디스크에 데이터를 저장하는 시스템 콜
    • 사용자 모드로 실행 시, 응용 프로그램은 하드 디스크에 직접 접근 불가
    • (1) 하드 디스크에 데이터를 저장하는 시스템 콜 요청 -> 커널모드로 전환
    • (2) 하드 디스크에 데이터를 저장하는 운영체제 코드를 실행해, 하드 디스크에 접근
    • (3) 접근이 끝나면 사용자 모드로 복귀해 프로그램 실행 재개

시스템 콜의 종류

호출기능
fork()새 자식 프로세스 생성
execve()프로세스 실행 (현재 프로세스의 메모리 공간을 새로운 프로그램의 내용으로 덮어씌움)
exit()프로세스 종료
wait()자식 프로세스의 종료까지 대기
open()파일 열기
close()파일 닫기
read()파일 읽기
write()파일 쓰기

인터럽트 / 예외

예외원인동기 / 비동기핸들러 반환 후
하드웨어 인터럽트
(Interrupt)
외부 장치의 신호(타이머, 입출력장치)비동기다음 명령어로 진행
소프트웨어 인터럽트
(trap)
시스템 콜 등 의도된 예외동기다음 명령어로 진행
폴트
(fault)
복구 가능한 오류(페이지 폴트)동기오류 복구 시, 현재 명령어 유지
복구 실패 시, 프로그램 종료
중단
(abort)
복구 불가능한 치명적 오류동기프로그램 종료
  • 비동기: 예외의 원인이 명령어 실행이 아님. 통칭 인터럽트
  • 동기: 예외의 원인이 명령어 실행임. 통칭 예외
  • 예외 발생 시 운영체제의 인터럽트 핸들러가 실행됨
    • 특정 예외가 발생했을 때, 이에 처리 및 대응하는 코드
    • 운영체제 코드를 실행해야 하므로, 사용자 모드 -> 커널 모드로 전환이 이루어짐
  • 인터럽트 발생 및 처리 과정
    • (1) CPU가 예외를 감지 후 예외 번호를 계산
    • (2) Interrupt Descriptor Table에서 예외 번호에 해당하는 예외 핸들러 주소를 확인해 진입
    • (3) 커널 모드로 전환 -> 커널 스택에 리턴 주소, 현재 레지스터 값 등 푸시
    • (4) 예외 핸들러 코드 실행, 예외 상황을 처리
    • (5) 커널 스택에 저장된 값을 팝해 복원한 뒤 리턴 주소 사용해 사용자 모드로 복귀
  • 하드웨어 인터럽트의 경우, 인터럽트 플래그가 활성화되어 있을 때만 인터럽트 요청 수용
    • 단, 정전이나 하드웨어 고장으로 인한 인터럽트는 막을 수 없음 - 무조건 수용(non-maskable interrupt)

세그멘테이션 / 페이지 폴트

  • General Protection Fault (예외번호 13)
    • 흔히 말하는 Segmentation Fault는 General Protection Fault에 포함됨
    • 정의되지 않은 영역 (e.g., NULL 포인터) / 읽기 전용 코드 영역 / 사용자 영역에서 커널 메모리 접근 등, 잘못된 메모리 접근 시 발생
    • 일반적으로 복구하려고 시도하지 않음, 프로그램 종료 선택
  • Page Fault (예외 번호 14)
    • CPU가 가상 주소에 접근할 때, 해당 주소가 현재 메모리에 매핑되어 있지 않을 때 발생
  • 리눅스 기준, MMU가 가상주소를 번역하는 과정에서 Page Fault 발생 시
    • (1) 가상주소가 유효한 메모리 영역에 위치해 있는지 판단
      • 메모리 영역은 heap, stack, text, mmap을 뜻함 -> 해당 주소가 어떤 영역에 속하는지 먼저 확인
      • 유효하지 않은 경우, Segmentation Fault(GPF의 일종) 발생
      • NULL 포인터 참조 시 무조건 발생, 미할당 포인터 참조 시에도 유효한 영역 외일 수 있으므로 발생 가능
    • (2) 해당 영역 내 접근 권한이 있는지 판단
      • 접근 권한이 없으면 General Protection Fault로 프로세스 중단
      • e.g., 코드 영역은 쓰기 연산 금지 -> 해당 영역에 쓰기 시도 시
      • e.g., 사용자 프로세스는 커널 영역의 데이터를 읽지 못함 -> 해당 영역에 접근 시도 시
    • (3) 위 조건 모두 충족 시, 정상적인 Page Fault 루틴이 처리
      • 새로운 물리 프레임으로 스와핑하고, 페이지 테이블을 갱신

사용자 스택, 레지스터

  • 사용자 스택
    • 함수 호출 시 필요한 정보를 저장하는 메모리 내 공간
      • 함수 인수, 리턴 주소, 지역 변수 등...
    • 스택 프레임: 각 함수가 사용하는 스택 내 저장 공간
    • e.g., 인수의 경우 최대 6개까지 레지스터로 전달 -> 나머지는 스택으로 푸시
    • 단, 시스템 콜의 경우 사용자 스택이 아닌 커널 스택에 값들이 푸시됨에 유의
  • rax 레지스터: 리턴 값을 저장하는 용도의 범용 레지스터

기타 키워드

  • file descriptor: 운영체제가 파일 등 입출력 자원을 식별하기 위해 사용하는 정수 값
    • open() 시스템 콜로 할당되며, 이 값을 통해 read(), write() 등 시스템 콜로 자원에 접근
  • atomic operation: 도중에 중단되거나 다른 작업과 섞이지 않고, 한 번에 완전히 수행되는 연산
    • write(), read() 등 시스템 콜은 atomic하게 동작하도록 구현됨 -> race condition 없이 사용 가능
    • 핀토스에서 global lock을 걸어주고 시스템 콜을 처리했던 이유는, 이를 구현하기 위해서
  • 32bit OS vs 64bit OS
    • 32비트, 64비트 -> 가상 주소값을 몇 비트로 나타내는지
    • 32비트 OS에선 최대 (2^32)개 주소 -> 4GB 메모리 주소 가능
    • 64비트 OS에선 최대 (2^64)개 주소 -> 수십~수백 TB까지 가능
    • 더 많은 데이터 사용과 빠른 데이터 사용에 유리

퀴즈 정리

커널 모드에서 실행될 수 있는 작업 및 사용자 모드에서 실행되지 않는 이유

  • 커널 모드에서는 파일 입출력, 프로세스 스케줄링, 메모리 매핑 등 작업이 실행된다. 사용자 프로그램이 직접적으로 운영체제의 하드웨어 자원에 접근하는 것을 막기 위해, 보안과 안정성을 위해 사용자 모드에서는 실행되지 않는다.
    • e.g., 다른 프로세스를 임의로 조작하거나, 할당되지 않은 메모리 공간에 접근하는 행위를 방지할 수 있다.

MLFQS를 사용하는 이유

  • 프로세스의 우선순위가 고정되는 기존 스케줄러에서는, 우선순위가 높은 프로세스가 계속 CPU를 점유하면 낮은 프로세스가 전혀 실행되지 않는 기아 현상이 발생할 수 있다. MLFQS는 프로세스를 우선순위에 따라 여러 큐에 배치하는데, 일정 시간마다 우선순위를 재계산해 큐를 재조정하기 때문에 기아 현상을 방지할 수 있다.

fork vs exec

  • fork는 부모 프로세스를 복제하여 독립적인 자식 프로세스를 생성한다. exec는 현재 프로세스의 코드, 데이터 등 메모리 공간을 새로 실행할 사용자 프로그램의 내용으로 덮어씌우며, 새로운 프로세스를 생성하지 않는다.

유저 프로그램에 스택이 높은 -> 낮은 주소, 힙이 낮은 -> 높은 주소로 성장하도록 설계된 이유

  • 메모리상 힙 영역과 스택 영역 사이 미할당 영역을 유동적으로 사용할 수 있게 하기 위해서이다. 예를 들어, 힙이 너무 커져도 스택이 아직 작으면, 중간 공간이 남아 있는 한 둘 다 확장 가능하다.

#ifdef 함수의 장단점

  • #if defined(매크로 상수명) 대신 #ifdef(매크로 상수명)이라고 줄여 사용할 수 있어 코드가 간결해진다. 하지만 #if 를 사용할 때와 달리, &&|| 등 조건식을 사용하여 다른 조건문과 함께 사용하는 것이 불가능해진다.
profile
뭔가 만드는 걸 좋아하는 개발자 지망생입니다. 프로야구단 LG 트윈스를 응원하고 있습니다.

0개의 댓글