여러 프로세스들이 동시에 돌아가게 보이도록 하려고 OS는 물리적인 CPU를 공유한다.
기본적인 아이디어는 CPU의 시간을 나누어 쓰면서 가상화를 구현한다
그러나 가상화를 구현하기 위해 몇가지 문제를 해결해야한다.
성능저하
제어 문제
제어권을 상실하면 한 프로세스가 컴퓨터를 독점할 수 있다..
제어권을 유지하면서 성능저하가 없도록 하는 것이 OS를 구축하는데 중요한 도전과제이다
OS | 프로그램 |
---|---|
1. 프로그램 목록의 항목을 생성(create) | |
2. 프로그램 메모리 할당(allocate) | |
3. 메모리에 프로그램 탑재(load) | |
4. argc/argv를 위한 스택 셋업 | |
5. 레지스터 내용 삭제 | |
6. call main()실행 | |
7. main()에서 실행 | |
8. main()에서 return 실행 | |
9.프로세스 메모리 반환(free) | |
10.프로세스 목록에서 항목 제거 |
구현이 쉽다!
그치만 문제점이 있음
Restricted operations
Switching between processes
동작하는 프로그램에 대한 제한 이 없으므로 OS는 아무것도 못한다
그래서 단순한 임베디드 시스템에 사용된다
그래서 이 방식에서는!!
=> OS는 아무것도 제어하지 않고 단지 library 역할만 한다.
direct execution의 장점은 빠르게 실행된다는 것
왜냐하면 프로그램이 cpu에서 실행되기 때문이다.
여기서 문제점
만약 프로그램이 제한된 연산을 요구하면 어떻게 하는가..?!
프로세스는 시스템에 대한 권한이 없기 때문에 제한된 연산을 수행할 수 없다..
제한된 연산
그냥 프로세스가 원하는대로 할 수 있도록 방치하는 방법이 있다...
불가!!! 제한된 연산은 필요하다
어떻게 제한을 하는가??
mode bit을 이용해 모드를 변경한다!
OS가 하드웨어의 자원에 접근 가능하다고 했다.. 아래와 같은 명령들을 실행해야하면 어떻게 하는가??
파일 시스템 접근
프로세스 생성, 소멸
다른 프로세스와 통신
더 많은 메모리 할당
디스크 입출력
=> 시스템 콜을 사용하면 된다!!
특별한 권한이 필요한 동작을 해야할 때 시스템 콜을 실행하자!
시스템 콜 실행 과정
OS가 return-from-trap을 실행시 유저 프로세스로 제대로 리턴을 해야하기 때문!!
ex) x86
일반적으로 유저 프로그램은 시스템 콜에 직접적으로 접근하지 않고 API를 사용한다 => System call library를 사용!!
라이브러리가 시스템 콜을 호출하면 아래 작업을 수행
trap이 OS 코드의 어디를 실행할지 어떻게 아는가...
trap을 실행하면 호출에 해당하는 시스템콜의 코드를 os가 어떻게 아는가..??
커널은 부팅 시 trap table을 만들고 이를 사용해 시스템을 통제한다.
OS는 Exception이 발생하면 어떤 코드를 실행해야할지 hw에 알려줘야한다
OS는 특정 명령어를 사용해 HW에 trap handler의 위치를 알려준다.
HW는 trap handler를 보고 무엇을 해야할지 알 수 있다.
전반부
후반부
OS(부트) (커널모드) | 하드웨어 | 프로그램 (유저모드) |
---|---|---|
트랩 테이블을 초기화 | ||
시스템콜 핸들러의 주소를 기억함 |
OS(실행) (커널모드) | 하드웨어 | 프로그램 (유저모드) |
---|---|---|
프로세스 목록에 항목을 추가 | ||
메모리 할당 | ||
메모리 탑재 | ||
argv 사용자 스택에 저장 | ||
레지스터, pc를 커널 스택에 저장 | ||
return-from-trap | ||
커널 스택으로 부터 레지스터 복원 | ||
유저 모드로 이동 | ||
main으로 jump | ||
main()실행 | ||
시스템콜 호출 | ||
OS로 trap | ||
레지스터를 커널 스택에 저장 | ||
커널 모드로 | ||
트랩 핸들러로 JUMP | ||
trap 처리 | ||
시스템 콜 서비스 수행 | ||
return-from-trap | ||
커널스택으로부터 레지스터 복원 | ||
유저 모드로 이동 | ||
trap 이후의 pc로 jump | ||
main에서 리턴(할일 끝) | ||
trap(exit()) | ||
프로세스의 메모리 반환 | ||
프로세스 목록에서 제거 |
실행 중인 프로세스를 멈추고 다른 프로세스를 실행한다.
프로세스가 실행중 == 운영체제는 실행중이지 않는다를 의미
그렇다면 어떻게 프로세스를 전환하는가??
OS가 CPU 권한을 얻는 방식
수동적인 스케줄링 시스템
CPU 제어 권한을 얻기위해 운영체제는 시스템콜을 기다리거나 illegal이 일어나길 기다려야한다.
만약 프로세스 내부적으로 무한 루프같은 상황 or 시스템 콜이 호출되지 않는다면 어떡하지?? => 내부적 해결 불가.. 재부팅 해야함..
timer interrupt를 이용하자
인터럽트 발생시 해당 인터럽트에 대한 인터럽트 핸들러 실행
타이머 인터럽트가 일어나면?
timer interrupt는 Os에게 cpu의 권한을 준다.
인터럽트 발생시 실행 중이던 프로세스의 상태를 저장한다. 나중에 다시 시작할 수 있도록
context: 레지스터에 있는값, 프로세스와 관련된 정보의 집합
레지스터, PC, 커널 스택 포인터
Context Saving
Context restoring
Context switching
OS(부트) (커널모드) | 하드웨어 | 프로그램 (유저모드) |
---|---|---|
트랩 테이블을 초기화 | ||
시스템콜 핸들러, 타이머 핸들러의 주소를 기억함 | ||
인터럽트 타이머 시작 | ||
타이머 시작,X 밀리세컨이 지난 후 CPU 인터럽트 |
OS(실행) (커널모드) | 하드웨어 | 프로그램 (유저모드) |
---|---|---|
프로세스 A | ||
타이머 인터럽트 | ||
A의 레지스터를 A의 커널스택에 저장(암묵적으로 하드웨어에 의해 저장!) | ||
커널모드로 이동 | ||
트랩 핸들러로 jump | ||
트랩처리 | ||
switch() 호출 | ||
A의 레지스터를 A의 proc 구조에 저장(명백히 하드웨어에 저장) | ||
B의 구조로 B의 레지스터 복원 | ||
B의 커널스택으로 전환 | ||
return-from-trap(B 프로세스로) | ||
B의 커널 스택을 B의 레지스터로 저장 | ||
사용자 모드로 이동 | ||
B의 PC로 jump | ||
프로세스 B |
OS에 의해 사용되는 프로세스의 모든 정보를 저장하기 위한 자료구조이다.
process descriptor라고 불린다.
PCB는 프로세스 관리에 중심이다.
오버헤드
하드웨어에 지나친 의존
CPU 클락 속도, 메모리 접근 속도, 메모리 접근 패턴
몇몇 프로세서는 다수의 레지스터 집합을 가짐
현재 레지스터의 포인터를 바꿔가며 context switch
ARM
response time을 개선하려면..?
time slice를 짧게하면 빨리 응답한다!!
그러나..
Time slice가 짧으면 context switch의 시간이 더 길수도 있다
=> response time은 context switch에 의해서 결정이 된다( 중간점에서 협의)
인터럽트, 트랩 핸들링 중 다른 인터럽트가 발생하면??
방법