2-2. System Structure & Program Execution 2

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

동기식 입출력(synchronous I/O)
립씽크. 소리와 입이 맞는 것.
시간적으로 서로 맞추는 것을 synchronous라고 한다. I/O 장치까지 직접가서 결과를 보고 오는 것을 보통 동기식 입출력이라고 볼 수 있다. IO 장치를 혼자만 접근하는 것이 아니라 여럿이 동시에 접근 할 수 있는데 A는 IO장치에 쓰고 B는 여기서 읽어오고 하는데 중간에 직접 확인하지 않고 바로 다음 일을 처리하면 이것은 synchronous하지 않은 Asychronous하다 라고 부르고 IO장치까지 가서 뭐가 적혀있는지를 직접 확인하고 읽어와서 그걸 보고 작업을 했다고 하면 synchronous read이고 IO장치에 뭔가를 써야하는데 그냥 쓰라고 하고 다음 일을 할 수도 있지만 쓰라고 한다음에 정말 써진 것을 확인하고 나서 그 다음 일을 실행하면 그것은 synchronous write가 된다.

IO를 수행하는 방법이 2가지 다른 방법이 있다. 좌측에 있는 그림이 일반적인 IO 방식이다.(I/O를 수행하는 special instruction에 의해) 이와 달리 우측에 있는 그림은 Memory Mapped I/O 방식이다.

 

CPU에서 직접 접근할 수 있는 메모리 스토리지 매체를 Primary(Executable)이라고 하고 CPU가 직접 접근 할 수 없는 메모리를 Secondary라고 한다. CPU가 직접 접근하기 위해서는 바이트 단위로 접근이 가능한 매체여야 한다. DRAM 메모리는 바이트 단위로 주소를 매겨서 바이트 단위 접근이 가능하기 때문에 Executable 하다. 그에 비해 하드 디스크 같은 경우는 바이트 단위 접근이 아니라 섹터 단위 접근이기 때문에 Executable 하지 않다.

CPU는 빠르게는 1 클락 당 인스트럭션 하나씩 처리하게 되는데 DRAM 메모리를 접근하려면 적게는 10에서 많게는 100클락 싸이클까지 걸리기 때문에 오래 걸린다. 이러한 속도 차이를 완충하기 위해 중간에 캐시 메모리라는 것을 두고 레지스터로 읽어들이고 이러한 작업을 수행하게 된다. 캐싱은 주로 재사용을 위해 사용한다.

 

프로그램은 보통 실행파일 형태로 하드디스크에 저장되어 있고 이를 실행시키면 메모리로 올라가서 프로세스가 된다. 정확하게는 물리적인 메모리에 바로 올라가는 것이 아니라 중간에 한 단계를 더 거치게 되는데 그게 바로 가상 메모리 단계이다.

어떤 프로그램을 실행시키면 그 프로그램의 메모리 주소 공간이 형성이 된다. 0번지부터 시작이 되는 그 프로그램만의 독자적인 주소 공간이 생기게 된다. 각각의 프로세스의 주소 공간은 code, data, stack의 영역으로 구성이 된다. code에는 CPU에서 실행할 기계어 코드를 담고 있고 data는 변수, 전역변수라던지 프로그램이 사용하는 자료구조를 담고 있고 stack은 코드가 함수구조로 되어있기 때문에 함수를 호출하거나 리턴할 때 데이터를 쌓았다가 꺼내가고 그런 용도로 사용된다.

모든 프로그램은 독자적인 가상 주소 공간을 가지고 있는데 이것을 물리 메모리에 올려 실행을 하게 된다. 가상 메모리의 주소 공간은 프로그램을 종료시키면 사라지게 된다. 프로그램을 실행시켰을 때 만들어지는 주소 공간을 물리적인 메모리에 통째로 다 올려놓는 것이 아니다. 그러면 메모리가 낭비가 되기 때문에 당장 필요한 부분에 해당하는 코드만 메모리에 올려놓게 된다. 그렇지 않은 부분은 올리지 않는다. 그리고 물리 메모리에 올라간 부분이 사용이 끝나면 쫓아내게 된다. 경우 따라서는 그냥 지워버리는 것이 아니라 프로그램의 실행이 끝날 때까지 보관하고 있어야 하는 부분이 있을 것이다. 이러한 부분은 디스크에 내려놓게 된다. 디스크의 Swap area라는 곳에 내려놓게 된다.

