2-1. System Structure & Program Execution 1

운영체제 – 이화여대 KOWC 공개강의

컴퓨터 시스템 구조

CPU의 작업공간이 메모리인 것처럼 각 I/O 디바이스(프린터, 모니터, 하드디스크 등)도 작업 공간이 local buffer로 존재한다.
CPU는 각 I/O 디바이스와 성능 처리 속도가 많이 난다. 하드 디스크는 CPU에 비해 100만배 정도 느리다.
따라서 디스크를 CPU가 직접 관장하지 않고 디바이스 컨트롤러라는 것이 담당하고 있다.

CPU 내부에 있는 mode bit 는 지금 CPU에서 실행되고 있는 것이 운영체제인지 사용자 프로그램인지를 구분해준다.

CPU 내부에는 메모리보다 더 빠르면서 정보를 저장할 수 있는 작은 공간이 레지스터가 존재한다.

Interrupt line이 CPU 내부에 붙어있다. CPU는 항상 메모리에 있는 인스트럭션만 계속 실행한다. 인스터럭션 하나가 실행되고 나면 다음번에 실행할 인스트럭션(기계어의 주솟값이 증가), 다음 싸이클에서는 다음 인스트럭션을 실행한다. 그럼 키보드에서 어떤 입력이 들어왔다던지 디스크에 뭔가를 읽어와야 한다던지 또 그 일을 다 끝냈다던지 하는 일을 CPU가 알 수 있게 해주는 것이 Interrupt line이다.

프로그램이 메모리에서 실행이 되다가 I/O를 하게 되면 그 I/O는 CPU가 직접 하는 것이 아니라 device controller한테 일을 시키고 그 다음 CPU는 놀지 않고 메모리 접근을 계속하면서 인스트럭션을 실행한다.

CPU는 빠르고 쉬지 않고 일을 한다.

만약 무한루프를 도는 프로그램을 만들면? 이 프로그램이 CPU한테 넘어가면 계속 CPU를 사용한다. 그래서 컴퓨터에는 timer라는 하드웨어를 사용한다. 이는 특정 프로그램이 CPU를 독점하는 것을 막는다. 운영체제는 사용자 프로그램이 실행이 되면 이를 CPU에 넘겨준다. 그런데 그냥 넘겨주는 것이 아니라 timer에 어떤 값을 셋팅한 뒤 프로그램을 CPU에 넘겨준다. 그러면 그 프로그램은 독점적으로 CPU를 계속 사용할 수 있는 것이 아니라 timer에 할당된 시간( 1초 미만 수십~수백 ms 정도)을 셋팅해서 프로그램한테 CPU를 넘겨준다. CPU는 인스트럭션을 실행하다가 셋팅된 시간이 되면 타이머가 CPU한테 인터럽트를 건다.

CPU는 인스트럭션을 하나씩 실행하다가 하나의 인스트럭션이 끝나고 나면 인터럽트 라인을 체크한다. 인터럽트 들어온게 없으면 다음 인스트럭션을 실행한다. 실행 뒤 인터럽트 라인체크, 이 작업을 CPU는 계속 반복한다. 만약 타이머가 인터럽트를 걸어오면 CPU는 하던 일을 잠시 멈추고 CPU의 제어권이 사용자 프로그램으로부터 운영체제한테 자동으로 넘어가게 되어있다.
메모리에 있던 해당 프로그램은 CPU를 100ms정도 썼기 때문에 다음 프로그램에게 CPU를 넘겨준다.

프로그램이 종료가 되면 CPU를 자동으로 반납하게 되어있다. 여러 프로그램이 CPU를 나눠쓰는 time sharing을 구현하기 위해 timer를 두고 있다.

사용자 프로그램은 직접 I/O 장치에 접근 할 수 없다. I/O 장치에 접근하는 모든 인스트럭션은 운영체제를 통해서만 할 수 있도록 막아놓았다. 사용자 프로그램이 I/O를 해야하는 상황에 오면 스스로 CPU를 운영체제에게 넘겨주고 운영체제가 해당 작업을 device controller에게 시킨다. (20:00)

시키고 나서는 I/O 작업이 오래 걸리기 때문에 운영체제는 지금 요청한 프로그램에게 CPU를 넘기는 것이 아니라 다른 프로그램에게 CPU 를 넘겨준다. 그러면 키보드에서 뭘 읽어오라고 요청한 프로그램은 언제 다시 CPU를 얻게 되느냐? 키보드에서 사용자 입력이 들어와야 다음 처리를 할 수 있는 상태인데 언제까지 그것을 기다리느냐면 IO 컨트롤러가 요청한 작업이 끝나서 사용자가 키보드로 입력한 것이 버퍼에 들어오면 키보드 컨트롤러가 CPU에게 인터럽트를 건다. 그러면 다른 프로그램이 CPU를 사용하고 있었겠지만 인터럽트가 들어왔기 때문에 CPU의 제어권이 운영체제에게 자동으로 넘어간다. 그러면 운영체제는 인터럽트가 들어온 이유를 조사했더니 아까 어떤 프로그램에서 요청했던 키보드 입력이 들어온 것을 알았다. 그러면 입력된 키보드 값을 아까 요청한 프로그램의 메모리 공간에 그 값을 카피해주고 그 후에 아까 CPU를 쓰다 인터럽트를 당한 프로그램에게 CPU를 다시 준다.(일반적으로) (해당 프로그램의 CPU 사용 time이 남았다면) 그리고 나머지 실행준인 프로그램들을 라운드로빈 돌리면서 CPU 사용권을 제공한다.

 

