시프 - 4주차 process

강준호·2024년 3월 28일

시스템프로그래밍

목록 보기
2/18

프로세스

프로세스의 정의 및 특성

프로세스란?

  • 프로세스는 실행 중인 프로그램의 인스턴스로 설명됩니다.
  • 프로세스는 실행흐름이지만, 관리가 되어지는 실행흐름들. 스케쥴링 단위.
  • 독립된 가상 메모리를 가지고 사용함. 서로 침범해서는 안돼.

Q. 사용해보면 프로세스>> CPU 이던데..?

  • 물리적으로는 1번에 1개만 수행하는데, 컨텍스트 스위칭으로 동시에 실행되는것처럼 보여짐.
  • 프로그램의 메모리에 올라가지 않아도 프로세스가 있을수있음.
  • 여기에는 프로그램의 명령, 사용된 메모리 및 액세스된 시스템 리소스가 포함됩니다.

UNIX 프로세스

  • UNIX 프로세스는 다른 프로세스로부터 보호됩니다:
    • 자체 메모리를 가짐
    • 전용 CPU에서 실행되는 것처럼 보임
    • 사용하는 시스템 서비스가 전용으로 제공됨
  • 이러한 환경을 유지하기 위해 하드웨어 지원이 필요합니다

실행 파일 형식

실행 파일 형식

  • 각 실행 파일은 특정 실행 파일 형식으로 저장됩니다.
  • 실행 파일 형식은 다음 정보를 제공합니다:
    • 프로그램에 필요한 환경 정보
    • 프로그램 코드 자체
    • 기타 메타데이터

ELF (Executable and Linking Format)

  • 많은 현대 시스템에서 ELF 형식을 사용합니다. (Windows는 PE, macOS는 Mach-O를 사용)
  • ELF 실행 파일과 라이브러리는 두 가지 유형의 정보를 포함합니다:
    • 객체를 로드하고 실행하는 데 필요한 정보
    • 객체를 링크하는 데 필요한 정보

로딩

  • 로딩은 실행 파일이나 공유 라이브러리를 메모리로 이동하는 과정입니다.
  • 리눅스에서 커널은 로딩을 시작하고, ld-linux.so가 이를 마무리합니다:
    • 커널은 ELF 실행 파일의 여러 부분을 제자리에 이동시킴
    • 로더를 제자리에 이동시킴
    • 커널은 로더를 호출하여 메모리 내 프로그램 데이터를 변경함
    • 로더는 프로그램의 시작 지점으로 점프

프로세스의 메모리 레이아웃

프로그램에서 프로세스로

  • 실행 파일이 메모리로 로드되어 프로세스가 됩니다.
  • 프로세스의 메모리 레이아웃은 ELF 섹션을 모방합니다.
  • 시스템은 로드된 레이아웃에 추가 의미를 부여합니다.
  • 대부분의 POSIX 시스템은 동일하거나 유사한 레이아웃을 사용합니다.

기본 레이아웃

  • 현대 시스템은 또한:
    • ELF 파일에 나타나지 않는 프로그램 코드인 공유 라이브러리를 매핑
    • 매핑된 섹션의 위치를 무작위화
  • 그러나 논리적 레이아웃은 동일하게 유지됩니다.
  • 특히 섹션의 순서는 유지됩니다.

텍스트 섹션

  • 텍스트 섹션은 실제 프로그램 명령어를 포함합니다.
  • 어셈블러는 ELF .text 섹션에 바이너리 기계 명령어를 배치합니다.
  • 커널은 텍스트를 프로세스의 메모리에 복사하고, 로더는 이를 실행할 준비를 합니다.

데이터 & BSS 섹션

  • 데이터 섹션은 컴파일 시 초기값이 정의된 변수와 상수를 포함합니다.
  • 링커는 이 데이터를 ELF .data 섹션에 삽입하고, 커널은 이를 프로세스의 메모리에 로드합니다.
  • BSS 섹션은 컴파일 시 값이 정의되지 않은 변수를 포함합니다.
  • 커널은 프로그램을 로드할 때 BSS를 위한 공간을 만듭니다.

스택과 힙

  • 스택: 함수 호출에 대한 지역 변수를 포함
  • 힙: 명시적으로 할당된 메모리를 포함
  • 스택과 힙은 모두 성장할 수 있습니다.
  • 따라서 힙과 스택 사이에 매핑되지 않은 공간이 존재합니다.

