위의 내용을 기반으로 OS의 진화 과정에 나오는 키워드들을 자세하게 알아보자.
Serial processing이란 연속적으로 하나씩 프로세스를 처리하는 방법이다.
OS가 존재하지 않던 시절 인간이 OS의 역할을 했으며, 여기서 사용하던 것이 Serial procesing, 즉 하나씩 연속적으로 처리하는 job-to-job transition을 사용하였다.
당시에 소스코드를 펀치카드와 비슷한 카드에 적었다고 한다. 이를 위한 컴파일러가 필요하며, 카드 리더 등 기계들을 탈부착했어야 하며 이를 모두 인간이 했다.
Serial processing의 문제점은 두 가지이다.
- 인간이 수동으로 setup을 하였으므로, 시간이 많이 소모된다.
- 작업에 대한 시간을 측정할 수없고, 하나씩 순차적으로 진행되므로 낭비되는 시간이 많았다.
이 시절엔 현대의 시스템과 다르게 응답시간, 대기시간을 척도로 삼지 않고, CPU 활용률에만 집중하였다. 낭비되는 시간이나 setup time을 줄이고자, 비슷한 job들을 하나로 묶었다. 자동화를 한 것이다.
1401은 별도의 I/O 장치들이며 하나로 묶어, setup time이 줄어든다.
자동화를 통해, job-to-job transition을 없애는 목표로 나온 OS이다. 이를 Batch Monitor(Batch OS)라 부른다.
자동화로 인해 OS 메모리에 항상 존재해야한다. 이러한 이유로 Resient monitor라고도 부른다.
위와 같이 boundary 기준으로 process와 OS가 분리되었고, job을 위해 control을 User program 영역에 부여하고 job이 끝나면 다시 OS가 가져오고 I/O에 결과를 출력한다. 이렇게 다른 job을 다시 OS가 지정할 수 있다.
이런식으로 자동화를 구현하기 위해 별도의 job control language(JCL)이 필요했다.
반복, 시작 등을 제어한다.
- Memory protection: user 수준의 버그가 많이 존재했다. Monitor가 존재하는 영역에 접근, 수정이 일어나는 것을 하드웨어가 막는 기능이 필요했다.
- I/O protection: 카드덱의 job을 읽거나 하는 이슈들을 막아야 하는 기능이 필요했다.
- Dual mode: I/O에 접근 또는 Monitor 메모리 영역에 접근하기 위해서 user mode가 아닌 kernel mode가 필요했다.
- CPU protection: 프로세스의 독점(e.g. 무한루프) 등을 막기 위해 System timer를 통해 특정 시간을 넘어가면 job을 중단한다.
위와 같은 동작을 위해 Interrupt 기능이 필요했다.- I/O device controller: I/O CPU가 직접 관리하면 활용률이 떨어지는 단점이 있는데, 이를 직접 관리하는 디바이스가 필요했다.
file read와 같은 Synchronous I/O는 cpu가 프로그램을 처리하다 job이 끝내기 전까지 무조건 기다려야한다.(이의 반대는 file write와 같은 Asynchronous I/O이다.)
이러한 자동화에도 불구하고, card reader가 너무 느리기 때문에, cpu의 활용률에 치명적이었다.
file read의 경우, 무조건 cpu가 job이 끝날 때까지 기다려야하기 때문에 CPU의 활용률이 현저히 낮다. 이를 해결할 방법은 multiprogramming이다.
현재 진행중인 작업을 메인 메모리에 남겨두고, job들이 멈췄을 경우, 다른 job을 수행해 옮겨 병행적으로 수행하는 것을 의미한다.
그런데 어떤 job을 선택해야할까? 이는 cpu scheduling에서 알아보자.
위의 내용을 보면, Wait를 read라 생각해보자. 프로그램마다 read가 발생할 경우, 이 때 병행적적으로 프로그램을 바꾸면, 다음과 같이 기다리는 시간에 다른 프로그램을 수행한다. CPU 활용도가 증가한다.
하지만 무한대로 좋아지지 않는다. 그래프로 나타냈을 때, 중간에 꺾인다. 이를 Virtual memory에서 자세히 알아보자.
Relocation 문제는 umiprogramming일 때, job 하나만을 처리하기 때문에 시작주소가 고정되어 있었다. 다른 일을 처리하고 와도 주소가 고정되어 있기에 상관없었다. 하지만 ultiprogramming일 때 2개 이상의 job은 OS가 메모리에 할당하기 때문에, 위치가 어디인지 알 수 없다. 게다가 잘 처리되지 않는 job은 메모리에서 할당 해제될 수 있기 때문에 다시 로드되면 주소가 바뀌는데 이를 알 수도 없다.
job들과 OS 영역 등, 메모리를 잘못 침범하는 문제도 발생하였다.
위의 레지스터 두 개로 job간의 경계를 나눌 수 있게 되었다.
CPU가 접근할 job의 logical 주소에 Base register의 값(job의 시작 주소)을 더해 물리적 주소를 구한다. 이를 Bound regsiter의 값(job의 마지막 주소)와 비교해 이를 넘어가면 예외, 넘어가지 않으면 메모리에 접근하게 해준다.