다음은 반효경 교수님의 ‘운영체제와 정보기술의 원리’ CH4. 프로그램의 구조와 실행를 읽고 정리한 내용입니다 🙌



🌩 1. 프로그램의 구조와 인터럽트

  • CPU에서 프로그램 명령을 실행하기 위해서는 프로그램 명령을 담은 주소 영역이 메모리에 올라가야한다.
    • 주소 영역은 code(프로그램 함수들이 기계어로 변환되어 저장), data(전역 변수 등 프로그램이 사용하는 데이터 저장), stack(함수 복귀 주소 및 데이터 임시 저장)으로 구분된다.
    • 함수를 호출하여 새로운 함수 위치로 점프할 때 다시 돌아올 주소를 스택 영역에 저장한다.
  • 인터럽트 동작 원리도 함수의 호출과 비슷하다.
    • 인터럽트 발생시 실행중이던 명령어의 위치를 저장한다. 처리루틴 후 해당 주소로 돌아와서 수행을 이어간다.
    • 이 주소는 운영체제가 관리하는 PCB에 저장된다.

🌩 2. 컴퓨터 시스템의 작동 개요

  • CPU는 매 시점 특정 주소에 존재하는 명령을 읽어서 그대로 실행한다.
  • CPU가 실행해야할 명령의 메모리 위치는 Program Counter라는 레지스터에 저장된다. 주로 PC는 바로 다음 주소를 가리켜 코드가 순차적으로 실행되도록 한다.
    • 반복문이나 함수호출 등의 주소이동이 있는 경우는 해당 주소를 가리키게 된다.
  • 프로그램 실행 중 입출력 등의 다른 연산이 이루어지면 각 장치의 컨트롤러와 로컬버퍼가 함게 동작하여 연산을 처리한다.
  • 만일 PC가 메모리의 운영체제 부분을 가리키고 있다면 CPU는 커널 모드에서 수행중이라고 한다.
  • CPU가 실행하는 명령은 일반명령과 특권명령을 나뉜다.
    • 일반명령은 모든 프로그램에서 수행하는 명령이다. 메모리 자료를 읽어서 CPU 연산 후 결과를 메모리에 쓴다.
    • 특권명령은 보안이 필요한 명령으로 각종 장치에 접근한다. 운영체제만 수행하며 모드비트로 구분된다.
  • 특권명령은 디스크파일접근, 화면출력 등을 수행할 수 있다. 사용자는 운영체제에 이 명령을 요청하여 대행하도록 system call을 한다.
    • system call이 호출되면 CPU는 해당 장치의 컨트롤러에 요청을 하고 데이터가 해당 장치의 로컬 버퍼에 담기면 컨트롤러가 CPU에 인터럽트를 발생시켜 작업 완료를 알린다.
  • CPU는 매 명령 수행 후 인터럽트 라인을 체크해 인터럽트가 일어났는지 확인한다.
    • 인터럽트 라인은 종류마다 다르다.

🌩 3. 프로그램의 실행

  • 프로그램이 실행된다는 것은

    1. 실행파일이 메모리에 적재된다.
    2. 프로그램이 CPU를 할당받고 명령을 수행하고 있다.

    라는 두가지 의미를 가진다.

  • 1번째 의미로 여러가지 프로그램이 메모리에 올라가 있을 수 있으니 여러 프로그램이 동시에 실행된다라고 할 수 있다.

  • 프로그램이 메모리에 적재될 때 일부분만 메모리에 나머지는 디스크에 내려가 있다.

  • 프로그램마다 독자적으로 주소공간을 가져 코드, 데이터, 스택 영역등으로 나뉜다.

    • 해당 공간을 가상메모리 virtual memory, 논리적 메모리 logical memory 라고 부른다.
  • 운영체제의 경우도 하나의 프로그램이다.

    • 각각의 코드, 데이터 스택주소 공간을 가지고 있다.
    • 하드웨어와 사용자의 중간이기 때문에 1) CPU, 메모리 자원을 관리하는 부분과 2) 사용자에게 편리한 인터페이스 제공하기위한 부분이 나뉜다.
    • 시스템 콜, 인터럽트 처리 부분도 포함된다.
  • 커널의 데이터 영역 - 각종 자원을 관리하는 자료구조가 저장

    • CPU, 메모리 하드웨어 자원 관리
    • 수행 중인 프로그램(소프트웨어) 관리 ⇒ 수행중인 프로그램을 프로세스라고 부른다.
      • 각 프로세스의 상태, CPU 사용 정보, 메모리 사용 정보 등을 담은 PCB를 둔다.
  • 커널의 스택 영역 - 함수호출 시 복귀 주소를 저장

    • 현재 수행 중인 프로세스마다 별도의 스택을 두어 관리
      • 프로세스마다 특권명령을 수행하려고 system call을 하고 system call 안에서 다른 함수를 호출할 경우 복귀 주소가 커널 내 주소가 되기 때문
      • 커널은 공유 코드이므로 각 사용자 프로그램이 커널 함수에 접근할 수 있으므로 일관성 유지를 위해 각 프로세스마다 스택을 따로 둠.
    • 요약
      • 사용자 프로그램 내에서 함수호출 시 해당 프로그램의 스택에 복귀 주소를 저장
      • 시스템 콜이나 인터럽트 발생으로 운영체제가 제어하면 프로그램 복귀 정보를 PCB에 저장
      • 커널 내에서 이루어지는 함수호출은 각 프로세스의 커널스택에 복귀 정보를 저장
        • 직전에 수행중이던 프로세스의 커널스택에 저장