ELF 구조와 프로세스의 구조 비교

ELF 구조

ELF 파일이란?

  • ELF(Executable and Linking Format)는 실행 파일, 객체 코드, 공유 라이브러리 및 코어 덤프에 사용되는 표준 파일 형식입니다.
  • 주로 UNIX 및 UNIX-like 시스템에서 사용됩니다.

ELF 파일의 주요 섹션

  1. 텍스트 섹션 (.text)

    • 실제 프로그램 코드가 포함되어 있습니다.
    • 프로세서가 실행하는 기계 명령어가 포함됩니다.
  2. 데이터 섹션 (.data)

    • 컴파일 시 초기값이 정의된 변수와 상수들이 포함됩니다.
    • 문자열 상수, 전역 변수 등과 같은 데이터가 포함됩니다.
  3. BSS 섹션 (.bss)

    • 초기값이 정의되지 않은 변수들이 포함됩니다.
    • 예를 들어, 초기화되지 않은 전역 변수 등이 포함됩니다.

ELF 파일의 추가 섹션

  • 헤더: 파일의 전반적인 구조와 정보를 정의합니다.
  • 심볼 테이블: 프로그램의 변수와 함수 심볼에 대한 정보를 포함합니다.
  • 섹션 헤더 테이블: 파일에 포함된 각 섹션에 대한 정보를 포함합니다.
  • 프로그램 헤더 테이블: 실행 파일의 메모리 매핑 정보 등을 포함합니다.

프로세스의 구조

프로세스란?

  • 프로세스는 실행 중인 프로그램의 인스턴스입니다.
  • 프로세스는 실행 파일을 메모리에 로드한 후, 운영체제가 이를 관리합니다.

프로세스의 주요 메모리 영역

  1. 텍스트 섹션

    • 실행 파일의 .text 섹션이 메모리로 로드되어 실행됩니다.
    • 프로그램의 기계 명령어가 포함되어 있으며, 실행 시 실제로 프로세서가 실행합니다.
  2. 데이터 섹션

    • 실행 파일의 .data 섹션이 메모리로 로드됩니다.
    • 초기값이 설정된 전역 변수와 상수가 포함됩니다.
  3. BSS 섹션

    • 실행 파일의 .bss 섹션이 메모리로 로드됩니다.
    • 초기값이 설정되지 않은 전역 변수들이 포함됩니다.

추가 메모리 영역

  • 힙 (Heap)

    • 동적 메모리 할당을 위해 사용됩니다.
    • malloc()과 같은 함수 호출로 런타임 중에 메모리를 할당합니다.
  • 스택 (Stack)

    • 함수 호출 시 지역 변수와 반환 주소를 저장합니다.
    • 함수 호출 시마다 새로운 스택 프레임이 생성됩니다.

프로세스 환경

  • 프로세스 제어 블록 (PCB)
    • 프로세스의 상태, 레지스터 값, 프로그램 카운터, 메모리 관리 정보 등을 포함합니다.
    • 운영체제가 프로세스를 관리하기 위해 사용합니다.

비교

공통점

  • 텍스트 섹션: ELF 파일의 .text 섹션은 프로세스의 텍스트 섹션으로 로드되어 프로그램 명령어를 실행합니다.
  • 데이터 섹션: ELF 파일의 .data 섹션은 프로세스의 데이터 섹션으로 로드되어 초기값이 설정된 변수를 포함합니다.
  • BSS 섹션: ELF 파일의 .bss 섹션은 프로세스의 BSS 섹션으로 로드되어 초기값이 설정되지 않은 변수를 포함합니다.

차이점

  • 메모리 레이아웃

    • ELF 파일은 파일 형식으로 디스크에 저장되며, 프로세스로 로드되면 메모리 레이아웃이 달라집니다.
    • 프로세스는 추가적인 메모리 영역(스택, 힙)을 포함하며, 동적 메모리 할당과 함수 호출을 위한 공간이 필요합니다.
  • 실행 환경

    • ELF 파일은 단순히 실행 파일을 저장하는 형식이지만, 프로세스는 운영체제에 의해 관리되는 실행 중인 엔티티입니다.
    • 프로세스는 PCB와 같은 제어 구조를 통해 운영체제에 의해 관리됩니다.

