프로그램 실행방법 중 하나로 direct execution이 있다.
프로그램을 기계어로 컴파일하여 직접 실행하는 방식이다.
그 외에도 인터프리터, 자바 가상머신, just in time 컴파일러(기본적으로 인터프리터, 빈번한 부분은 실시간으로 컴파일), 가상머신 등이 있다.
OS가 CPU가상화를 구현할 때 고려해야하는 것 중 성능과 함께 제어권문제를 빼놓을 수 없다.
제어권을 상실하면 한 프로세스가 영원히 실행될 수 있고, 접근해서는 안되는 정보에 접근할 수 있다.
그래서 프로세스는 1.제한된 연산, 2.프로세스간 전환 이 가능하도록 실행되어야한다.
이를 준수하기 위해 RDE(restricted direct execution)기법은 다음과 같이 구현할 수 있다.
제한된 연산을 수행하다가, 필요하다면 미리 정의된 형태의 작업이 제공될 수있다.
프로세스의 특권레벨(privilege level)은 크게 사용자모드 또는 커널모드로 구분될 수 있다.
예를 들어 x86 instruction set에서는 0~3의 4가지의 특권레벨이 존재한다.
특권 레벨 0은 사용자모드, 3은 커널 모드이다.
사용자모드의 프로세스는 일부 자원에 대한 접근이 제한되어있다.
커널모드의 프로세스는 모든 자원에 대한 접근이 가능하며, 특권 명령(privileged instruction)을 실행할 수 있다.
사용자모드에서 제한된 연산을 실행해야할 경우, 시스템콜이라는 API(Application Programming Interface. application과 다른 sw간의 상호작용을 위한 interface)를 사용하여 제한된 연산이 허용될 수 있다.
초기 UNIX는 약 20개의 시스템콜을 제공했고, 현대의 OS에서는 수백개의 시스템콜을 제공한다.
시스템콜을 통해 파일 시스템 접근, 프로세스 생성 및 제거, 다른 프로세스와의 통신 및 메모리 할당이 가능하다.
사용자모드의 프로세스가 시스템콜 래퍼함수를 호출하면 실행되는 프로토콜은 다음과 같다.
(x86에서 주로 소프트웨어 인터럽트 번호 0x80을 사용)
Unix os에서 gcc와 함께 설치된 표준c언어라이브러리에 포함되어 있는 write함수 내부에서 특권레벨을 상향조정시키는 경우를 예로들면 다음과 같다.
Trap와 Interrupt는 이벤트 처리 기법이라는 공통점이 있지만, 이벤트 발생 요인과 처리 방법이 다르다.
Trap은 동기적(synchronous)으로 이벤트를 처리하는 기법이며, Interrupt는 비동기적(asynchronous)으로 이벤트를 처리하는 기법이다.
1.2.1. Trap(동기적)

Trap은 주로 시스템 콜을 처리하는데 이용된다. 즉, Interrupt와는 달리 주로 현재 처리하고 있는 프로그램에 의해서 발생하게 된다.
이와같이 발생한 이벤트는 Trap Handler에 의해 처리된다. Trap handler에서는 Interrupt handler와 달리 동기적으로 이벤트를 처리하므로 현재 처리하고 있는 프로그램에 대한 Context를 저장할 필요도 없고 복원할 필요도 없다.
따라서 Trap이 발생하게 되어 Trap Handler가 특정 동작을 수행하고 나면, SP(Stack Pointer)와 PC(Program Counter)만을 이용하여 기존에 수행하던 동작으로 복귀할 수 있게 된다.
1.2.2. Interrupt(비동기적)

