본 포스팅은 Abraham Silberschatz 저 『Operating System Concepts』(9th Edition)의 내용을 개인 학습 목적으로 요약·정리한 글입니다.
2.1 운영체제 서비스
- 운영체제는 프로그램과 사용자에게 프로그램 및 서비스를 실행하기 위한 환경을 제공한다.
사용자에게 유용한 기능을 제공하는 서비스
1. 사용자 인터페이스(User interface)
1-(1) CLI : 문자열로 명령하는 인터페이스를 제공함.
1-(2) Batch Interace : 디렉티브가 파일 형태로 입력되고, 파일을 통해 인터페이스를 제공함.
1-(3) GUI : 가장 보편적. 그래픽 요소들을 통해 인터페이스를 제공함.
2. 프로그램 수행(Program Execution)
- System은 Program을 메모리에 load해서 실행할 수 있어야 한다.
- 프로그램이 정상적이든, 비정상적이든 실행을 끝낼 수 있어야 한다.
3. 입출력 작업(I/O Operation)
- 수행 중인 프로그램은 입출력을 요구할 수 있다.
- 사용자는 보통 입출력 장치를 직접 제어할 수 없으므로, 운영체제가 입출력 수행의 수단을 제공해야 한다.
4. 파일 시스템 조작(File System Manipulation)
- 프로그램은 파일을 읽고 쓸 수 있어야 하며, 이름에 의해 파일 생성/삭제/검색 등을 할 수 있어야 한다.
- 이에 많은 OS들은 다양한 specific feature와 Performance feature를 제공하기 위해 다양한 파일 시스템을 제공한다.
5. 통신(Communication)
- 한 프로세스가 다른 프로세스와 정보를 교환해야 할 필요가 있는 상황이 많다.
- 이러한 통신은 두 가지 방법(Shared Memory, Message Passing)에 의해 구현될 수 있다.
6. 오류 탐지(Error Detection)
- 운영체제는 모든 가능한 Error를 항상 의식하고 있어야 한다.
- Error는 CPU, Memory Hardware, I/O, 또는 User program에 의해 일어날 수 있다.
시스템 효율성을 보장하는 운영체제 서비스
7. 자원 할당(Resource Allocation)
- 다수의 User가 존재하거나 다수의 작업들이 동시에 수행될 때, Resource를 적절히 할당해주어야 한다.
- 예를 들어, CPU를 최대한 효율적으로 이용하기 위해 운영체제는 CPU Scheduling Routine이 CPU의 속도, 사용 가능한 레지스터 수 등의 다양한 요인을 고려하여 자원을 할당한다.
8. 회계(Accounting)
- 사용자가 컴퓨터 자원을 어떻게, 얼마나 많이 사용하는지를 알 수 있도록 해야 한다.
9. 보호(Protection)와 보안(Security)
- 보호(Protection) : 시스템 자원에 대한 모든 접근이 통제되도록 보장하는 것
- 보안(Security) : 각 사용자가 자원에 대한 접근을 원할 때, 시스템에게 자기 자신을 인증하는 것에서부터 시작
2.2 사용자 OS 인터페이스
-
명령 해석기(Command-Interpreter)
- Shell = 명령 해석기의 한 종류 (명령 해석기를 사용자와 운영체제 사이에서 작동하게 해주는 껍데기(Interfaces))
- 사용자가 입력한 명령어를 운영체제가 이해할 수 있게 해석하고 실행해주는 프로그램
-
GUI(Graphical User Interface)
- CLI에 비해 사용자 친화적. 마우스/터치스크린 등을 이용.
2.3 시스템 콜 (System Calls)
- 응용 프로그램(Application)이 운영체제와 통신하기 위한 방법
- 시스템 콜은 User Space → Kernel Space를 연결하는 유일한 인터페이스
-
그러나 대부분의 프로그래머들은 API를 통해 System Call을 호출한다.
- 일반적으로 고급 언어(C,C++)로 프로그램을 작성
- API를 사용 시 이식성이 높아짐
- System Call을 직접적으로 사용하기 어려움
-
System Call을 직접 사용하는 경우
-
API를 사용하는 경우
Linux 시스템 콜 예시
- User Space의 사용자 애플리케이션이 getpid() 호출
- getpid 함수는 시스템콜 번호를 EAX 레지스터에 설정함
mov $NR_getpid, %eax
- 커널 진입 (
int $0x80
어셈블리 명령을 실행하여 커널 모드로 진입) -
커널의 공통 시스템 콜 진입 지점인
system_call
함수가 실행됨- 여기서
eax
레지스터의 값을 기준으로 시스템 콜 테이블에 접근 call system_call_table[eax]
- 여기서
- 시스템콜 번호(eax)에 따라
sys_getpid
,sys_fork
,sys_exit
등 커널 내부 구현 함수 호출 - 실제 커널 함수 실행 (
sys_getpid
) -
결과 반환 → 사용자 공간 복귀
- 결과를 eax 레지스터에 담고,
syscall_exit
루틴을 통해 사용자 공간으로 복귀
- 결과를 eax 레지스터에 담고,
시스템 콜 구현
-
리눅스에서의 시스템 콜 구현 (시스템 콜을 추가할 때 올바른 순서)
-
System Call 함수 정의
-
System Call 번호 할당
-
System Call 함수 등록
-
커널 Rebuild & Test
make bzImage
,make modules
, qemu 등으로 빌드 & 테스트 수행
-
- 사용자 정의 System Call 호출해보기
-
일반적으로 각 시스템 콜(System Call)에 숫자가 할당됨
- 시스템 콜 인터페이스는 이 숫자에 따라 인덱싱된 테이블을 유지
- 시스템 콜 인터페이스는 운영 체제 커널에서 의도된 시스템 콜을 호출하고, 시스템 콜의 상태 및 반환 값을 반환
-
호출자는 시스템 호출이 어떻게 구현되었는지 구현 방법을 알 필요가 없음
- 단지 API를 준수하고, 시스템 콜이 실행되면 OS가 무엇을 해주는지 이해하면 됨
- OS 인터페이스의 대부분의 세부 사항은 API에 의해 프로그래머에게 숨겨짐
- 런타임 지원 라이브러리(컴파일러와 함께 제공되는 라이브러리에 내장된 함수 집합)에 의해 관리
운영체제에 매개변수를 전달하기
-
운영체제에 매개변수를 전달하는 방법은 크게 3가지가 있다.
-
레지스터에게 매개변수 전달
- 그러나 경우에 따라 레지스터보다 더 많은 매개변수가 필요할 수 있음
- 메모리의 블록(또는 테이블)에 매개변수 저장하고, 해당 블록의 주소를 레지스터에 매개변수로 전달
-
매개변수를 블록이나 스택에 푸시하여 저장
- 블록 및 스택 방식은 전달할 매개변수의 수나 길이에 제한을 두지 않음
-
API - 시스템콜 - 운영체제 간의 관계
-
사용자 프로그램(애플리케이션)이 API 함수 open() 을 사용
- open() 은 C 표준 라이브러리에 정의된 API 함수
-
API가 System Call Interface를 호출
syscall(SYS_open, ...)
같은 식으로 시스템 콜 번호와 인자를 준비함.- 이 과정은 사용자 모드에서 실행되고, SysCall 명령어 또는 시스템 콜 트랩을 통해 커널 모드로 전환함
- System Call Interface가 시스템 콜 테이블에서 번호에 맞는 적절한 함수를 찾아 실행
- 커널이 실제 자원 처리 ( = 파일 열기)
2.4 시스템 호출의 유형(Types)
-
Process Control (프로세스 제어)
- 정상적으로(end()), 혹은 비정상적으로(abort()) 종료
- 적재(load), 수행(execute), 대기(wait) 등
-
File Manipulation (파일 조작)
- 열기(open), 닫기(close), 읽기(read), 쓰기(write), 위치변경(reposition)
-
Device Manipulation (장치 조작)
- 장치 요구(request), 방출(release), 읽기, 쓰기, 위치변경
-
Information Maintance (정보 유지 보수)
- 시간(time), 날짜(date) 반환
-
Communication (통신)과 Protection (보호)
-
Message Passing Model
- 통신하는 두 process가 정보를 교환하기 위해 서로 메시지를 주고받는다.
-
Shared Memory Model
- 다른 process가 소유한 메모리 영역에 대한 접근을 하기 위해 System call을 사용한다.
- 대부분의 System은 두 가지 모두를 구현한다.
-
2.5 시스템 프로그램
- 시스템 프로그램은 시스템 유틸리티(System Utility)로 알려져 있으며, 프로그램 개발과 실행을 위해 보다 편리한 환경을 제공한다.
- 시스템 프로그램은 파일 관리, 상태 정보, 파일 변경, 프로그래밍 언어 지원, 프로그램 적재와 수행, 통신, 백그라운드 서비스의 범주로 분류할 수 있다.
2.6 운영체제 설계 및 구현
- 일반적인 목적의 OS는 매우 큰 프로그램이다
-
운영체제의 다양한 구조화 방법들
- Simple Structure : MS-DOS
- More Complex: UNIX
- Layered: 추상화
- MicroKernel : Mach
1️⃣ MS-DOS
- 간단한 구조. 가장 작은 공간에 최대의 기능을 제공
-
모듈로 나누어지지 않음
- User Program이 고장 나게 되면 시스템 전체가 고장나게 된다.
-
MS-DOS는 일부 구조를 가지고 있지만, 그 인터페이스와 기능의 수준은 잘 구분되어 있지 않음
- 예를 들어, Application Program은 basic I/O routine을 통해 display와 disk drive에 직접 쓰기가 가능하다.
2️⃣ UNIX
-
유닉스는 커널과 시스템 프로그램의 두 가지 분리된 부분으로 구성됨
-
시스템콜 Interface와 커널 Interface 사이의 모든 것이 커널이다.
- 즉, 시스템콜 인터페이스 ~ (물리적) 하드웨어 사이의 모든 것 = 커널
-
단일 레벨(커널)에서 시스템콜을 통해 파일 시스템, CPU 스케줄링, 메모리 관리 등의 다양한 기능을 제공
- 이 Monolithic(돌덩이같은) 구조는 구현하기 어렵고, 유지 보수하기 어렵다는 단점이 있다.
3️⃣ 계층적 접근 (Layered)
-
OS는 여러 개의 레이어로 나누어지며, 각 레이어는 하위 레이어 위에 구축됨
- 최하위 층(Layer 0)는 Hardware이고, 최상위 층(Layer N)은 User Interface(UI)이다.
- 적절한 hardware support가 있을 경우, 운영체제는 보다 적절하게 분할될 수 있다.
-
계층적 접근의 장점
- 구현과 디버깅이 간단하다
- 하위 층부터 구현하며 상위 층을 시도하므로, 버그 발생 시 해당 층에서의 오류임을 바로 파악 가능하다
-
계층적 접근의 단점
- 여러 개의 계층을 적절히 정의하기가 어렵다.
- 다른 유형보다 효율성(속도)가 느리다.
- 시스템 호출이 모든 하위 레이어를 거쳐야 하므로, 각 레이어가 추가하는 오버헤드가 발생
4️⃣ 마이크로 커널 (Microkernels)
-
커널에서 중요하지 않은 많은 부분을 제거하고, System 또는 User Space로 이동시킴
- 즉, 마이크로한 커널 = 마이크로커널 구조
- 마이크로커널의 주 기능 = User Program간의 Message 전달 (=Communication)
-
마이크로커널 구조의 장점
- 운영체제 확장이 용이하다 (모든 새로운 서비스는 User Space에 들어감)
- 커널을 변경해야 한다고 하더라도, 크기 자체가 작아 변경할 부분이 많지 않다
-
마이크로커널 구조의 단점
- System-Function의 overhead가 증가하여 성능이 나빠진다
5️⃣ 모듈 (Modules) 구조
-
많은 현대 운영 체제는 로드 가능한 커널 모듈을 구현 (현대 Linux 등)
- 객체지향 접근방식을 사용
- 각 핵심 구성요소는 분리되어 있음
- 각 구성요소는 정의된 인터페이스를 통해 서로 통신
- 필요한 경우 커널 내에서 로드 가능
-
각 부분이 별도 정의되고 Protected Interface를 가진다는 점에서 계층적 구조와 비슷하다.
- 하지만, 모듈에서 임의의 다른 모듈을 호출할 수 있다는 점에서 계층적 구조보다 유연하다.
6️⃣ 하이브리드 시스템 (Hybrid Systems)
-
하나의 구조만을 채택한 운영체제는 거의 존재하지 않으며, 보통 여러 구조를 결합한 혼용 구조로 구성된다.
- Linux는 Monolithic 구조임과 동시에 새로운 기능을 동적으로 추가 가능한 Module을 사용
- Windows도 Monolithic + 동적 적재 가능한 커널 모듈 지원