운영체제가 제공하는 서비스
종류
- 파일 시스템
- I/O 수행
- 하드웨어 리소스 할당: CPU 자원을 효율적이고 공평하게 사용하도록 스케줄링.
- 유저 인터페이스:
- CLI는 텍스트 기반으로 쉘에서 명령을 내릴 수 있도록 한 것. 깜빡거리는 것을 프롬프트라고 하며, 쉘이라고 이름 붙인 이유는 사용자가 세부적인 동작을 알 필요 없도록 껍데기로 감싸서 abstraction했다는 뜻이다. Bourne Shell, Bash가 대표적이다. Bash는 "born again shell"의 약자이다.
- GUI(Graphic User Interface)는 그래픽 UI를 통해 더 쉽게 사용할 수 있게 한 것. Mac OS X, 아이폰 터치스크린 인터페이스 등이 있다.
- Communication: 프로세스 사이가 격리되어 있고 직접적으로 데이터를 주고받을 수 없다. 서로 데이터를 주고받으려면 운영체제의 허락을 받아야 한다. IPC(Interprocess Communication)라고 부른다.
- Protection 및 보안
- 계정 관리
- 프로그램 실행 등

시스템 프로그램
- 정의: 프로그램 개발과 실행을 편하게 해주는 개발 환경. 시스템 유틸리티라고도 한다.
- 프로그래밍 언어 지원, 로드 및 실행 프로그램:
- 컴파일러: 광의의 컴파일러는 전처리기와 translator로 이루어져 있다.
#include
, #define
등의 전처리 지시문을 통해서 코드가 있는 걸로 가정을 하고 컴파일할 수 있도록 해준다. 실제 코드는 라이브러리에 존재한다. 소스코드를 컴파일하면 목적코드가 생성된다. 리눅스는 gcc
가 기본으로 탑재되어 있으나 윈도우는 별도로 다운로드받아야 한다.
- 링커: 컴파일이 끝나면 목적 파일이 소스코드 갯수만큼 나오는데, 목적 파일들을 묶어주는 것이 링커이다. 링킹을 하는 방식은 Static Linking과 Dynamic Linking으로 나뉜다. 일반적으로 Dynamic Linking을 많이 쓴다. Dynamic Linking은 예를 들어
cout
을 하는 코드가 있으면 해당 기능이 있는 라이브러리로 jump해서 수행하고 돌아오는 방식이다. Static Linking의 경우 코드 안에 cout
코드를 다 복사 붙여넣기 하여 결과적으로 바이너리 파일의 사이즈가 커진다. Static Linking을 많이 사용하는 분야는 임베디드이다. 공용 라이브러리의 사이즈가 커서 사용하는 부분만 복사 붙여넣기 한 다음 바이너리로 만드는 것이다. 공용 라이브러리는 윈도우에서는 .dll (dynamically linked library)
이고 리눅스에서는 .sa
나 .so
파일이다.
- 로더: 실행 파일을 실행했을 때 디스크에서 메모리로 올려주는 로딩을 수행한다.
- 파일 변경 프로그램: Windows의 Notepad, 리눅스의
vi
등의 텍스트 에디터.
- 통신: email 등의 통신 관련 서비스 제공.
- 상태 정보: 시스템 날짜, 사용 가능한 메모리, 디스크 공간 등의 시스템 정보 제공.
- 파일 관리:
ls
, cd
, rm
, mv
등의 명령어도 프로그램으로 구현되어 터미널에서 파일을 관리할 수 있도록 해주는 시스템 프로그램이다.
System Call 서비스
- 순서: Dual mode operator로 구현되어 있으며 user mode와 kernel mode로 나뉜다. user mode에서
read()
와 같은 시스템 콜을 호출해서 trap이 걸리면 kernel mode로 변경되어 프로세스 상태를 저장하고 trap handler가 동작한다. trap handler가 벡터 테이블에서 read()
의 핸들러를 찾아 커널에서 수행 후 프로세스에 결과를 돌려주고 user mode로 돌아간다.
- 시스템 콜은 함수 형태로 구현되어 있고 코드의 주소값을 알아야 해당하는 함수로 점프해 수행할 수 있다. 프로세스는 함수들의 주소를 벡터 테이블로 관리한다. 이를 시스템 콜 테이블이라고 한다. 시스템 콜의 input parameter는 레지스터를 통해서 넘겨준다. 예를 들어
printf()
같은 함수를 수행하면 printf()
함수는 stdio 라이브러리에 구현되어 있고, printf()
함수의 내부에는 write()
시스템 콜이 있다. 시스템 콜이 호출되면 인터럽트가 발생하고 커널이 CPU에 올라온다 (kernel mode가 된다). 트랩 핸들러는 레지스터에서 인덱스를 찾아 시스템 콜 테이블에서 인덱스의 값(주소)이 가리키는 시스템 함수를 실행한다. 작업이 끝나면 유저 모드로 되돌아간다. 이러한 과정이 내부에서 시스템으로 구현되어 있는 것이고, 우리가 직접 시스템 콜을 호출하는 경우는 애플리케이션 개발 레벨에서는 거의 없다.

- 시스템 콜 standard API를 보면 상세하게 시스템 콜에 대해 파악할 수 있다.
read()
는 파라미터 중 하나로 fd를 받는데, 파일 디스크립터라는 뜻이다. 파일 디스크립터는 프로세스에서 다른 파일을 정수값으로 매치해서 관리하는 테이블이다. 리눅스에서 파일 디스크립터 0, 1, 2번은 지정이 되어 있는데, 0번은 표준 입력 (stdin), 1번은 표준 출력 (stdout), 2번은 표준 에러 (stderr)이다. 유닉스 운영체제에서는 대부분의 요소가 파일처럼 취급된다. 디렉토리, 하드웨어 장치 등도 특수한 종류의 파일로 취급된다. 키보드 같은 입력 장치는 /dev
디렉토리에 있는 특수한 파일로 취급된다. 키보드를 타이핑할 시 /dev
디렉토리에 있는 파일에 데이터가 쓰여진다.
- 유닉스 계열과 윈도우의 시스템 콜은 형태가 다르다. 유닉스 계열의 운영체제들은 POSIX 표준에 따라서 만들어지기 때문에 시스템 콜의 형태가 같다. 윈도우는 스레드의 개념이 나오고 난 후 생긴 운영체제라서 시스템 콜이 다르고 호환성 문제가 있다.