수정입니다
6. Mechanism: Limited Direct Execution 본문
운영체제는 time sharing을 통해서 CPU 를 process에 공유한다고 했다.
여기서 두가지 issue 존재
- Performance - context switching overhead
- Control - process에 넘긴 CPU 주도권을 어떻게 다시 가져오고 유지할 지
Direct Execution
- 그냥 프로그램 실행 후 끝날 때까지 기다렸다가 다시 control을 가져오는 방식
- 하지만 프로그램에 어떤 limit도 가하지 않는다면, 운영체제로서의 역할을 한다고 말하기 어렵다
- +) 여러가지 문제 존재
Problem 1 : Restricted Operation
- process가 CPU처리 이외에 disk의 I/O처리나 다른 system resouces를 필요로 할 때 어떻게 할 거냐?
- process가 하드웨어의 이리저리 전부 접근하고 제어권을 뺏기는 경우가 생길 수 있음
Solution : Using protected control transfer
- User mode : application이 돌아가면서 hardware resources에 완전하게 접근하지 못함 (low privilege level)
- Kernel mode : OS가 돌아가면서 hardware에 완전히 접근할 수 있게 함 (high privilege level)
=> user mode에 있는 process들이 system call을 통해 OS에 요청, OS가 kernel mode에서 처리한다
=> 다른 의미가 아니라 prcessor(CPU)에 이런 모드들을 세팅해서 process와 OS를 왔다갔다 하는 거임
System call
- Accessing the file system
- Creating and destroying process
- Communicating with other processes
- Allocating more memory
OS가 이러한 주요한 함수들을 process들에 carefully expose 함
=> OS가 process들이 사용할 수 있도록 핵심적인 기능을 모아놓은 것이 system call
=> sys call이 process의 요청이 정당한지 아닌지 판단 후 실
그렇다면, User mode에 있는 process들은, 어떻게 system call을 호출 할 수 있을까?
=> Trap instruction
- Jump into the kernel
- Raise the privilege level to kernel mode
=> application(user mode)에서 실행하는 명령어
=> Return-from-trap instruction
- Return into the calling user program
- Reduce the privilege level back to user mode
=> OS가 kernel mode에서 실행하는 명령어
Limited Direction Execution Protocol
- 제일 처음, OS가 trap table을 초기화(각 handler의 주소로, trap table의 jump 명령을 채움)
- fork()를 통해 process 생성(fork도 syscall이므로 return-from-trap 존재)
** kernel stack의 두가지 기능 => kernel stack은 각 process마다 가지고 있다.
1. OS 함수를 실행할 때 필요한 local var, input para, return addr를 저장하는 역할
2. user mode에서 kernel mode로 들어갈 때 user mode의 register를 저장, 다시 돌아갈 때 복원하는 역할
이후 실행하며 sys call 호출 flow
OS(kernel mode) | Hardware | Program(user mode) |
system call 호출, trap into OS | ||
1. save regs to kernel stack 2. move to kernel mode 3. jump to trap handler |
||
Handle trap Do work of system call return-from-trap |
||
1. restore regs from kernel stack 2. move to user mode 3. jump to pc afer trap |
||
retrun from main |
- user process는 system call handler의 주소를 모른다.
- 따라서 exception(system call, interrupt)가 발생하면 다 멈추고 trap table로 가게 pc를 수정
- hardware에서 3가지 처리 후 handle trap
process A에서 read() syscall 호출, trap instruction 발생
trap inst 발생 시, 모든걸 다 멈추고 가야하기 때문에, 그때까지 CPU에서 하던거 저장해야됨
1. save regs to kernel stack
저장할 register들을 A의 kernel stack에 저장
2. move to kernel mode
저장 후 proecess A를 kernel mode로 변경 (privilege level 상승)
3. jump to trap handler
trap table에서 명령어에 맞는 걸 찾아서, 그 syscall handler로 jump
syscall_handler에서 뭔가를 또 처리해야하니, register 내용이 변경 되었을 것 (register는 공용이다)
handler에서 다 처리한 후, return-from-trap을 만나면, 다시 hardware 처리 시작
이건 Limited Direct Execution 예시이므로, 그냥 kernel stack에 저장된 A regi를 바로 복원한다
(A가(A혼자) 하드웨어에 막 접근하지 못하도록 limit을 주는 예시)
Problem 2 : Switching Between Processes
- process들을 서로 바꿔줄 때, OS가 어떻게 다시 control을 가져올까?
- A cooperative Approach : Wait for system calls - process가 양보
- A Non-Cooperative Approach : The OS takes control - 제 3의 handler를 이용해서 OS가 제어권을 얻어냄
A cooperative Approach : Wait for system calls (별로 안좋다고 한다)
- process가 주기적으로 yield() 같은 system call을 만들면서 CPU 제어권을 포기함
- +) 뭔가 잘못된 걸 했을 때 OS에게 제어권 넘김 ( 0으로 나눈다거나, 접근불가 메모리에 접근한다거나 )
** 만약 process가 infinite loop에 들어가면 machine을 reboot 하는 것 이외에 OS가 regain을 할 기회 자체가 없어짐
A Non-Cooperative Approach : The OS takes control
- A timer interrupt - OS가 주기적으로 이걸 발생시킴
- interrupt가 발생되면
- 1. 현재 실행 중인 process가 halt 되고
- 2. 그 program의 현재 상태를 저장하고
- 3. OS에서 미리 구성된 interrupt hanlder를 실행함
Saving and Restoring Context
- 운영체제가 제어권을 잡으면, Scheduler 가 결정을 내림
- 현재 process를 계속 실행 vs 다른 process로 바꾸기
- 다른 process로 바꾸는 결정을 하면, OS가 context switch를 실행한다.
** context == 문맥 == 그니까 register를 바꿔준다고 생각하면 된다
Context Switching (assembly code로 짜야한다)
1. 현재 process의 PCB에 register 저장(r0~r12 : general, r15 : pc, r13 : sp)
2. 바꿔줄 process의 PCB에 저장된 register를 CPU로 복원
3. 바꿔줄 process의 kernel stack으로 switch
Limited Direction Execution Protocol(Timer interrupt)
process A가 실행 중일 때 Timer interrupt가 들어옴
실행 중이던 process A의 현재 실행 상태를 A의 kernel stack에 저장
process A의 mode를 kernel mode로 변경
timer interrupt에 맞는 handler를 찾아서 jump, switch()를 실행
1. Save a few register value for the current process onto its PCB (r0~r12 : general, r15 : pc, r13 : sp)
switch()를 실행하면서 이 kernel내에서 현재까지의 진행상황을 A의 PCB에 저장함
그래야 A가 다시 돌아왔을 때 kernel내에서 어디까지 진행했는지를 보고 복원을 하든 뭘 하든 할거 아님
(위에서 kernel stack에 저장한건, 실제 CPU 위에서 user mode에서 진행중인 A의 진행 상황)
저장했으면 switch를 하고 B를 실행 (restored은 아래에서)
아까 바꾼 A를 다시 바꿀거임.
2. Restore a few for the soon-to-be-executing porcess from its PCB
3. Switch to the kernel stack for the soon-to-be-executing process
A PCB에 저장 해 놓은 reg를 복원하고, A의 kernel stack으로 바꿔줌
return-from-trap을 만나면 A의 kernel stack에 저장되어 있던 reg를 다시 복원
다시 A를 실행
'전공 > 운영체제' 카테고리의 다른 글
9. Scheduling: Proportional Share (0) | 2024.01.01 |
---|---|
8. Scheduling: The Multi-Level Feedback Queue (1) | 2023.12.30 |
7. Scheduling: Introduction (0) | 2023.12.30 |
5. Interlude : Process API (0) | 2023.12.29 |
4. The Abstraction: The Process (0) | 2023.12.28 |