운영체제와의 상호작용

  • ELF 파일
    • 파일 시스템에 저장되고, 실행 시 로더에 의해 메모리로 로드됩니다.
  • 프로세스
    • 실행 파일이 로드된 후, 운영체제의 스케줄러, 메모리 관리자, 시스템 호출 인터페이스와 상호작용합니다.

이 비교를 통해 ELF 파일이 단순히 프로그램의 실행 파일 형식인 반면, 프로세스는 실행 중인 프로그램으로서 더 복잡한 메모리 구조와 운영체제와의 상호작용을 포함하는 것을 알 수 있습니다.


프로세스 환경

프로세스 환경

  • 프로세스는 메모리 외에도 복잡한 환경을 가집니다.
  • 커널 서비스:
    • 시스템 호출
    • 파일 시스템
    • 신호
  • 생명 주기:
    • 생성
    • 새로운 프로그램의 실행
    • 종료

커널 서비스

  • 커널은 프로세스를 대신하여 서비스를 수행합니다.
  • POSIX 시스템은 다음을 제공합니다:
    • 메모리 격리
    • 전용 CPU의 환상
  • 이를 시행하기 위해 하드웨어 지원이 필요합니다.
  • 따라서 프로세스는 시스템 호출을 통해 커널에 접근을 요청해야 합니다.

커널/사용자 공간 분리

  • 커널은 POSIX 시스템의 모든 공유 자원을 관리합니다:
    • 메모리
    • 파일
    • 하드웨어 장치 (마우스, 키보드, 디스플레이 등)
  • 커널은 이들을 제어하기 위해 슈퍼바이저 모드에서 실행됩니다.
  • 프로세스는 사용자 모드에서 실행되며, 이를 사용자 공간(userspace)이라 부릅니다.

프로세스 생명 주기

  • 프로세스의 메모리 공간은 커널에 의해 생성됩니다.
  • 프로세스는 커널에 의해 생성됩니다.
  • 프로세스가 완료되면, 자원은 정리되어야 합니다:
    • 메모리
    • 파일
    • 기타 공유 자원
  • fork() 시스템 호출
  • 버츄얼 메모리 공간이 만들어지는데, A프로세스의 버츄얼 메모리 스페이스를 복사해서 만들어줌. 빈 깡통 공간이 아님!
  • 모든 프로세스마다 3개의 파일이 만들어져. stdin,stdout,error 이렇게 3개. 0,1,2 는 예약된 프로세스

시스템 호출

  • 각 시스템콜 마다 번호가 매핑되어있음. ex) 오픈은 1번 등등

  • 번호를 통해서 OS 에 요청할거임.

  • 레지스터에 저장을 한다.

  • 시스템콜을 할때는 스택을 사용할 수 없어 => 즉, arg 의 제한이 있어. cpu의 레지스터 개수는 정해져있으니. 이 개수만큼만 사용가능.

  • 특정 레지스터에 약속된 값을 저장해놓고, interupt 를 실행.

  • Ex) OS님 제가 read syscall 하고 싶습니다.

보호 도메인

  • 슈퍼바이저 모드와 사용자 모드는 보호 도메인입니다.
  • 보호 도메인 간의 전환에는 하드웨어 지원이 필요합니다.
  • 따라서 시스템 호출은 단순한 함수일 수 없습니다.
  • x86_64 리눅스 시스템에서 시스템 호출은 소프트웨어 인터럽트를 통해 접근합니다.

함수 호출

  • 일반 함수 호출:
    • 함수 인수를 특정 레지스터나 스택에 배치
    • 현재 프로그램 카운터를 스택에 배치
    • 프로그램 카운터를 호출된 함수의 첫 번째 명령어로 변경
  • 함수 완료 시:
    • 반환 값을 특정 레지스터에 배치
    • 이전 프로그램 카운터를 스택에서 가져옴
    • 프로그램 카운터를 호출 위치로 변경

