ACM Symposium on Operating Systems Principles 1973
Introduction
기본적인 하드웨어 설명과 함께, 유닉스를 이루는 근간인 소프트웨어들 그리고 C언어의 유용성에 대하여 설명하고 있다.
The File System
유닉스의 파일시스템은 크게 디스크 파일, 디렉토리, 그리고 특수 파일로 구성된다. Ordinary Files는 스토리지에 저장되는 기본적인 파일로서, 텍스트나 여러가지 문자열, 혹은 바이너리 파일을 저장하고 있다. 특수 문자를 이용하여 개행이나, 탭과 같은 특수 기호를 표시하도록 하였다.
디렉토리는 파일과 파일사이에 구조적인 관계를 제공한다. 유닉스는 기본적으로 Multi-User를 지원하기 때문에, 유저들은 각각의 디렉토리를 가지고 Permission을 구분하여 RWX를 구분하도록 하였다. Root 디렉토리는 유닉스에서 모든 디렉토리와 파일이 위치하는 최정점의 디렉토리로, 시스템이 제공하는 디렉토리이다. 또한 디렉토리에 따라서 유닉스에서 사용하는 여러 시스템요소들을 구분해서 저장할 수 있도록 하였다. 예를 들어서 어떤 디렉토리는 커맨드만을 저장하는 디렉토리도 있었다. 파일은 14개 이하의 (홀리...)문자열로 지정된다. /를 통해서 디렉토리를 구분하도록 하였다. 또한 링킹을 통해서 각각의 파일이 다른 파일을 가르킬 수 있도록 하였다. 또한 모든 폴더는 적어도 두개의 엔트리를 가지는데, 바로 .과 ..이다. 이 둘은 현재, 그리고 상위 디렉토리를 가르키는 위치를 담고 있다.
특수 파일은 Ordinary Disk File처럼 읽히지만, 특수한 내용을 가지고 있는 파일이다. 사실 특수 파일은 스토리지에 구현되어 있는 것이 아니라 메모리에 존재하면서 특수한 기능을 가지게 된다. 예를 들어서 /dev/ppt는 Punch Paper tape(!)의 디바이스를 가르키게 된다.
또한 각각의 파일시스템은 Mount를 이용하여 루트내의 그 어떤 서브디렉토리에도 마운트 될 수 있다. mount는 hierarchy tree 이하의 내용을 replace하게 된다.
시스템의 모든 유저들은 독특한 User Identification number를 부여받게 된다. 이 아이디로 User의 Permission을 구분하게 된다. 파일은 생성시 Owner User ID와 RWX비트를 가지게 되며 이를 통해서 접근 권한을 부여받게된다. 특히 Permission 비트중 마지막 7비트는 유저가 Effective User ID로 파일을 시행할 수 있도록 해준다. 이 말은, 이 비트가 설정되어 있으면 프로그램의 수행한 사람이 아닌 프로그램이 소속된 User의 Permission으로 프로그램이 실행될 수 있도록 해준다. 특히 모든 Permission은 단 하나의 Super User를 예외로 인식하여 모든 권한을 이 Super User에게 주도록 하였다.
또한 파일시스템에서 서로 다른 유저가 같은 파일에 접근할 수 있도록 하였다. 즉 Lock이란 개념을 파일에 적용하지 않았다. 이는 파일이 Permission에 의해서 보호받기 때문에 파일의 오너가 알아서 이 파일에 대한 Consistency를 보장하도록 하였기 때문이다.
각각의 파일은 유닉스 시스템안에서 아이노드로 구현되게 된다. 각각의 아이노드들은 아이노드 넘버를 부여받게 되고, 아이노드 넘버로 아이노드를 찾아서 파일에 관한 메타데이터에 접근하게 된다. 즉 open, close는 파일의 path를 가지고 적절한 아이노드를 만들거나 닫고, 아이노드 넘버를 가져오는 함수들이다. 이러한 아이노드 넘버는 각 프로세스에 FD (file-descriptor_)로 전환되고 TSS를 통해 저장되게 된다. 이떄 파일을 삭제하고 만드는 것은 아이노드에 있는 링크 카운트와도 관련되어 있다. 그렇다면 왜 카운트를 사용하는 것일까? 그것은 바로 하드 링크의 유무때문이다. 하드링크를 만들게 되면 파일 시스템에 링크 카운트가 1증가하게 되고, 결국, 링크 카운트가 0일때 파일을 삭제한다면 링크를 안전하게 구현할 수 있기 때문이다.
유닉스 시스템은 또한 page cache를 만듬으로써, file i/o에 대한 처리가 모든 read write에 대해서 이루어지지 않도록 하였다. 파일 io는 우선 buffer cache에 의해서 버퍼링된 다음, 일정한 시간 간격에 따라 혹은 fsync가 들어오면 그제서야 디스크로 이동하게 된다.
프로세스와 이미지
프로세스는 머신의 Abstraction이다. (여기서는 이미지-즉 머신의 Abstraction이라고 나옴). 프로세스는 text, data, stack 으로 가상 주소를 나누어 가지게 된다. (text, data는 loading에서 fix되어 0부터 되는 아래부터 시작하고, stack은 VMM high부터 시작하게 된다.)
그외 fork, execute, exit, pipe에 대한 설명이 있다.
The Shell
쉘은 유닉스의 기본 명령어 실행 유틸리티이다. 쉘은 그 자체로 명령어실행되는 프로그램이기도 하다. (즉 커널이 아닌 유저 프로그램이다.)
standard IO (STDIN, STDOUT, redirection)에 대한 설명이 있었다. 또한 shell에서 multitasking을 하는 방법이 소개되어 있다. 즉 백그라운드에서 명령어를 실행시키는 방법인 &과 다시 fg로 가져오는 방법들이 설명되어 있다.
쉘은 새로운 프로그램은 fork를 통해서 생성하게 된다. 만약 &가 주어지지 않으면, shell은 현재 프로세스로 바로 돌아오지 않고 wait을 호출하면서 fork한 주어진 프로그램이 끝나기를 기다린다.
UNIX는 커널 initailization이 끝난뒤, init 프로세스를 호출하게 된다. init은 user id와 identification을 기다리게 되며, 적절한 인풋이 들어오게 되면, shell을 user의 working direcotory에서 실행시키게 된다. 그 후 init은 다시 새로운 사용자가 로그인 하기까지 기다리게 된다.
Traps
만약 잘못된 명령이 수행되게 되면, (#PF, #GP, #InvOP...)시스템은 프로세스를 종료시키고, 그에 대한 정보를 출력시키게 된다. (지금은 libc에서 이 일을 해주고 있다.) 또한 프로그램은 interrupt signal 을 받을 수 있도록 하여서, 프로그램이 언제든지 종료될 수 있도록 하였다. 특히 quit시그널은 프로그램의 의지와는 상관 없이 강제로 종료시킬 수 있도록 하였다. 이는 프로그램중 불필요하게 오래동안 돌고 있는 프로그램을 언제든지 종료시킬 수 있도록 하였다.
Perspective
유닉스 시스템의 성공은, 유닉스 시스템에 특정한 목적이 아니라 general-purpose의 목적을 위해서 작성되었다는 점에 있을 것이다. 또한 Unix는 Berkeley time sharing system이나 Multics에 영향을 받았음을 밝히는 바이다.
특히 유닉스 시스템은 3가지의 디자인 컨셉을 가지고 작성되었다.
- 유닉스는 프로그램을 쉽고 빠르게 test하고 build할 수 있도록 작성되었다. (개발자 친화적이다.)
- 유닉스는 최소한의 자원에서 최대한의 성능을 발휘 할 수 있도록 작성되었다.
- 유닉스는 유지관리가 쉽도록 디자인 되었다. (왜냐하면 어셈블리가 아니라 source코드가 C니깐!!)