유닉스 & 리눅스의 탄생과 구성
유닉스
- 1969년 AT&T 산하의 벨 연구소에서 켄 톰슨과 데니스 리치가 개발
- 어셈블리어로 개발 후 C로 재작성
- 데니스 리치가 연구한 멀틱스가 기반이 됨
- 개발 후 소스 코드 공개, 대학과 기업들에서 이를 이용한 연구를 진행해 다양한 기능 추가
- 상업용 유닉스와 버클리의 BSD로 분리되어 발전
- 두 계열의 장점을 결합한 SVR4를 기반으로 다양한 버전 개발 → 솔라리스
- 대화형 시스템
- 멀티 유저, 멀티태스킹
- 높은 이식성과 확장성
- 계층적 파일 시스템 구조
리눅스
- 멀티 유저, 멀티태스킹을 지원하는 유닉스와 비슷한 운영체제
- 멀티 유저: 여러 사용자가 동시에 동일한 시스템에 접근 가능
- 멀티태스킹: 여러 개의 태스크를 동시에 실행하고 교대로 컴퓨터의 자원을 사용
- 리누즈 토르발즈에 의해 독립적으로 자체 커널이 개발된 공개용 운영체제
- 누구에게나 자유롭게 배포 가능
- 안정성, 보안성, 신속한 기능의 보강 가능
- CUI 및 GUI의 지원
- 여러 종류의 파일 시스템 지원
- 쉘 기능 제공
- 하드웨어 기능을 효과적으로 사용
- 다른 운영체제보다 적은 양의 메모리를 필요로 함
- Swap 방식을 통해 메모리의 효율을 높일 수 있음
리눅스의 발전 과정
- 1985: 리차드 스톨만 GNU Manifesto 발표
- 1991: 토르발즈 리눅스 개발
- 2000년 이후: 급격한 리눅스 시장의 발전에 발 맞춰 사용자가 급격히 증가
GNU 프로젝트
- 리차드 스톨만에 의해 1984년 창설
- 소프트웨어를 공유했던 최초의 공동체
- 현재는 Free Software Foundation이라는 이름으로 활동
유닉스 프로세스 관리와 시스템 호출
유닉스 프로세스
- 사용자 프로세스: 단말기의 사용자와 관련된 프로세스
- 커널 프로세스: 커널 모드에서 실행, 프로세스 0이 해당
- 데몬 프로세스: 다른 사용자와 관련이 전혀 없으나, 전역 함수와 같이 네트워크 제어·관리 등 시스템을 지원하는 프로세스
- 유닉스는 사용자 프로세스 환경에서 실행되므로 사용자 모드와 커널 모드가 필요
- 시스템 프로세스와 사용자 프로세스가 모두 사용됨
- 시스템 프로세스: 커널 모드에서 동작하며, 프로세서 할당과 프로세스 스케줄링, 메모리 할당, 프로세스 교환 등 시스템 관리 작업을 수행하는 운영체제 코드를 실행
- 사용자 프로세스: 사용자 모드에서 동작, 사용자 프로그램이나 유틸리티 수행, 인터럽트 등 발생하면 시스템 호출을 하여 커널 모드로 들어감
프로세스 테이블
- 정보를 프로세스마다 유지하며 항상 메인 메모리에 상주
- 프로세스 상태 필드(준비 상태, 실행 상태, 수면 상태 등)
- 사용자 영역 포인터
- 프로세스 식별자, 사용자 식별자
- 프로세스 크기, 이벤트 디스크립터, 스케줄링 매개변수 항목 등
- 공유 코드가 있는 프로세스에서 텍스트 테이블을 유지
사용자 테이블
- 프로세스가 대치되지 않고 메모리에 있을 때 필요한 정보 보관
- 해당 프로세스 활성화 때만 메인 메모리의 임시 영역에 적재
- 커널 가상 데이터 영역으로 매핑, 개방된 파일의 테이블은 사용자 테이블에 유지
각 프로세스의 사용자 영역
- 텍스트: 프로그램의 명령어들이 저장되어 있고, 읽기만 가능
- 데이터 & 스택: 항상 같은 주소 공간에 있지만 독립적으로 반대 방향으로 늘어남
- 커널을 실행할 때 필요한 추가 정보가 들어있음
- 프로세스의 테이블 포인터
- 시스템 호출 매개변수
- 사용자 식별자, 사용자와 커널의 사용 시간
- 시스템 호출을 할 때 발생하는 오류, 시스템 호출의 반환 값
- 프로세스가 시그널으르 수신했을 때 수행하는 동작
- 입출력과 파일의 매개변수 등
유닉스 프로세스 스케줄링
- 시분할 시스템에서 커널은 각 프로세스에 시간 할당량이라는 시간 동안 프로세서 할당
- 시간 할당량을 초과하는 경우에는 해당 프로세스를 중단시키고 다른 프로세스를 스케줄링함
- 스케줄링: 컴퓨터 시스템의 모든 자원의 성능을 향상시키기 위해 자원에 대한 사용 순서를 결정하기 위한 정책
- 프로세스들은 프로세서 위주의 작업들을 수행하는 순환 할당 알고리즘과 같은 우선순위 알고리즘으로 프로세서의 시간 일부를 할당 받음
- 유닉스 스케줄러는 다단계 피드백이 있는 순환 할당 스케줄러에 속함
- 커널이 프로세스에 프로세서 시간 할당, 프로세스가 할당된 시간을 초과하는 경우 중단한 후 여러 우선순위를 갖는 큐 중에서 우선순위가 가장 높은 것 하나를 선택함
파일 조작
- 유닉스에서 파일은 바이트의 연속이지만, 커널 측면에서는 어떤 구조도 없음
- 파일은 트리 구조의 디렉터리에서 생성
- 파일인지 디렉터리인지는 경로명 형식으로 구별 불가
- 유닉스의 경로명은 절대 경로명과 상대 경로명으로 구분
- 절대 경로: 파일 시스템의 루트에서 /로 시작
- 상대 경로: 현재 디렉터리에서 시작
- . : 디렉터리 자신을 가리키는 하드 링크(물리적 링크)
- 원본을 삭제해도 원본과 내용이 동일한 파일이 있어, 자원이 공유하면서 데이터도 안전하게 관리
- 파일 복사와 비슷하지만 차이점 존재 (i 노드를 복사하는지 공유하는지)
유닉스의 주요 디렉터리
- /: 최상위 루트 디렉터리
- /bin: 명령어가 있는 디렉터리
- /boot: 시스템 부팅 관련 파일
- /dev: 시스템 디바이스 파일
- /etc: 시스템 전체 환경 설정 파일
- /home: 사용자의 홈 디렉터리
- /lib: 프로그램에 필요한 각종 라이브러리
- /mnt: 플로피, CD-ROM 등 마운트를 위한 디렉터리
- /sbin: 시스템 관리자용 명령어
- /tmp: 일시적인 저장을 위한 디렉터리
- /usr: 각종 어플리케이션 등이 설치되어 있는 디렉터리
- /usr/src: 프로그램 소스(주로 커널 소스)가 저장되는 디렉터리
- /usr/local: 아파치같은 추가 소프트웨어가 설치되는 장소
- /var: 시스템 운용 중에 생성되었다가 삭제되는 데이터를 저장하는 디렉터리
- /var/log: 각종 로그파일
프로세스 제어
- 새로운 프로세스는 fork 명령어로 만들고, 부모 프로세스 주소 공간의 복사본(동일한 프로그램과 값이 똑같은 동일한 변수)으로 구성
- 부모와 자식 관계의 프로세스는 fork 명령어를 수행 후에도 같은 명령을 계속 실행
- 새로운 자식 프로세스는 fork 명령어의 반환 값으로 0을 반환
- execve: 가상 메모리에 새로운 프로그램을 대치, 부모와 자식 프로세스 중 한 프로세스 생성 후 사용하는 명령어
- exit 명령어로 종료, 부모 프로세스는 wait 명령어를 통해 자식 프로세스가 종료할 때까지 대기
- 자식 프로세스에 오류가 발생하면 exit 명령어로 빠져나옴
- 자식 프로세스가 존재하는 시간과 부모 프로세스가 wait 명령어를 끝내는 시간 사이에 프로세스는 아무 일도 하지 않음
- 부모 프로세스를 자식 프로세스보다 먼저 종료하는 경우 자식 프로세스는 좀비 프로세스가 됨
프로세스 시그널
- 프로세스에게 어떤 이벤트의 발생을 알리기 위해 전달되는 소프트웨어 인터럽트
- 커널 모드에서 사용자 모드로 돌아가기 직전 우선순위가 낮은 프로세스가 수면 상태로 들어가거나 깨어나는 경우 → 시그널의 수신 여부 조사
- 커널 모드에서 사용자 모드로 돌아가는 경우 → 시그널 처리
- 시그널은 커널 모드에서 실행 중인 프로세스인 경우 → 즉각적인 효과 없음
- 한 프로세스를 사용자 모드에서 실행 중이고 그 프로세스로 시그널을 보낸 인터럽트를 커널이 처리한 경우 → 커널은 인터럽트에서 돌아올 때 그 시그널을 인식하고 처리
- 프로세스는 미해결 상태의 시그널을 처리하기 전인 경우 → 사용자 모드에서 실행 불가
유닉스 메모리 관리
- 유닉스는 처음에 단일 사용자를 위해 개발, 나중에는 다중 사용자 환경에 적합하도록 발전
- 다중 프로그래밍 유닉스에서는 메모리 관리 방법으로 스와핑(대치)이나 페이징 사용
- 크기가 작은 작업 → 스와핑
- 다수의 큰 작업 → 페이징
- 메모리 관리자: 각 프로세스를 메모리에 저장하는 동안 중첩되지 않도록 보호, 메모리에 상주하는 커널은 여러 프로세스가 메모리에 동시에 있도록 메모리 경계 설정
스와핑
- 메모리와 가상 메모리 사이의 프로세스 이동은 스와퍼라는 스케줄러에 의해 처리
- 메모리에서 가상 메모리로의 스와핑은 새로 적재될 프로세스에 대한 메모리의 여유 공간이 없을 때 발생
- 실행될 준비가 된 프로세스들이 있다면 가상 메모리에 가장 오래 있었던 프로세스를 선택한 다음 어떤 방법으로 스와핑할 지 조사
페이징
- 프로세스 및 디스크 블록 버퍼에 메인 메모리의 페이지 프레임을 할당하는 가상 메모리 기능
- 사용자 프로세스와 디스크 입출력 위해 효과적 메모리 관리 가능
- 메모리의 외부 단편화를 해결할 수 있지만 내부 단편화가 발생
- 복잡한 하드웨어 구성과 시스템 오버헤드의 증가, 작업 부하가 크면 스래싱 현상 야기
- 스래싱: 메모리 영역에 접근하게 될 때, 메모리에 페이지가 부재하여 페이지 폴트(Page Fault)율이 높은 상태
- 페이징을 구현하여 프로세스의 전체 가상 주소 공간을 메모리에 적재하지 않아도 수행 가능
페이지 교체 알고리즘
- Page Replacement Algorithm
- 실행 중인 프로토콜 지원
- 사용 가능한 프레임을 충분한 유지를 위해 최소 사용 알고리즘 사용
- 최근에는 수정된 시계 페이지 교체 알고리즘(CLOCK ?)을 사용
- 일단 여기 [링크 - 페이지 교체 알고리즘] 나중에 참고..
페이징 구현과 프로세스
- 프로세스의 가상 주소 크기가 시스템에서 이용 가능한 물리적 주소의 양 초과
- 프로세스는 제한된 지역을 중심으로 참조하는 지역성 원리 적용
- 프로세스가 참조한 페이지 집합 → 작업 집합
- 전체 프로세스의 작은 부분
- 스왑 시스템보다 많은 프로세스를 동시에 메인 메모리에 적재하여 스왑량과 시스템의 스래싱 현상 감소
유닉스 파일 시스템
디스크 블록의 구조
- 디스크 블록: 자유 디스크 블록의 번호를 포함하는 배열 형태, 이 중 한 항목은 다음 디스크 블록의 번호를 가리킴
- [부트 블록] + [슈퍼 블록] + [i 노드 * n] + [데이터 블록...]
- 부트 블록: 파일 시스템에 유닉스 커널을 적재시키는 프로그램을 포함, 이런 프로그램을 부트 스트랩 또는 부트 로더라고 함
- 슈퍼 블록: 파일 시스템을 관리하는 아래의 정보를 저장
- 파일 시스템에 있는 블록의 총 수
- 파일 시스템에 있는 자유 i 노드의 리스트와 i 노드 수
- 파일 시스템에서 이용 가능한 자유 블록 리스트(비트맵)
- 바이트 단위로 된 블록의 크기
- 자유 블록 수, 사용 중인 블록 수, 파일 수
- 자유 i 노드 리스트에서 다음 자유 i 노드를 가리키는 인덱스
- 데이터 블록: 일반 파일이나 디렉터리 파일의 내용이 들어있음
- i 노드: i 노드 여러 개로 구성
- 파일 관리에 필요한 정보 저장
- 파일 하나에서 하나의 i 노드를 만듦
- i 노드 번호라고 하는 번호로 구별
유닉스의 연속 파일 할당
- 파일에 디스크 블록을 하나씩 할당하여 블록들이 파일 시스템의 여러 곳에 분산되도록 함으로써 융통성 높임, 이런 할당 방법은 데이터를 찾는 알고리즘을 복잡하게 함
- i 노드 리스트에 파일의 데이터가 들어 있는 블록 번호를 모두 담을 수 있지만, 이런 선형 목록은 관리가 어려움
유닉스의 디렉터리
- 디렉터리 내용은 데이터 블록에 있고 일반 파일처럼 i 노드로 표현, i 노드의 형태 필드만 일반 파일과 디렉터리 구분
- 경로명의 첫 글자가 /이면 루트 디렉터리이고, 그 외는 현재 디렉터리를 나타냄
- 사용자는 경로명으로 파일 참조, 파일 시스템은 i 노드 혹은 기억된 i 노드를 사용하여 파일을 정의
- 커널은 사용자 경로명을 i 노드로 맵핑해야 함
디렉터리 사용 시 규칙
- 경로명이 /로 시작하면 루트 디렉터리에서 시작
- 경로명에서 마지막 이름은 요청한 파일 이름
- 경로명에 .이나 ?이 나타나면 .은 현재 디렉터리, ?은 상위 디렉터리를 의미 → 모든 경로명은 이 둘을 제외하고 트리 아래쪽으로 진행
- 경로명에는 공백 사용 불가
유닉스의 디스크 구조
- 사용자가 보는 파일 시스템은 일반적인 디스크의 데이터
- 논리적 파일 시스템 하나는 대부분 여러 물리적 파일 시스템으로 구성
- 디스크와 같은 물리적 장치는 여러 논리적 장치로 나눠서 물리적 장치 정의
- 각 파일 시스템을 다른 용도로 사용 가능
- 소프트웨어 손상이 파일 시스템 하나에만 제한되므로 신뢰성 증가
- 각 분할 부분에서 파일 시스템 매개변수(ex. 블록과 단편화 크기)를 변화함으로써 효율 향상