시스템 호출 호출

  • 시스템 호출은 특별한 호출 방식을 가집니다:
    • 시스템 호출 번호를 특정 레지스터에 배치
    • 시스템 호출 인수를 다른 레지스터에 배치
    • syscall 프로세서 명령어를 호출
  • 그 후 CPU 하드웨어:
    • 보호 도메인 변경
    • 잘 알려진 위치로 점프
  • 시스템 호출 실행 후:
    • 반환 값을 특정 레지스터에 배치
    • sysret 프로세서 명령어를 호출
  • CPU 하드웨어:
    • 사용자 모드로 변경
    • 호출 함수로 점프

프로세스 생명 주기

프로세스 생성

  • fork() 시스템 호출: 부모 프로세스를 복제하여 새로운 프로세스를 생성.
    • 새로운 프로세스 ID(PID) 생성.
    • 부모 프로세스의 메모리 공간을 복사하여 새로운 프로세스에 할당.
  • fork()는 호출 프로세스를 복제하여 다음을 수행:
    • 새로운 프로세스 ID (PID)와 커널 구조 생성
    • 새로운 메모리 공간 생성
    • 현재 프로세스의 전체 내용을 새로운 메모리 공간으로 복사
    • fork() 호출에서 두 프로세스 모두 실행을 반환
  • 원래 프로세스에서 fork()는 새로운 PID를 반환
  • 새로운 프로세스에서 fork()는 0을 반환

프로세스 가족

  • 모든 POSIX 프로세스는 부모 프로세스를 가짐
  • 프로세스는 fork() 또는 posix_spawn()을 호출하여 자식 프로세스를 가질 수 있음
  • 부모 프로세스가 종료되면, 프로세스는 고아가 됨
  • 고아 프로세스는 init에 의해 채택됨
  • 모든 프로세스의 가족은 트리를 형성

fork()/exec() 모델

  • fork된 프로세스는 생성자의 동일한 프로그램을 실행해야 함
  • POSIX는 새로운 프로그램을 실행하는 exec() 시스템 호출 제공
  • 많은 시스템에서 다음을 위한 단일 호출 제공:
    • 새로운 프로세스 생성
    • 해당 프로세스에서 새로운 프로그램 실행
  • 현대 POSIX 시스템은 이를 위해 posix_spawn() 제공

프로세스 종료

  • 프로세스는 다음 시점에 종료:
    • exit() 시스템 호출을 호출할 때
    • main()에서 반환될 때
    • 특정 신호를 받고 처리하지 못할 때 (예: SIGSEGV)
  • 첫 두 경우에는 선택한 값을 반환:
    • exit()의 정수 인수
    • main()의 정수 반환 값
  • 세 번째 경우에는 신호에 의해

프로그램 실행

  • exec() 시스템 호출: 새로운 프로그램을 현재 프로세스 주소 공간에 로드하여 실행.
    • 현재 프로세스의 이미지가 새로운 프로그램 이미지로 대체됨.

시스템 리소스와의 상호작용

파일 시스템

  • 프로세스는 파일을 열고 읽거나 쓸 수 있음.
  • 파일 디스크립터를 통해 열린 파일을 추적.

시스템 호출

  • 프로세스는 커널 서비스에 접근하기 위해 시스템 호출을 사용.
  • 시스템 호출은 하드웨어 인터럽트를 통해 커널 모드로 전환됨.

신호 (Signals)

  • 프로세스 간 또는 커널이 프로세스에 신호를 보낼 수 있음.
  • 신호는 특정 이벤트(예: 종료, 예외 등)를 프로세스에 알림.

프로세스 환경 변수

  • 프로세스는 실행 시 환경 변수(environ)를 가짐.
  • getenv()와 setenv() 함수를 통해 환경 변수를 읽거나 설정할 수 있음.

작업 디렉토리

  • 프로세스는 현재 작업 디렉토리를 가짐.
  • chdir() 시스템 호출로 현재 작업 디렉토리를 변경할 수 있음.

프로세스 종료

  • exit() 시스템 호출: 프로세스가 종료될 때 호출.
    • 메모리, 파일 디스크립터 등 모든 자원을 정리하고 해제.
  • wait() 시스템 호출: 부모 프로세스가 자식 프로세스의 종료를 기다림.

요약

  • 프로세스가 뭔지
  • 프로세스가 실행될때 주변 환경이 어떻게 되는지
  • ELF 파일 포멧
  • fork 가 되서 불러지는 모양들

0개의 댓글