-> 블로그 이전

[OS] 1. 컴퓨터시스템 구조

2022. 3. 21. 10:57Major`/운영체제

OS (Operating System)

- 주어진 자원으로 최대한의 효율을 내도록 자원 관리
- 형평성 있는 자원 분배 : 프로세스가 CPU 독점하지 않도록

 

좁은 의미의 OS : kernel

- 메모리에 항상 상주하는 부분
- OS의 핵심


넓은 의미의 OS : Kernel + 각종 Utility

- Utility는 메모리에 상주하지 않고, 필요할 때만 메모리에 올라간다


OS의 분류

동시 작업 가능 여부

1) 단일 작업 (Single Tasking)

MS-DOS : 하나의 프로그램만 메모리에 올려서 수행 & 한번에 하나의 작업만 처리

2) 다중 작업 (Multi Tasking)

UNIX(Linux) & MS Windows : 여러 프로그램들을 메모리에 올려서 동시에 2개 이상의 작업 처리

  • 이 과정에서도 각 프로세스별로 CPU를 한 프로세스에게만 할당 가능

 

user 수

1) 단일 사용자

MS-DOS / Windows

2) 다중 사용자

UNIX(Linux) / NT Server

  • 파일의 공유 범위에 대한 처리를 고려해야 하기 때문에 복잡

 

처리 방식

1) 일괄 처리 (Batch Processing)

- 컴퓨터 프로그램 흐름에 따라서 순차적으로 자료를 처리하는 방식

- System의 실행시간을 최대한 정확하게 예측할 수 있다

- 하지만 프로그램 하나만 메인 메모리에 올릴 수 있기 때문에 해당 프로그램이 I/O를 요청하면 CPU는 그 시간동안 아무것도 하지 못한다

  • 하나의 작업이 끝나기 전까지 다른 작업을 할 수 없다

 

2) 멀티 프로그래밍 (Multi Programming)

- 메인 메모리에 여러개의 프로그램을 올려서 I/O Interrupt가 발생하게 되면 즉시 "context switching"을 통해서 다른 프로세스에게 CPU를 할당해준다

  • 이렇게 구현되면 CPU는 idle status에 빠지지 않고 계속해서 일을 한다

- Multiprogramming은 "time quantum"이 굉장히 길다

  • I/O Interrupt를 통해서 "context switching"이 되면 원래 할당되었던 프로세스는 다시 CPU를 할당받으려면 오랜시간 기다려야 하기 때문에 CPU를 독점으로 사용한다고 인식하지 못한다

 

3) 시분할 (Time Sharing)

- 각각의 프로세스에게 "고정적인 CPU 할당 시간"을 부여해준다 :: 굉장히 짧은 time quantum
- 주어진 CPU 할당 시간 내에 프로세스를 완료하거나 & 완료하지 못하거나 & I/O Interrupt가 발생하면 즉시 "context switching"을 통해서 강제로 CPU의 할당을 중지하고 다른 프로세스에게 CPU를 할당해준다
- time quantum이 굉장히 짧아서 빨리빨리 "context switching" 된다 :: 각 프로세스가 자신이 CPU를 독점적으로 사용한다고 느낄수 있다

  • CPU의 모든 성능을 최대한으로 활용하고 있다고 생각할 수 있다

>> interactive job들에게 굉장히 효율이 좋은 방식이다

  • I/O가 굉장히 많이 발생하고, 그에 따른 "context switching"이 자주 발생하기 때문에 time quantum이 빨라야 한다

 

4) 실시간 (Real-Time)

- 정해진 시간안에 해당 프로세스에 대한 종료가 반드시 보장되어야 한다 : "Deadline"이 존재

  • 이와 달리 시분할은 "Deadline" 개념이 없다

- Deadline을 어기게 되면 치명적인 문제가 발생한다

  • 원자로/공장 제어, 미사일 제어, 로봇 제어, 반도체 장비 제어, ...

Multi Tasking?

- 여러 작업을 동시에 실행

Multi Programming?

- 여러 프로그램이 메인 메모리에 올라가 있다는 의미

Time Sharing?

- CPU 시간을 각 프로세스가 분할해서 사용

Multi Process?

- 하나의 컴퓨터에 CPU 여러개


컴퓨터 시스템 구조

## Memory ##

- CPU의 작업 공간

  • CPU는 매 클럭 주기마다 메인 메모리의 명령어들을 굉장히 빠른 속도로 실행해준다

 

## Device Controller ##

- I/O장치를 전담하고 제어하는 일종의 작은 CPU (하드웨어)
- I/O장치 제어를 위한 "Control Register" & "Status Register"가 존재한다
- Device Controller는 본인만의 작업 공간인 "local buffer"가 존재한다
- I/O는 실질적으로 device ↔ local bufffer간에 발생한다

  • 어떤 I/O interrupt가 발생하면 device controller가 I/O 수행해준다
  • 일을 수행하면서 추출한 결과들을 local buffer에 저장한다
  • device controller가 일을 다 마치면 CPU에 interrupt를 걸어서 "일을 다 마쳤다"라고 알려야 한다
  • 그러면 CPU는 "local buffer"에 존재하는 내용(결과)들을 메인 메모리의 프로세스에게 copy해준다

 

※ Device Driver

- OS 코드 중 각 장치별 처리 루틴 (소프트웨어)

 

※ Example) program A가 키보드로부터 어떠한 값을 읽어야 한다

user program은 절대로 I/O에 직접 access가 불가능하다. I/O에 대한 access는 반드시 OS의 제어 하에서 수행되어야 하는 명령들이다

1. user program이 CPU에 interrupt : System Call
2. 그러면 CPU 제어권이 OS로 넘어가게 된다 : kernel mode

  • kernel은 내부적으로 각 System Call을 구분하기 위한 System Call Table이 존재한다
  • System Call Table은 각 kernel function마다 번호가 할당된 채로 존재한다
  • kernel은 요청받은 System Call에 대한 number를 System Call Table에서 찾는다
  • kernel은 해당 번호에 맞는 ISR을 호출해서 수행한다
  • ISR을 모두 처리하면 다시 kernel mode → user mode로 전환된다

3. 그리고 device controller에게 System Call에 대한 일을 수행시킨다
4. 일이 끝나면 device controller는 CPU에 interrupt를 걸어서 일을 마쳤다고 알려줘야 한다
5. 그러면 CPU는 "local buffer"에 존재하는 data들을 메인 메모리의 프로세스에게 copy해준다

## DMA (Direct Memory Access) & DMA Controller ##

우리가 I/O에 대한 일을 마치면 device controller → CPU로 interrupt가 발생한다
그런데 일을 마칠 때 마다 interrupt가 발생하게되면 CPU는 본인의 job인 메인 메모리의 프로그램의 명령어를 실행하는거 대신에 interrupt 관련된 job을 더 많이 수행할 것이다
여기에 더해서 매우 빠른 I/O장치가 매번 I/O 요청 완료에 대한 interrupt를 건다?? CPU는 굉장히 비효율적으로 일을 하게 된다

  • 1byte 당 계속 interrupt를 걸면 CPU 입장에서는 최악이다

>> 따라서 "block" 단위로 일을 마치면 interrupt를 걸자 : DMA

위에 설명한 예시의 이유는 "오직 CPU만 메모리에 접근이 가능하다"라는 문제 때문이다

결국 어떠한 user program이 I/O에 대한 결과가 필요해서 System Call을 걸게되면 해당 System Call에 대해서 device controller가 일을 하게되고, 그 결과를 "local buffer"에 저장해두면 이 "local buffer"에 존재하는 data들은 user program이 필요한 data이고 메인 메모리에는 CPU만 접근이 가능하기 때문에 결국 CPU가 "local buffer"에 존재하는 data들을 메인 메모리로 copy해줘야 한다

여기서 "DMA Controller"라는 추가적인 하드웨어를 통해서 메인 메모리에 접근하도록 해주면 된다


"DMA Controller"는 "local buffer"의 "block 단위"의 Data들을 직접 메인 메모리에 접근해서 옮겨줌에 따라 "local buffer"에 어느정도 결과를 쌓았다는 것을 CPU에게 interrupt 걸지 않고 바로 dma controller를 통해서 메인 메모리로 copy해준다
이러면 CPU로의 interrupt는 덜 발생하고 결과적으로 CPU는 효율적으로 일 처리가 가능하다

>> 물론 일을 전부 마치면 device controller는 cpu에 interrupt를 걸어서 일을 다 마쳤다고 알려줘야 한다

## Interrupt Line ##

CPU는 메인 메모리의 명령어의 실행을 마치고나서 항상 "Interrupt Line"을 check해서 interrupt가 들어왔나 확인해줘야 한다

  • interrupt가 들어왔으면 해당하는 ISR을 수행
  • interrupt가 안들어왔으면 다음 명령어 수행

 

## Timer ##

CPU를 user program에게 할당해주는 일은 OS가 수행해주지만, user program으로부터 CPU를 뺏어오는 것은 OS 혼자 힘으로 불가능하다
만약 어떤 user program이 무한루프를 돌게된다? 이러면 해당 user program으로부터 CPU를 뺏어와야하고 CPU를 뺏어오려면 어떠한 "원인"이 필요하다
이 "원인"을 제공해주는 것이 Timer이다

1. OS가 user program에게 CPU를 할당해줄 때는 특정 시간의 Timer를 세팅해줘서 할당해준다
2. 이 Timer가 지나면 Timer Interrupt가 발생하게 되고, interrupt가 발생하면 CPU에 대한 제어권이 OS에 넘어감에 따라 그 때 OS가 user program으로부터 CPU를 뺏는다
3. 그러면 OS는 다른 프로세스에게 CPU를 할당해줌으로써 하나의 프로세스의 CPU 독점을 막는다

- Timer는 매 클럭마다 1씩 감소되면서 0이 되면 Timer Interrupt가 발생한다

## mode bit ##

user program의 잘못된 수행으로 인해 다른 program & OS에 피해가 가지 않도록 하기 위한 보호 장치(dual mode)에 사용되는 bit이다

  • mode & 명령어 모드를 비교해서 다르면 즉시 해당 프로세스 kill

- CPU에 대한 제어가 user program에 존재하나(user mode : 1) or OS에 존재하나(kernel mode : 0)

  • "보안"을 위해서 중요한 명령어는 반드시 kernel mode에서 실행되어야 한다 : "특권 명령"

 


Interrupt

Interrupt를 당한 시점에서의 레지스터 & PC값을 저장 후 CPU의 제어를 ISR에 넘긴다

H/W Interrupt

- 하드웨어가 발생시킨 인터럽트

  • Timer / Device Controller

 

S/W Interrupt (Trap)

- 프로그램의 오류 (Exception) & 프로그램이 커널 함수를 호출 (System Call)
- 개별 프로그램이 CPU에 대한 제어를 OS로 넘기기 위해 발생하는 인터럽트

System Call

user program이 OS의 서비스를 받기 위해 kernel function을 호출하는 것
- 이러면 user program에 대한 I/O작업이 수행된다

 

trap을 발생시켜서 인터럽트 벡터를 통해서 메모리의 ISR 위치로 이동

- 인터럽트 벡터는 "메모리의 ISR의 주소"를 보유하고 있다
- 따라서 인터럽트 벡터를 통해서 ISR의 주소로 이동
- 이러면 제어권이 결국 ISR로 이동됨에 따라 ISR을 수행한다

  • 물론 여기서 올바른 I/O 요청인지 확인 후, I/O를 수행한다
  • I/O에 대한 일의 수행은 Device Controller가 수행한다

- I/O가 완료되면 device controller는 CPU에 interrupt를 걸어서 일을 마쳤다고 알린다

  • 여기서 발생하는 interrupt는 H/W interrupt이다

>> 따라서 trap이 발생했다는 것은 S/W interrupt이지만, trap에 해당하는 ISR을 마치고 CPU에게 알리는 interrupt는 H/W interrupt이다

 

※ 인터럽트 벡터
- 인터럽트 종류별로 실행해야 할 ISR의 주소를 보유

※ ISR
- 해당 인터럽트를 처리하는 kernel function


동기식 I/O (synchronous I/O)

어떤 program A에 대해서, 다음 실행할 명령어가 I/O에 대한 결과가 필요한 명령어이고, 그에 따라서 I/O interrupt동안에 CPU를 다른 프로세스에게 할당해준다. 이러면 program A의 입장에서는 waiting하는 중이다

>> 다음 명령어가 I/O에 대한 결과에 영향을 받음

 

비동기식 I/O (asynchronous I/O)

어떤 program A에 대해서 I/O가 들어옴에도 불구하고 CPU는 계속 프로그램 A에 할당되어서 다음 명령어를 수행
>> 다음 명령어는 I/O에 대한 결과와 상관없이 수행 가능

※ Example

어떤 파일에 data를 작성하는데 "파일에 data 작성"이라는 job은 다음 명령어에 영향을 미치지 않는 job이므로 계속해서 CPU는 해당 프로세스에게 할당된채로 다음 명령어를 수행한다

>> 동기식 I/O & 비동기식 I/O 둘다 I/O 완료에 대해서 device controller가 CPU에 interrupt를 걸어서 알려줘야 한다

 


Primary (Executable)

- 휘발성 메모리이다
- CPU에서 직접 접근이 가능하다 : byte 단위로 접근

Secondary

- 비휘발성 메모리이다
- CPU가 직접 접근이 불가능하다 : sector 단위로 별도의 controller로 접근


어떤 프로그램을 메인 메모리로 올릴때는 disk에서 바로 메인 메모리로 올리지 않고 중간에 "Virtual Memory"를 거쳐서 올라간다

1. 프로그램을 실행하면 해당 프로그램만의 독자적인 메모리 영역을 생성해준다 (0 ~ ) : Address Space

  • code & data & stack & ...

2. 각 Address Space를 메인 메모리에 할당해줌으로써 실행된다

  • 메인 메모리의 kernel space를 제외한 나머지 영역에 할당

- 여기서 해당 프로그램에서 당장 필요한 영역부터 메인 메모리에 올려준다

  • 메인 메모리 낭비 줄이기

- 그리고 필요하지 않는 나머지 영역은 swap area에 존재한다

  • swap area는 메인 메모리의 공간의 한계로 인해서 사용되는 영역이다


>> Virtual Memory의 주소와 Main Memory에 할당되는 주소는 다르기 때문에 논리적 주소 → 물리적 주소Mapping해줘야 한다


code

- 자원 관리 코드
- 편리한 서비스 제공 코드
- System Call & ISR 코드

data (OS가 사용하는 여러가지 자료구조)

- 하드웨어 관리를 위한 자료구조 (CPU / Memory / I.O)
- 각 프로세스 관리를 위한 자료구조 (PCB)

stack

- 커널도 결국 함수구조로 구현이 되어 있다
- 그래서 각 함수가 실행됨에 따라 stack에 쌓아야한다

  • 각 프로세스마다 별도의 커널 스택이 존재