운영체제 6)
운영체제
6) 제한적 직접 실행 원리
여러 프로세스들이 동시에 돌아가게 보이도록 하려고 OS는 물리적인 CPU를 공유한다.
기본적인 아이디어는 CPU의 시간을 나누어 쓰면서 가상화를 구현한다
그러나 가상화를 구현하기 위해 몇가지 문제를 해결해야한다.
-
성능저하
- 시스템에 많은 오버헤드를 주지 않으면서 가상화를 구현 가능 한가
-
제어 문제
- CPU에 대한 통제를 유지하면서 프로세스를 효율적으로 실행시킬 수 있는 방법이 있는가
제어권을 상실하면 한 프로세스가 컴퓨터를 독점할 수 있다..
여러 프로세스들이 동시에 돌아가게 보이도록 하려고 OS는 물리적인 CPU를 공유한다.
기본적인 아이디어는 CPU의 시간을 나누어 쓰면서 가상화를 구현한다
그러나 가상화를 구현하기 위해 몇가지 문제를 해결해야한다.
-
성능저하
- 시스템에 많은 오버헤드를 주지 않으면서 가상화를 구현 가능 한가
-
제어 문제
- CPU에 대한 통제를 유지하면서 프로세스를 효율적으로 실행시킬 수 있는 방법이 있는가
제어권을 상실하면 한 프로세스가 컴퓨터를 독점할 수 있다..
제어권을 유지하면서 성능저하가 없도록 하는 것이 OS를 구축하는데 중요한 도전과제이다
기본원리: Direct Execution(제한적 직접 실행)
- 프로그램을 CPU에서 직접 실행시킨다.
- Os가 프로그램이 CPU에서 동작하는 도중에는 간섭을 할 수 없다.
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
- time sharing을 어떻게 구현하는가?
동작하는 프로그램에 대한 제한 이 없으므로 OS는 아무것도 못한다
그래서 단순한 임베디드 시스템에 사용된다
그래서 이 방식에서는!!
=> OS는 아무것도 제어하지 않고 단지 library 역할만 한다.
문제점1 Restricted operation(제한된 연산)
direct execution의 장점은 빠르게 실행된다는 것
왜냐하면 프로그램이 cpu에서 실행되기 때문이다.
여기서 문제점
만약 프로그램이 제한된 연산을 요구하면 어떻게 하는가..?!
프로세스는 시스템에 대한 권한이 없기 때문에 제한된 연산을 수행할 수 없다..
제한된 연산
- 디스크에서의 입출력 요청
- CPu, 메모리등 시스템 자원에 대한 추가 자원 할당 요청
그냥 프로세스가 원하는대로 할 수 있도록 방치하는 방법이 있다...
불가!!! 제한된 연산은 필요하다
- 어떤것이 제한되는가?
- 메모리 접근
- 여러 프로세스가 있을때 접근하면 꼬이니깐..
- 디스크에 대한 입출력
- 특정 인스트럭션
- 메모리 접근
어떻게 제한을 하는가??
mode bit을 이용해 모드를 변경한다!
- User Mode
- 기능이 제한된다
- 어플리케이션은 하드웨어 자원에 대한 접근이 제한된다
- 오직 프로그램이 실행될때만 코드와 데이터 조각이 탑재된다.
- Kernal Mode
- 모든 기능이 사용 가능하다
- OS는 하드웨어의 자원에 모두 접근 가능하다
OS가 하드웨어의 자원에 접근 가능하다고 했다.. 아래와 같은 명령들을 실행해야하면 어떻게 하는가??
-
파일 시스템 접근
-
프로세스 생성, 소멸
-
다른 프로세스와 통신
-
더 많은 메모리 할당
-
디스크 입출력
=> 시스템 콜을 사용하면 된다!!
시스템 콜
-
특별한 권한이 필요한 동작을 해야할 때 시스템 콜을 실행하자!
- 커널에 trap 명령어를 전달
- 커널모드로 진입 => OS는 모든 명령어를 실행할 수 있다 => 프로세스가 요청한 작업을 수행가능
- 작업이 완료되면 OS가 return-from-trap 명령어를 호출
- 커널모드에서 사용자모드로 변경
- 커널에 trap 명령어를 전달
시스템 콜 실행 과정
- 시스템 콜 호출
- 프로세스가 trap 명령어 실행
- 커널로 들어감
- 커널 모드로 변경
- 명령어 수행
- os가 return-from-trap 명령어 호출
- 유저모드로 변경
trap을 실행할 때 호출한 프로세스의 필요한 레지스터를 저장해야한다.
OS가 return-from-trap을 실행시 유저 프로세스로 제대로 리턴을 해야하기 때문!!
ex) x86
- trap을 실행하면, 프로세서는 PC,flags,다른 레지스터들을 각 프로세스의 커널 스택에 저장한다.
- return-from-trap 명령어가 이 값들을 스택에서 pop하여 유저모드 프로그램을 다시 시작한다.
시스템 콜은 인터페이스이다!!
-
일반적으로 유저 프로그램은 시스템 콜에 직접적으로 접근하지 않고 API를 사용한다 => System call library를 사용!!
- 직접적인 시스템 콜 사용은 낮은 레벨의 프로그래밍(어셈블리어)를 사용해야한다.
- 그렇게 되면 사용자는 target을 모른다
- cpu와 독립된 코드를 생성할 수 없다.
- 높은 레벨의 언어가 시스템콜을 사용하기 쉽다
- 유저 프로그램과 OS 사이의 인터페이스
- 시스템 콜은 Os와 하드웨어 사이의 인터페이스다
- API에 의해 OS 대부분의 디테일은 숨겨진다
- 시스템콜 인터페이스는 OS의 시스템 콜을 활성화시키고 시스템콜의 상태와 리턴 값들을 반환한다.
- 직접적인 시스템 콜 사용은 낮은 레벨의 프로그래밍(어셈블리어)를 사용해야한다.
라이브러리가 시스템 콜을 호출하면 아래 작업을 수행
- 시스템 콜의 인자, 시스템 콜 번호를 스택 or 레지스터에 저장
- trap 명령어 실행
- trap 실행 후 시스템 콜의 리턴값을 읽고 제어권을 시스템콜을 호출한 프로그램으로 넘김
시스템콜 추가 이론
trap이 OS 코드의 어디를 실행할지 어떻게 아는가...
trap을 실행하면 호출에 해당하는 시스템콜의 코드를 os가 어떻게 아는가..??
커널은 부팅 시 trap table을 만들고 이를 사용해 시스템을 통제한다.
OS는 Exception이 발생하면 어떤 코드를 실행해야할지 hw에 알려줘야한다
OS는 특정 명령어를 사용해 HW에 trap handler의 위치를 알려준다.
HW는 trap handler를 보고 무엇을 해야할지 알 수 있다.
- 시스템 콜은 자신의 고유 번호를 가진다.
- 사용자 프로그램은 원하는 시스템 콜 호출을 위해 해당 번호를 스택 or 레지스터에 저장
- trap 명령어를 호출 (라이브러리가 수행함)
- trap handler가 실행
- trap handler가 시스템 콜 번호를 읽어 시스템 콜이 유효한지 파악
- 유효하다면 해당 코드로 이동해 실행
- trap 핸들러는 OS의 일부분이다
LDE 방식 진행 단계
전반부
- 부팅 시 커널은 트랩 테이블을 초기화, CPU는 나중에 이를 사용하기 위해 테이블의 위치를 기억
- 시스템 콜을 이용해 커널이 테이블을 사용해 해당되는 명령어로
- trap을 이용해 이를 사용!
후반부
- return-from-trap을 이용해 사용자 프로세스를 시작할 때
- 새 프로세스를 위한 노드할당해 프로세스 리스트에
- 메모리 할당을
OS(부트) (커널모드) | 하드웨어 | 프로그램 (유저모드) |
---|---|---|
트랩 테이블을 초기화 | ||
시스템콜 핸들러의 주소를 기억함 |
OS(실행) (커널모드) | 하드웨어 | 프로그램 (유저모드) |
---|---|---|
프로세스 목록에 항목을 추가 | ||
메모리 할당 | ||
메모리 탑재 | ||
argv 사용자 스택에 저장 | ||
레지스터, pc를 커널 스택에 저장 | ||
return-from-trap | ||
커널 스택으로 부터 레지스터 복원 | ||
유저 모드로 이동 | ||
main으로 jump | ||
main()실행 | ||
시스템콜 호출 | ||
OS로 trap | ||
레지스터를 커널 스택에 저장 | ||
커널 모드로 | ||
트랩 핸들러로 JUMP | ||
trap 처리 | ||
시스템 콜 서비스 수행 | ||
return-from-trap | ||
커널스택으로부터 레지스터 복원 | ||
유저 모드로 이동 | ||
trap 이후의 pc로 jump | ||
main에서 리턴(할일 끝) | ||
trap(exit()) | ||
프로세스의 메모리 반환 | ||
프로세스 목록에서 제거 |
문제점 2 Switching Between Processes(프로세스간 전환)
실행 중인 프로세스를 멈추고 다른 프로세스를 실행한다.
프로세스가 실행중 == 운영체제는 실행중이지 않는다를 의미
그렇다면 어떻게 프로세스를 전환하는가??
OS가 CPU 권한을 얻는 방식
- Cooperative(협조) 방식: 시스템 콜을 기다린다
- Non-cooperative(비협조) 방식: OS가 제어를 가져온다
Cooperative Approach
- 프로세스는 주기적으로 시스템콜을 호출함으로서 CPU를 반납한다.
- 운영체제가 CPU를 다른 프로세스에게 할당할 수 있게 한다.
- 비 정상적(illegal) 프로세스에게서 OS가 권한을 가져온다 -> 종료를 시킨다!
- 0으로 나누는 연산
- 허가되지 않은 메모리에 접근
수동적인 스케줄링 시스템
CPU 제어 권한을 얻기위해 운영체제는 시스템콜을 기다리거나 illegal이 일어나길 기다려야한다.
만약 프로세스 내부적으로 무한 루프같은 상황 or 시스템 콜이 호출되지 않는다면 어떡하지?? => 내부적 해결 불가.. 재부팅 해야함..
Non-cooperative approach
timer interrupt를 이용하자
인터럽트 발생시 해당 인터럽트에 대한 인터럽트 핸들러 실행
- timer interrupt
- 컴퓨터 부팅시 운영체제는 timer를 시작한다
- Timer는 밀리세컨드 마다 인터럽트를 발생시킨다
타이머 인터럽트가 일어나면?
- 현재 진행중인 프로세스가 멈춘다
- 실행 중이던 프로세스의 상태를 저장한다
- OS 실행 시 미리 구성된 인터럽트 핸들러 작동
timer interrupt는 Os에게 cpu의 권한을 준다.
인터럽트 발생시 실행 중이던 프로세스의 상태를 저장한다. 나중에 다시 시작할 수 있도록
Saving and Restoring context 문맥의 저장과 복원
- 스케줄러는 결정을 한다
- 현재 진행중인 프로세스를 계속할지 다른 프로세스로 switch 할지
- 만약 switch라는 결론이 나오면, OS는 context switch를 실행해야한다
Context switch
context: 레지스터에 있는값, 프로세스와 관련된 정보의 집합
레지스터, PC, 커널 스택 포인터
- 현재 실행중인 프로세스의 레지스터 값들을 커널 스택에 저장하고 새로 실행될 프로세스의 커널 스택에서 레지스터 값을 복원하는 것
context switch 방법
-
Context Saving
- 커널 스택에 현재 프로세스에 대한 몇 개의 레지스터 값을 저장
-
Context restoring
- 커널 스택에서 프로세스를 실행할 수 있도록 몇 개를 복원
-
Context switching
- 실행될 프로세스를 위해 커널 스택을 switch
타이머 인터럽트 방식
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 |
PCB
OS에 의해 사용되는 프로세스의 모든 정보를 저장하기 위한 자료구조이다.
process descriptor라고 불린다.
- 프로세스가 생성되면, OS는 프로세스에 상응되는 PCB를 생성
- 프로세스의 state가 변경되며 PCB는 업데이트 된다.
- 프로세스가 종료되면, PCB는 새 PCB가 나오는 pool로 반환
- 각 프로세스는 PCB를 지님
PCB는 프로세스 관리에 중심이다.
- 자원관리, 스케줄링 등등
Context Switch Time
오버헤드
- OS와 PCB가 복잡할수록 context switch가 오래걸린다
하드웨어에 지나친 의존
-
CPU 클락 속도, 메모리 접근 속도, 메모리 접근 패턴
- 높은 CPU 속도 -> 낮은 context switch 오버헤드
- 메모리 접근도 context switch 오버헤드에 중요한 영향
-
몇몇 프로세서는 다수의 레지스터 집합을 가짐
-
현재 레지스터의 포인터를 바꿔가며 context switch
-
ARM
response time을 개선하려면..?
time slice를 짧게하면 빨리 응답한다!!
그러나..
Time slice가 짧으면 context switch의 시간이 더 길수도 있다
=> response time은 context switch에 의해서 결정이 된다( 중간점에서 협의)
-
병행성의 문제??
인터럽트, 트랩 핸들링 중 다른 인터럽트가 발생하면??
방법
- 인터럽트가 처리되는 동안 나머지는 무시한다
- 락 기법을 이용해 내부 자료구조에 대한 동시 접근을 막는다
정리
- Cpu는 제한적인 사용자 모드와 제한이 없는 커널 모드를 지원해야한다.
- 일반적 프로그램은 유저모드에서 실행되며 시스템 콜을 통해 커널로 트랩해 Os의 서비스를 요청
- OS가 시스템 콜 서비스를 마치면 return-from-trap을 통해 유저프로그램으로 돌아간다. 그리고 트랩 이후의 실행되어야할 인스트럭션에 제어권을 반환
- 트랩 테이블은 부팅 시 OS에 의해 설정되어야함, 쉽게 사용자에 의해 수정되면 안된다
- 프로그램이 실행되면 OS는 프로그램이 영원히 실행되는 것을 막기위해 타이머 인터럽트를 사용, non-cooperative 방식이다
- OS는 인터럽트나 시스템 콜 실행중 다른 프로세스로 전환할 수 있다. context switch
Author And Source
이 문제에 관하여(운영체제 6)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@zh025700/운영체제06저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)