Concepts/OS

Limited Direct Execution

ocwokocw 2024. 5. 25. 23:35

- 출처: Operating System - Three Easy Pieces

 

- 개요

CPU 가상화의 기본적인 개념은 하나의 process를 잠시 동안 실행하고, 그 후 다른 process 를 실행하는식으로 진행하는 time sharing 이다.

 

가상화의 가장 중요한 요소는

  • performance: 추가적인 overhead 없이 가상화 구현
  • control: CPU 에 대한 제어를 하면서 효율적으로 process 실행한다. 제어를 하지 않으면 하나의 process 가 machin 을 영원히 점유하거나 접근하면 안되는 자원에 접근할 수 있게 된다.

결국 올바른 제어를 하면서 좋은 성능을 내는것이 OS 의 주요 과제이다.


- Limited Direct Execution

프로그램을 가장 빠르게 실행하는 방법은 CPU 상에서 직접 실행("direct execution") 하는 것이다. 이를 그림으로 나타내면 아래와 같다.

이렇게 간단한 과정을 거쳐 프로그램을 실행할 수 있지만 문제가 좀 있다.

  • OS가 프로그램이 원하지 않는 동작을 하지 않도록 제어하면서 효율적으로 프로그램을 실행할 수 없다
  • process 를 실행할 때 OS 가 어떻게 실행중인 process 를 멈추고 다른 process 가 실행되도록 전환시킬 수 있는가?

- 문제1) 제한된 연산

위에서 단순히 프로그램을 직접 실행("direct execution")하는 방식은 성능면에서는 분명 가장 좋은 방법이다. 하지만 process 가 제한된 연산(ex - I/O 요청을 disk 에 보내거나 CPU나 memory 같은 시스템 자원을 더 많이 요청)을 수행해야 한다면 어떨까?

 

process 가 원하는 연산을 단순히 허락하면 안될까? 라는 의문이 있을 수 있다. 하지만 파일시스템의 경우만 보더라도 읽거나 쓸 수 있는 권한이 있기 때문에 단순히 process 가 disk 를 모두 읽을 수 있도록 하는 방식은 위험하다. 이를 해결하기 위해 processor mode를 도입해야 하는데 이것이 한번쯤은 들어봤을법한 "user mode"와 "kernel mode" 이다.

  • user mode: user mode 에서 실행되는 code 는 할 수 있는 행위가 제한된다. process 는 I/O 요청을 발행할 수 없으며, 이를 시도하면 exception이 발생하고 OS는 이런 process 를 종료한다.
  • kernel mode: I/O 발행과 모든 제한된 명령어 권한 작업을 실행할 수 있다. 

위의 설명을 보고 의아하다는 생각이 들것이다. 우리가 흔히 실행하는 프로그램들은 disk 에 정보를 저장하거나 읽어올 수 있는데 I/O 요청을 발행할 수 없다니 이게 무슨말인가? 이를 가능하게 하기 위해서는 H/W 가 프로그램에게 "system call" 을 실행능력을 제공한다.

 

"system call" 을 실행하기 위해서 프로그램은 아래 과정을 거친다.

  • 특별한 명령어 "trap" 실행
  • kernel 로 진입하여 실행 권한이 kernel mode로 상승
  • 필요한 작업 수행
  • 모든 필요한 작업이 수행되고 나면 OS는 특별한 명령어 "return-from-trap" 을 호출
  • 프로그램으로 복귀되어 실행권한이 user mode로 하강

H/W는 trap을 실행할 때 호출자의 register 정보를 저장하여 return-from-trap 호출시 정확한 지점을 복귀할 수 있도록 해야한다. 예를 들어 x86 에서는 processor가 PC(program counter), flag 와 기타 register 들을 process 당 "kernel stack" 에 넣는다. 그 후 return-from-trap 이 실행되면 이 정보들을 꺼내서 user mode 로 프로그램을 재개한다.

 

그런데 trap 이 OS 에서 어떤 코드를 수행해야할지 어떻게 알 수 있을까? kernel 은 부팅 시점에 trap table 을 초기화 한다. OS 는 H/W 에게 특정 이벤트 발생시 어떤 코드를 실행해야 하는지 알려주는데 예를 들면 하드디스크 인터럽트, 키보드 인터럽트, 프로그램의 system call 호출등과 같은 것들이다. OS 는 H/W 에게 이런 trap handler 들의 위치를 알려준다.

 