Mode bit가 커널 모드일 때는 어떤 일이든지 다 할 수 있게끔 정의 되어 있다. 메모리 접근, I/O 접근 인스트럭션도 실행할 수 있다. 운영체제가 CPU를 가지고 있기 때문이다. 그런데 Mode bit가 1일 때(사용자 프로그램이 CPU를 가지고 있을 때)는 제한된 인스트럭션만 CPU에서 실행할 수 있게 된다. 보안 상의 목적이 있다.
인터럽트가 들어오게 되면 CPU 제어권이 사용자 프로그램에서 운영체제로 넘어오면서 Mode bit가 커널모드로 변경된다.

 

 

화면에 출력하기 위해서는 메모리에 있는 출력할 내용을 모니터의 로컬 버퍼에 담은 뒤에 화면에 출력을 하라는 지시는 컨트롤러가 하게 된다. 마찬가지로 사용자 프로그램에서 어떤 내용을 파일에 저장하고 싶다면 그 데이터 자체는 로컬 버퍼에 담아두고 저장하라는 명령은 제어 레지스터를 통해 CPU가 IO 컨트롤러에게 명령하게 된다.

원칙적으로 메모리는 CPU만 접근할 수 있게 하드웨어적으로 구현을 해 놓았다. IO 디바이스들은 메모리에 접근 불가하다. 대신 각 디바이스들이 접근할 수 있는 로컬 버퍼를 따로 두었다. 로컬 버퍼에 있는 데이터로 일을 처리한다. CPU는 자신의 메모리 접근도 할 수 있고 각 디바이스의 로컬 버퍼에도 접근 할 수가 있다. 작은 CPU(디바이스 컨트롤러)는 자신의 로컬 버퍼에만 접근할 수 있다.

그런데 그렇게 하다 보니 CPU가 인터럽트를 너무 자주 당하게 되어 빠른 CPU 장치가 효율적으로 작업을 하지 못하게 된다. 그래서 DMA(Direct Memory Access)라는 컨트롤러를 하나 두게 된다. 원래는 메모리에 접근 할 수 있는 장치는 CPU 뿐이었는데 DMA를 두게 되면 메모리를 CPU도 접근할 수 있고 DMA도 접근 할 수 있게 된다. DMA와 CPU 둘이 동시에 메모리의 특정 영역에서 작업을 하게 될 수 있어서 Memory controller는 그런 것을 중재하는 역할을 한다.

DMA의 역할은 중간중간에 IO 디바이스들의 작업이 들어왔을 때 그때마다 CPU에게 인터럽트를 걸어서 CPU가 IO 로컬 버퍼에 있는 내용을 메모리에 카피하는 것은 오버헤드가 너무 크다. 그래서 이런식으로 하지 않고 CPU는 계속 자기 일을 하고 있고 중간 중간에 IO 디바이스의 로컬 버퍼에 들어오는 내용이 작업이 끝났으면 DMA가 직접 이를 메모리로 복사하는 일까지 해준다. 그리고 작업이 다 끝났으면 CPU에게 인터럽트를 한번만 걸어서 해당 작업(메모리로 복사)이 끝났음을 DMA가 보고해준다. 그렇게 되면 CPU가 중간에 인터럽트 당하는 빈도가 줄어들게 되어 CPU를 더 효율적으로 사용할 수 있다.

결국 CPU의 역할은 본인이 이번에 실행해야 될 인스트럭션의 메모리 주소를 내부의 레지스터 중에서 Program Counter라는 레지스터가 다음번에 어디에 있는 인스트럭션을 실행해야 하는지에 대한 인스트럭션의 주소를 가지고 있다. 매번 그 인스트럭션만 실행하는 것이 CPU의 숙명이다.

시스템콜은 사용자 프로그램이 운영체제 커널 함수를 호출하는것. 이것은 일반 함수 호출과는 다르다. 사용자 프로그램이 IO를 수행할 때 직접 소프트웨어 인터럽트(트랩)를 걸어서 CPU가 운영체제한테 넘어가게 한다.

Trap = 소프트웨어 인터럽트

IO를 하기 위해서 인터럽트가 두 가지 종류가 걸린다. 소프트웨어 인터럽트(트랩) + 하드웨어 인터럽트. IO 요청을 하기 위해 트랩을 통해 요청하고 IO가 끝났으면 하드웨어 인터럽트를 통해 끝났다는 것을 알려준다.

Timer 인터럽트( 프로그램에 할당된 time이 지남. CPU 그만 써라)

하드웨어 인터럽트

현대의 운영체제는 인터럽트에 의해 구동된다. 운영체제는 CPU를 사용할 일이 없다. 인터럽트가 드러올 때만 CPU가 운영체제한테 넘어간다. 그렇지 않으면 CPU는 항상 사용자 프로그램이 사용하고 있다.

인터럽트에는 종류가 많다.(타이머 인터럽트, 키보드 디바이스 컨트롤러 인터럽트 etc..) 각각의 인터럽트마다 운영체제가 해야 할 일이 다르다. 각각의 인터럽트마다 무슨 일을 해야하는지가 운영체제 코드에 정의가 되어있다. 인터럽트마다 실제 처리해야 할 코드를 인터럽트 처리 루틴이라고 한다. 그리고 그 인터럽트 처리 루틴 주소를 가지고 이쓴 것이 인터럽트 벡터이다.

댓글 남기기

Close Menu