[운영체제] 4. Limited Direct Execution

만두·2024년 1월 30일
0

운영체제

목록 보기
4/13

control해서 CPU를 얼마나 효율적으로 가상화할 수 있을까?

OS는 time sharing을 통해 physical CPU를 공유할 필요가 있다.

  • 문제
    • Performance : 우리는 어떻게 추가적인 오버헤드 없이 가상화를 구현할 수 있을까?
    • Control : 어떻게 우리는 CPU 컨트롤을 유지하면서 효율적으로 프로세스를 실행시킬 수 있을까?

Direct Execution

  • 단순히 CPU에서 직접적으로 프로그램을 실행한다고 가정해보자.

  • OS에서 프로세스 리스트에서 entry를 생성하고
  • 프로그램의 메모리를 할당하고
  • 메모리에서 프로그램을 적재하고
  • argc, argv로 stack을 설정한다음
  • 레지스터를 초기화하고
  • main 함수를 불러서 실행하면
  • Program에서 main함수를 실행하고
  • return을 불러서 실행하면
  • OS에서 다시 프로세스의 메모리를 해제하고
  • 프로세스 리스트에서 제거한다.
💡 실행중인 프로그램에서 limits(제한) 없이 os는 어느것도 제어할 수 없다. 그저 Library가 될 뿐이다.

Restricted Operation

문제 1. 제한된 명령어

만약 프로세스가 디스크에서 I/O 요청하는 이슈라던가 CPU 또는 메모리같은 시스템 자원에 더 많은 접근을 얻는 제한된 명령어 종류를 수행하기 원한다면?

솔루션 : 보호되는 control transfer를 사용한다.

  • User mode: 하드웨어 자원에 대한 완전한 접근을 가지지 않는 어플리케이션
  • Kernel mode: OS는 기계의 모든 자원에 대한 접근 권한을 가짐.

System call

  • kernel이 조심스럽게 특정 주요 기능을 유저 프로그램에게 보여주는것을 허락한다. 예를들면,
    • 파일 시스템 접근
    • 프로세스 생성 및 제거
    • 다른 프로세스와의 의사소통
    • 더 많은 메모리 할당

Trap Instruction

  • kernel로 jump한다.
  • privilege level(권한 레벨)을 kermel mode로 올린다.

Return-from trap instruction

trap instruction으로부터 얻는 return 값은?

  • user program이라고 불리는 곳으로부터 리턴된다.
  • privilege level을 user mode로 다시 낮춘다.

trap은 어느 코드가 OS안에서 실행되어야하는지 어떻게 아는걸까?

  • trab table과 trab handler가 있기 때문
  • trab table
    • interrupt descriptor table 또는 interrupt vector table 라고도 불림
  • trap handler
    • 코드는 프로그램이 trap 명령어를 실행할 때 실행되어야 한다.

System-call number

  • 각각의 시스템 콜은 시스템 콜 number가 배정되어 있다.
  • 따라서 user code는 레지스터에 원하는 시스템 콜 번호를 배치할 책임이 있다.


System call Handler

→ 원래 이렇게 유저 프로그램에서 printf 함수 실행하면 해당 라이브러리를 찾고 그 안에 시스템콜 원형인 write를 찾아서 kernel모드에서 write 시스템 콜을 수행하고 이것이 terminal output에 보인다.

→ glibc에서 찾은 것은 결국 system call stub에서 찾을 수 있고, 잘 보면 write, printf는 write 시스템콜을 strcpy는 그 자체 open, fdopen은 open 시스템콜을 kernel level에서 찾아서 수행한다.

위 사진은 fork() 시스템 콜을 수행했을 때의 그림이다.

먼저 User program에서 fork() 함수를 수행하면 libc.a라는 라이브러리 파일에서 fork()를 찾는다.

movl 2, %eax

int $0x80

이 코드를 확인할 수 있는데, 여기서 eax는 레지스터이고 int 뒤에 쓰인 것은 Interrupt vector table에 저장된 system call 주소이다.

  • 참고로 아까 interrupt vector table의 다른 말 2가지 더 있었다. = interrupt descriptor table = trap handler