Interrupt는 주로 네트워크의 Packet 도착 혹은 I/O에 대한 이벤트를 처리하는데 이용된다.
Interrupt는 Trap과 달리 현재 처리하고 있는 프로그램에 의해 발생하는 것이 아니라 특정 하드웨어에 의해 발생하게 된다.
따라서 Interrupt는 하드웨어의 우선순위에 따라 우선순위를 가지게 되고, 하드웨어들이 동시에 Interrupt를 걸어도 적절히 처리가 가능하게 된다. 이와같이 발생한 이벤트는 Interrupt Handler에 의해 처리된다. Interrupt Handler에서는 Interrput Service Routine을 통해 이벤트를 처리하게 되는데, Interrupt를 처리한 뒤 복귀해야 하는 프로세스가 현재 프로세스가 아닐 수 있기 때문(원래 흐름과 비동기적)에 Interrupt Service Routine 진입 전에 반드시 Context에 대한 기록이 요구된다.
따라서 Interrupt에 대한 처리를 마치면 저장된 Context를 복원하여 중단된 시점부터 다시 프로세스를 처리하게 된다.
1.2.3. 비교
Trap의 경우에는 Trap Service Routine 내에서 처리 도중에 Interrupt를 받을 수도 있지만, Interrupt의 경우에는 Interrupt Service Routine 내에서 처리 도중에 Interrupt를 받을 수 없게 되어있다.
이는 Interrupt의 Depth가 깊어짐에 따라 하나의 Interrupt가 끝나는데 긴 시간이 요구되는 구조가 될 수 있기 때문이다.
결과적으로 Trap은 프로세스의 Context를 저장하지 않아도 된다는 면에서 Interrupt보다 가볍지만, Trap에 대한 처리가 완료될 때까지 Block된다는 특징이 있다. Interrupt는 Trap의 반대의 특징을 갖고 있다고 생각할 수 있다.
만일 Interrupt가 동시에 발생하면 우선순위에 따라 처리하는데, 동일한 우선순위를 가진 Interrupt를 받게 되면 운영체제와 하드웨어에 의해 하나의 Interrupt를 처리하고 나머지 Interrupt는 저장해두거나 무시하게 된다.
cpu의 점유를 획득하기 위한 os의 스케쥴링 방식은 협조 방식과 비협조 방식으로 나눌 수 있다.
협조방식
과거의 몇몇 시스템에서 채택되었던 방식이다.
그냥 우호적인 프로세스가 시스템콜(yield)으로 cpu점유를 포기하는걸 기다리는 것이다.
비협조방식
프로세스가 비협조적이더라도 cpu의 제어를 획득할 수 있는 방법이다.
각 프로세스에 할당되는 최대 실행 시간인 time quantum을 정해두고
타이머 인터럽트가 발생할 때마다 time quantum이 소진되었는지 확인한다.
소진되었다면 현재의 프로세스를 종료시키고 다른 프로세스를 실행시킨다.
** 타이머 인터럽트는 타이머 장치에 정해진 주기마다 발생한다.
이를 통해 os는 일정한 주기로 작업을 수행하거나 스케줄링을 조정할 수 있다.
협조적이든 아니든, os가 cpu를 다시 획득하면 어떤 프로세스를 계속 실행할 것인지 결정해야한다.
이 결정은 os의 scheduler에 의해 내려진다.
다른 프로세스로 전환되는 것이 결정되면, os는 context switching이라는 코드를 실행한다.
프로세스 전환이 필요한 시점의 context switching프로토콜은 다음과 같다.
** switch루틴에서 서로 다른 프로세스의 커널스택에 접근할 수 있는 이유
os는 프로세스 간의 문맥 교환을 위한 PCB 테이블이라는 데이터 구조를 사용한다.
PCB 테이블에는 각 프로세스의 PCB가 포함되어 있기때문에
switch 루틴은 os가 직접 관리하는 PCB에 접근할 수 있다.
https://github.com/remzi-arpacidusseau/ostep-translations/tree/master/korean
https://efilevol42.oopy.io/38ec9f78-a491-47c9-8021-79e48ca4456d
https://www.javatpoint.com/trap-vs-interrupt-in-operating-system