메인 메모리의 연장 공간으로 하드디스크를 사용하는 것을 Swapping, Swap area 용도로 사용한다고 한다. 이것을 버추얼 메모리 기법이라고 부르기도 한다. 하지만 프로그램마다의 독자적인 메모리 공간이 생기는 것을 보통 가상 메모리라고 한다. 그림에 보면 하드디스크가 두가지 부분으로 나뉘어 있는데 이 두가지는 용도가 다르다. 오른쪽 부분은 File system 용도이다. 전원이 나가더라도 파일은 내용이 유지가 된다. 왼쪽의 Swap area로 사용되는 하드디스크는 전원이 나가면 의미가 없는 데이터이다. 왜냐하면 전원이 나가면 프로세스는 종료가 되기 때문이다. 메모리에 있는 내용도 사라지기 때문이다.
Swap area는 메모리 공간의 한계로 메모리의 연장 공간으로 사용하고 오른쪽 하드디스크는 비휘발성의 용도, 전원이 나가도 내용을 유지하는 용도로 사용된다.

물리적인 메모리도 0번지 부터 시작하는 메모리 주소가 있다. 가상메모리에서 0번지부터 시작되는 특정 프로세스의 독자적 메모리는 물리 메모리에 올라갈 때 주소가 3000번에서 부터 시작된다던지 하는 식으로 주소가 바뀌어야 한다.(Address transition) 이러한 주소 변환을 해주는 주소 변환 계층이 존재한다. 이것은 운영체제가 할 수 있는 것은 아니고 이를 위한 하드웨어 장치가 따로 있다.

커널도 하나의 프로그램이기 때무에 code, data, stack으로 구성되어 있다. 그림은 이를 옆으로 눕힌 모습이다. 이 그림은 운영체제 커널 주소 공간의 내용이다. data 부분에는 운영체제가 사용하는 여러 자료구조가 정의되어 있다. 운영체제는 CPU나 메모리 디스크와 같은 하드웨어를 관리하고 통제한다. 이를 관리하기 위해 하드웨어 종류마다 자료구조를 하나씩 만들어서 관리를 하고 있다. 운영체제는 프로세스도 관리한다. 각 프로그램들이 독자적인 주소공간이 있는데 이를 관리하기 위한 자료구조가 필요한다. 어떤 프로그램이 CPU를 얼마나 썼는지, 그 다음에 누구한테 얼마나 메모리를 할당해야 할지 등을 결정하기 위해 각 프로그램마다 운영체제가 관리하고 있는 자료구조가 필요하다. 이를 PCB라고 부른다. (Process Control Block) 시스템 안에 프로그램이 하나 돌아가면 그 프로그램을 관리하기 위한 자료구조가 운영체제 커널에 하나씩 만들어진다. 운영체제도 함수구조로 코드가 짜여져 있기 때문에 함수를 호출하거나 리턴하 때 stack 영역을 사용해야 한다.

운영체제의 코드는 여러 프로세스들이 시스템 콜을 통해 사용을 할 수 있다. 그렇기 때문에 사용자 프로그램마다 커널 stack을 따로 두고 있다.

 

모든 프로그램은 함수 구조로 짜여져 있다. 프로그래밍 언어에 따라 별도로 짜여진 코드가 컴파일이 되어 기계어가 만들어지게 되더라도 그 기계어 구조에서는 함수에 해당하는 부분이 어디부터 어디까지 인지에 대한 정보가 유지가 되어 있다. 그래서 함수라는 용어를 고급언어가 아닌 인스트럭션 레벨까지 내려가서도 함수라는 용어를 계속 사용한다.
사용자 정의 함수든 라이브러리 함수든 컴파일 해서 실행파일을 만들게 되면 내 프로그램 안에 이 함수들이 모두 포함되어 있다. 반면에 커널 함수는 운영체제 안에서 정의된 함수고 이것도 내가 프로그램 안에서 가져다 쓸 수 있다. 하지만 이 코드는 내 프로그램 안에 있는 함수가 아니라 커널 코드 안에 있는 함수이다. 그래서 내 프로그램 안에는 커널 함수의 코드가 없다. 호출만 하게 되고 커널 주소 공간으로 넘어와서 커널에 있는 함수를 호출하게 된다.

우리가 보통 메모리 주소를 바꾼다 점프를 한다는 것은 물리적 메모리에서의 점프가 아니라 인스트럭션 차원에서는 가상 메모리의 주소상에서의 점프이다. 프로세스의 코드에서 커널 주소 공간은 아예 다른 영역이기 때문에 점프가 불가능하다. 이 부분은 시스템 콜을 통해 인터럽트 라인을 셋팅해서 CPU 제어권이 커널로 넘어가게 해서 커널함수를 실행하게 된다.

댓글 남기기

Close Menu