하여튼 Interrupt vector table의 0x80번지를 살펴보자. 이 함수를 통해 kernel에서 system call entry에 접근할 수 있고, 여기서 정의된 sys_call table에서 아까 %eax로 가져온 2라는 값이 system call table의 2번에 있다. 2번에 저장된 sys_fork() 에서 fork의 구현이 가능하다.



Limited Direction Execution Protocol

  1. os에서 trap table을 초기화한다.

  2. process list를 위해 entry 를 생성한다.

    프로그램의 메모리를 할당한다.

    메모리에 프로그램을 적재한다.

    argv로 user stack을 설정한다.

    reg, PC로 kernel stack을 채운다.

  3. kernel stack에 의해 레지스터가 다시 저장된다.

    user mode로 이동하고, main으로 jump한다.

  4. user mode에서 main함수를 실행하고 system call → os로 trap

  1. 위 과정을 계속 반복하다가

    program에서 exit 호출을 trap하면서 return되면

  2. OS에서 프로세스의 메모리를 해제하고

    프로세스 리스트에서 제거한다.

문제 2. 프로세스 간 스위칭

  • 어떻게 OS는 프로세스 사이에서 스위치 하기 위해 cpu의 제어권을 다시 얻을 수 있을까?
    • 협력적인 접근법 : Wait for system calls
    • 비협력적인 접근법 : The OS takes control

→ system call을 기다리면서 제어권을 주기를 기다리고, 프로세스가 정말로 잘 주면 좋겠지만, 비협력적일 수도 있다. 이럴땐 OS가 강제로 빼앗아야 한다.


Wait for system calls

협력적인 접근법 : 시스템 콜을 기다린다.

프로세스는 주기적으로 CPU를 포기한다. yield와 같은 시스템콜을 만듦으로써.

  • OS는 몇몇 다른 일을 수행하기로 결정한다.
  • 어플리케이션이 불법적인 일을 할 때 OS로 제어권을 이전하기도 한다.
    • 0으로 나누거나
    • 엑세스 할 수 없는 메모리에 접근하거나
  • ex) Mancintosh OS의 초기 버전, 구 제록스 알토 시스템
💡 process는 무한 루프에 갇힌다. → **Reboot the machine**

OS Takes Control

비협력적인 접근법 : OS가 접근권을 가진다.

  • Timer Interrupt → 커널을 실행한다.
    • 부팅 시퀀스 중에 OS가 타이머를 시작한다.
    • 타이머는 몇 밀리초마다 인터럽트를 발생시킨다.
    • 인터럽트가 발생한 경우
      • 현재 실행중인 프로세스가 중지된다.(halt)
      • 프로그램의 상태를 충분히 저장한다.
      • OS에서 미리 구성된 인터럽트 핸들러가 실행된다.
💡 Timer Interrupt는 OS가 cpu에서 다시 실행할 능력을 준다.

Saving and Restoring Context

  • Scheduler는 의사를 결정한다.
    • current process를 계속해서 실행할지 말지, 또는 다른 것으로 바꿀지

    • 만약 스위치하기로 결정한다면 OS는 context switch를 실행한다.


Context Switch

  • 어셈블리 코드의 low-level
    - current process의 몇몇 레지스터 값을 그 커널의 stack에 저장한다.
    - 일반적인 purpose register와
    - PC 값과
    - kernel stack pointer 들을
    - 커널 스택에서 곧 실행될 프로세스를 위해 몇가지를 다시 저장한다.
    - 곧 실행될 프로세스를 위해 커널 스택으로 스위치한다.

→ trap table을 초기화하고 interrupt timer를 시작한다.

→ 프로세스 A를 실행하다가

→ Hardware에서 Timer interrupt가 발생하면

→trap을 처리하고 switch 함수를 실행한다.

→ 현재 실행중인 프로세스의 레지스터 값들을 kernel의 stack에 저장한다.

동시성에 관한 걱정?

interrupt나 trap handling 하는 중에 무언가 발생한다면 다른 인터럽트가 발생할까?

OS 는 이 상황들을 다룬다.

  • interrupt processing 하는 도중 interrupt는 불가능하다.
  • 내부 데이터 구조에 대한 동시 접근을 보호하기 위해서 여러가지 정교한 잠금 방식을 사용한다.
profile
아무것도 모르는 말하는 감자 입니다

0개의 댓글

관련 채용 정보