H/W 에게 trap table 의 위치를 알려주는 연산은 매우 강력하기 때문에 user mode 에서 이 연산을 실행할 수 없다.

 

 

위의 타임라인 그림은 process 가 kernel 로 진입하거나 빠져나올 때 register 들이 저장되고 복원되는 kernel stack 이 process 마다 존재한다고 가정한것이다. 타임라인은 크게 2 부분, trap table 을 초기화하는 부분과 kernel 로 부터 프로그램이 시작되고 종료되는 부분으로 나눌 수 있다.


- 문제2) Process 간 전환

process 를 전환한다는건 아주 간단하게 생각해보면 하나의 process 를 멈추고 다른 process 를 실행하면 되는것 아닌가? 라는 생각이 들 수 있다. 하지만 process 가 CPU 상에서 돌아간다는건 잘 생각해보면 OS 가 실행되지 않고 있다는 뜻이다. OS 가 실행되지 않으면 process 간 전환을 누가 관리하고 제어할까?

 

협력적인 접근법: system call 대기

이 문제를 해결하기 위해 한 가지 방법을 생각해보자. 바로 OS 가 process 를 신뢰하는 방식이다. 이 방식에서는 process 가 system call 을 호출함으로써 CPU 제어권이 OS 로 전이된다. 예를 들면 process 에서 file 을 읽거나, 다른 기기에 메시지를 전송하거나 신규 process 를 생성하는 등과 같은 system call 을 호출하는 경우이다. 또한 어플리케이션이 하면 안되는 행위를 하는 경우, 예를 들어 0 으로 나누거나 접근하면 안되는 메모리 영역에 접근하는 경우도 trap 을 발생시켜 OS 로 제어권이 전이된다.

 

그런데 만약 process 가 계속해서 돌아가서 system call 을 발생시키지 않으면 어떻게 될까? OS 는 평생 제어권을 얻을 수 없을까?

 

비 협력적인 접근법: OS 가 제어

앞의 접근법에서 process 가 계속 CPU 를 점유하는 상황은 분명 문제가 있다. 이를 해결하기 위해 "timer interrupt" 라는 개념을 도입한다. 일정 주기마다 인터럽트가 걸릴 때 실행중인 process 가 중지되고 미리 설정된 OS 의 인터럽트 handler 가 실행되면서 OS 가 제어권을 가져가는 방식이다.

 

이 방식은 process 가 영원히 CPU 를 점유하지 않기 때문에 비교적 OS 가 안심하고 user 프로그램을 실행할 수 있다. 


- Context 의 저장과 복원

OS 가 협력적인 접근법을 취하건 비 협력적인 접근법을 취하건 제어권을 획득하면 둘 중 택1 해야한다.

  • 현재 실행중인 process 를 계속해서 수행
  • 다른 process 로 전환

이는 "scheduler" 가 결정한다.

 

만약 다른 process 로 전환하기로 결정했다면 OS 는 "context switch" 를 실행한다. context switch 는 아주 간단하게 요약하면 현재 실행중인 process 를 위한 regiter 들을 저장하고 곧 재개될 process 의 register 들을 복원하는것이다. 

 

현재 실행중인 process 의 context 를 저장하기 위해서 OS는 우선 general purpose register, PC, ketnel stack pointer 을 저장한다. 그리고 곧 실행될 register, PC, kernel stack 을 복구한다. stack 을 전환하면 곧 실행할 process 의 context 로 전환되고 OS 가 return-from-trap 명령어를 실행하면 마침내 process 가 전환된다.


- Summary 

아무런 제약없는 가장 직관적인 방법인 "Direct Execution" 부터 "Limited Direct Execution" 까지의 과정을 살펴봤다. 결국 직접 실행을 제한해야 하는 이유는 OS 도움없이 process 가 할 수 있는 것을 제약하도록 H/W 를 설정한 후 process 를 실행하는것이라고 할 수 있다.