🌩 4. 사용자 프로그램이 사용하는 함수

  1. 사용자정의 함수 - 프로그래머 본인이 작성
    1. 코드 영역에 기계어 형태
  2. 라이브러리 함수 - 다른 누군가 미리 작성
    1. 코드 영역에 기계어 형태
  3. 커널 함수 - 운영체제 커널의 코드에 정의된 함수
    • system call 함수, 인터럽트 처리 함수
    • printf()와 같은 함수는 라이브러리 함수고 내부에서 system call을 한다.
    • system call은 사용자가 운영체제 CPU를 넘겨서 실행하는 것이다.
    • system call 또한 인터럽트 라인을 세팅하는 방법을 사용한다.

🌩 5. 인터럽트

  • CPU는 대부분 명령을 순차적으로 진행한다. 매 명령마다 인터럽트 라인을 체크하고 발생했다면 제어권을 운영체제에게 넘겨 인터럽트 처리루틴에 따라 처리하고 다시 돌아온다.
  • 인터럽트 처리 중 다른 인터럽트가 발생 한 경우
    • 원칙적으로 위 경우는 데이터 일관성을 위해 허용하지 않는다.
    • 예외적인 경우는 인터럽트 처리루틴 중 더 시급하거나 CPU가 당장 필요한 일이 발생한 경우이다.
  • 인터럽트마다 중요도가 다르므로 중요도가 더 높은 인터럽트는 발생을 허용해 우선순위가 높은 인터럽트부터 처리하도록 한다.

🌩 6. 시스템 콜

  • 시스템 콜은 프로세스가 가지고 있는 자신의 주소 공간 내의 호출이 아닌 커널 (다른 프로그램 주소 공간) 함수를 호출하는 것이다.
    • 이 경우 프로그램 자신이 스스로 인터럽트 라인을 세팅한다.
  • 입출력 시스템 콜인 경우 CPU 명령 수행보다 많은 시간이 소요되므로 CPU가 그 시간동안 대기하고 있는 것은 자원의 낭비이다.
  • 또한 입출력을 요청한 프로그램에게 CPU를 다시 넘겨주는 것은 필요한 데이터가 없으므로 옳지 않다.
  • 따라서 한 프로그램이 입출력을 요청한다면 다른 프로그램에게 제어권을 넘겨주어 실행되도록 한다.
  • 입출력 작업이 완료되었을 경우 인터럽트 처리루틴
    • 해당 인터럽트는 하드웨어 인터럽트이다.
    • 로컬버퍼의 내용을 메모리로 복사하고 해당 프로세스가 다시 CPU를 획득할 수 있는 권한을 준다.
    • 해당 프로세스가 작업 큐에 삽입되어 제어권이 돌아오게 한다.
  • 정리 - 프로세스가 CPU를 빼앗기는 경우 2가지
    1. 타이머에 의한 인터럽트 발생 → 한 프로세스의 독점을 방지
    2. 시스템 콜에 의한 인터럽트 발생 → 운영체제 함수 호출이 필요한 경우 실행

🌩 7. 프로세스의 두 가지 실행 상태

  • 사용자 모드에서 실행상태 (user mode running) - 자신의 주소 공간의 코드 실행
  • 커널 모드에서 실행상태 (kernel mode running) - 커널의 시스템 콜 함수 실행
    • 이 경우에도 커널이 실행 상태에 있다고 하는 것이 아니라 해당 프로세스가 실행상태에 있다고 한다.
    • 해당 프로세스가 필요한 일을 처리하는 것이기 때문이다.
    • 프로세스 A가 커널모드에 실행 중 이라고 표현한다.
  • 프로그램 실행이 끝날 때는 커널 모드로 프로그램을 종료한다.