* 본 글은 학부생의 입장에서 공부 내용을 정리하기 위해 작성되었습니다. 틀린 내용이 있으면 피드백 부탁드리며, 무분별한 비방 작성시 차단 될 수 있음을 알려드립니다.
안녕하세요 파일입니다. 이번에 UNIX 시스템 프로그래밍에 대해서 학습하게 됐는데 기억을 잊지 않고자 관련 내용을 정리하고자 합니다. 만약에 UNIX 기반 운영체제나, Linux 등을 잘 모른다면 해당 포스팅을 먼저 선행 학습하시고 해당 글을 읽는걸 추천드립니다. 기본적으로 전공자를 대상으로하며, 컴퓨팅 시스템의 대략적인 이해를 가지고 읽는걸 권장합니다.
우선 시스템 프로그래밍 (소프트웨어) 에 관한 내용을 알아보기 앞서 필요한 간단한 사전지식을 획득하고 넘어가 보겠습니다. 우리는 기본적으로 컴퓨터를 사용 시 HW를 직접 이용하진 않습니다. 음? 저는 컴퓨터도 제가 부품 하나하나 보면서 조립하고 쓰는데요? 라고 생각할 수 있지만 그런 의미는 아니구요, 컴퓨터를 사용할 때 기계 그 자체 쌩으로 이용하지 않는다는 의미입니다.
우리는 컴퓨터를 사용할 때 먼저 운영체제(OS)를 설치하고 사용하게 됩니다.
윈도우라던가 리눅스 등등을 설치해서요. 사실상 운영체제 없이 컴퓨터를 그대로 사용하는건 불가능에 가깝고 그렇게 할 이유도 없습니다. 당장 CPU만 생각해봐도 일반적으로 Data Path 와 Control Unit 등으로 구성된, 계산을 잘하는 기계에 불과합니다. (뭐 사실 계산말고도 여러가지를 할 수 있긴 합니다..) 운영체제가 없다면 화면도 안들어오는 상황에서 이 계산 잘하는 CPU한테 하나하나 명령을 내려서 일을 해야겠죠 (...)
이미 똑똑한 천재들이 컴퓨터를 쉽게 사용할 수 있는 환경을 제공해줬으니, 우리는 컴퓨터에 OS를 그냥 설치해서 그 위에서 프로그램도 돌리고, 여러 작업도 수행하면 된다는 뜻입니다.
컴퓨터 시스템의 4가지 구성 요소
본 사진은 컴퓨터 시스템의 4가지 구성요소를 일종의 계층도로 나타낸 모습입니다.
영어가 나와서 좀 거북할 수 있는데 그냥 영어 단어 뜻 그대로 읽으시면 됩니다.
맨 밑부터 하나하나 알아봅시다.
1. computer hardware
가장 아랫단에 존재하는, 우리가 흔히 컴퓨터 하드웨어라고 하는 부분입니다. CPU, Memory(Dram), I/O 장치 (키보드, 모니터, HDD, SSD) 를 포함하는 개념입니다. 기본적인 컴퓨팅 자원을 제공해주게 됩니다.
2. operating system (os)
위에서 열심히 설명한 OS입니다. 컴퓨터 하드웨어 위에서 돌아가면서, 매우 많은 일들을 수행해주는데 그 중 매우 중요한 일이 바로 여러 프로그램을 실행시켜주는 기능입니다. HDD/SSD 같은 저장장치에서 프로그램을 메모리에 로드해 실행시키는 역할을 하게 됩니다. 만약 OS가 없으면 더블클릭을 해서 실행 파일을 실행시킬 수 없겠죠?
3. system and application programs
application programs 는 우리가 흔히 응용 프로그램이라고 하는 사용자의 문제를 해결해주는 UI를 가진 프로그램을 의미하는 것이고 (우리가 컴퓨터에서 키는 워드프로세서, 포토샵 같은 모든 프로그램을 총칭합니다), system programs 가 바로 본 글에서 다루는 시스템 프로그램 (시스템 소프트웨어) 을 의미하게 됩니다. 뒤에 가서 한번더 설명할 것이지만 시스템 소프트웨어는 쉽게 말해서 UI가 존재하지 않는, 개발을 위해 사용하는 프로그램을 의미합니다. 예로 DB나 컴파일러를 예로 들 수 있겠네요.
4. user
컴퓨터를 사용하는 사용자로써, 맨 위에 존재하게 됩니다.
운영체제와 시스템 콜 (OS& System Call)
OS(Operating System)
위에서 OS가 프로그램을 실행시켜주는 역할을 한다고 했지만 OS는 더 많은 일을 수행합니다. 아래는 OS가 수행하는 일들입니다.
- 유저 프로그램 실행 (방금 설명)
- 개발자(사용자)에게 문제를 더 쉽게 해결 하도록 다양한 서비스를 라이브러리 형태로 제공
- 사용자가 컴퓨터 사용이 편하도록 컴퓨터 하드웨어 자원(CPU, Memory) 을 효율적으로 관리해줌
* 라이브러리? : 쉽게 이야기 해서 함수들의 묶음을 의미
OS의 정의
1. 사용자와 컴퓨터 하드웨어 사이에 존재하면서 실행되는 프로그램
2. CPU, memory, I/O devices 같은 다양한 자원들의 할당과 컨트롤 기능을 가진 시스템 소프트웨어
3. 컴퓨터에서 항상 실행되고 있는 프로그램, 흔히 커널이라고 불림
*커널 : 운영체제의 핵심이 되는 부분
OS란 위 계층도에서 봤듯이 사용자와, 컴퓨터 하드웨어 사이에 존재하며, OS 역시 일종의 큰 분류로 일종의 시스템 소프트웨어에 속하게 됩니다. HW 윗단에서 돌아가는 항상 실행되는 프로그램이라고 이해할 수 있겠습니다. OS가 제어를 잘해주기에 저희가 여러 프로그램을 윈도우에서 동시에 돌릴 수 있는거고, HW 자원도 스스로 관리해줘서 컴퓨터를 편하게 사용할 수 있게 되는 겁니다.
근본적으로 운영체제도 프로그램이기 때문에 똑같이 프로그래밍 언어로 제작됩니다. 예전 C언어가 나오기 이전엔 어셈블리어로 극강의 노가다와 최적화를 진행해서 OS를 뽑아냈지만, 데니스 리치가 UNIX 운영체제 제작을 위해 C언어를 창시하고 성공함으로써, 요새 운영체제는 생산성도 어느정도 타협을 해 C나 C++로 제작하는게 국룰이 되었습니다.
https://github.com/torvalds/linux
UNIX 계열 운영체제 중 하나인 리눅스 커널 코드는 C로 작성되었고, 이렇게 오픈소스로 GitHub에서 관리되고 있는데 라인수만 천만줄이 넘어가는 위엄을 뽐내고 있습니다. 살아있는 노가다판의 현장이자 지옥입니다. 운영체제는 현존하는 프로그램 중 규모가 가장 큰 프로그램 중 하나입니다.
이제 시스템 소프트웨어를 알기 위해 중요한 개념인 시스템 콜(System Call) 에 대해 알아봅시다. 시스템 콜을 바로 알아보기 전에 해당 사진에 주목해봅시다.
우선 아까도 봤듯이 아래에 HW가 존재하고, 그 위에 운영체제가 있는데 오른쪽 괄호가 묶여있는걸 잘보면 운영체제 안에 커널(Kernel) 이 존재하고 또 System Call Interface 라는게 존재합니다.
우선 커널은, 운영체제의 알맹이로 운영체제의 핵심적인 부분을 담당하며 다양한 서비스가 존재하게 됩니다. 다양한 서비스라 하면 프로세스 관리, 메모리 관리, 파일 관리, 네트워크 관리 등 컴퓨터에서 매우 중요한 기능들입니다. 운영체제가 설치된 모든 기기에는 커널이 존재하며 사람에게 비유하자면 심장, 혹은 자동차의 엔진으로 비유할 수 있습니다.
어떤 커널을 사용하는지에 따라 우리가 실행하고 개발하는 프로그램이 하드웨어를 이용하는 양상이 달라지고 결과적으로 컴퓨터의 전체적인 성능도 달라질 수 있습니다. 대부분의 운영체제 전공서는 운영체제의 핵심부, 즉 커널을 설명하며 앞으로 운영체제를 지칭할 때는 특별히 언급하지 않는 한 커널을 지칭한다고 봐도 무방합니다.
그래서 결론적으로 OS는 시스템 콜 + 커널로 구성되며 , OS에서 시스템 콜 부분만 제외한다면 커널만 남게 됩니다.
시스템 호출(System Call)
운영체제에서 커널의 중요성에 대해 이제 알았습니다. 그럼 저 System Call 이라는 저건 뭘까요? 우선 정의부터 하고 시작하자면 응용 프로그램은 하드웨어에 직접 접근할 수 없습니다. 응용 프로그램이 하드웨어에 직접 접근할 수 있도록, 커널이 응용 프로그램에 제공하는 함수 또는 인터페이스를 시스템 호출 또는 시스템 콜 이라고 합니다.
아까 위의 사진에서 우리가 사용하는 응용프로그램은 OS위에서 돌아가는걸 확인했습니다. 응용프로그램이 컴퓨터 HW에 직접 접근하려고 해도 저렇게 OS에 가로막혀 있기 때문에 바로 접근이 불가합니다. 직접 접근을 시도하면 OS쪽에서 막아버린다는 뜻이죠.
OS는 사용자가 실행하는 응용 프로그램이 하드웨어 자원에 직접 접근하는 것을 막아서, 자원들을 보호합니다. 만약 응용프로그램이 CPU, 메모리, 하드 디스크에 마음대로 접근하고 조작할 수 있다면 자원이 무질서하게 관리될 것이고 응용프로그램이 조금만 실수해도 시스템 전체가 다운될 수 있습니다.
예를 들어서 A라는 응용 프로그램이 CPU HW에 바로 접근이 가능해서 자신이 CPU의 모든 코어를 점유해버린다면 다른 다른 응용프로그램들은 자신의 일을 전혀 수행할 수 없는 상태에 빠지게 될 것 입니다.
그래서 운영체제는 응용 프로그램들이 자원에 접근하려고 할 때 오직 자신을 통해서만 접근하도록 하여 자원을 보호합니다. 쉽게 이야기 해서 운영체제는 일종의 문지기 역할을 해서 응용 프로그램들의 자원 접근을 대행한다는 의미입니다. 즉 응용 프로그램이 하드 디스크에 접근하여 데이터를 저장하려면 OS한테 "내가 파일을 저장하고 싶은데 저장해주세요~" 와 같이 요청해야 합니다. 이 요청이 바로 시스템 콜 입니다.
그러면 운영체제는 커널 영역 내의 하드 디스크에 데이터를 저장하는 코드를 실행해서 응용 프로그램의 작업을 대신 수행해줍니다. (OS내부에 하드 디스크에 데이터를 저장하는 코드가 이미 작성되어 있습니다. 시스템 콜을 부르면 관련된 OS 내부의 코드를 OS 안으로 들어가서 실행시키게 됩니다.)
운영체제는 이러한 문지기 역할을 어떻게 하나요? (궁금한분은 클릭)
운영체제가 응용프로그램이 HW에 직접 접근을 막는 문지기 역할을 하는건 바로 이중 모드(dual mode) 에 의해 실현됩니다. 이중 모드란 CPU가 명령어를 실행하는 모드를 크게 사용자 모드와 커널 모드로 구분하는 방식입니다. CPU는 명령어를 사용자 모드로도 실행이 가능하고, 커널 모드로도 실행이 가능합니다.
사용자 모드(user mode)는 운영체제 서비스를 제공 받을 수 없는 실행 모드 입니다. 즉 커널 영역의 코드를 실행할 수 없는 모드입니다. 일반적인 응용프로그램은 기본적으로 사용자 모드로써 실행됩니다. 사용자 모드로 실행중인 CPU는 이름에서 추측하셨듯이 입출력 명령어와 같이 하드웨어 자원에 접근하는 명령어 실행이 불가능합니다. 그래서 사용자 모드로 실행되는 일반적인 응용 프로그램은 HW 자원에 접근할 수 없습니다.
반면 커널 모드(kernel mode)는 운영체제 서비스를 제공 받을 수 있는 실행 모드입니다. 즉, 커널 영역의 코드를 실행할 수 있는 모드입니다. CPU가 커널모드로 명령어 실행시 자원에 접근하는 명령어를 비롯해 모든 명령어를 실행할 수 있습니다. 운영체제는 커널모드로 실행되기에, HW 자원에 바로 접근할 수 있습니다.
CPU가 사용자모드로 실행중인지, 커널 모드로 실행중인지 체크하고 싶다면 플래그 레지스터 속 슈퍼바이저 플래그를 읽어보면 압니다. 슈퍼 바이저 플래그가 1이면 커널 모드고, 0이면 사용자 모드로 실행중이라는 뜻 입니다.
사용자 모드로 실행되는 프로그램이 자원에 접근하는 운영체제 서비스를 제공받으려면 운영체제에 요청을 보내 커널 모드로 전환해야 하며, 이런 운영체제 서비스를 제공 받기 위한 요청이 바로 위에서 설명한 시스템 콜 입니다.
<Example>
응용 프로그램 A가 디스크에 데이터를 저장하려고 한다 => 사용자 모드로 실행되고 있는 동안엔 HW(하드디스크) 에 직접 접근 불가 => 하드 디스크에 데이터를 저장하는 시스템 콜을 발생시켜서 커널모드로 전환 => 운영체제 내의 '하드 디스크 데이터 저장 코드 실행' => 접근이 끝나면 다시 사용자 모드로 복귀
정리하여 OS는 보시다 싶이 다양한 서비스를 가지고 있으며 (다양한 커널의 서비스), 이 서비스는 개발자에게 함수(시스템 콜)로 제공합니다. 개발자가 OS의 다양한 서비스를 합법적으로 이용하고 싶다면 OS가 제공하는 함수인 명칭 '시스템 콜' 을 사용해 접근하게 됩니다.
일반적으로 시스템 콜은 C언어로 제공되어서, C언어로 헤더파일만 가져와서 호출하면 됩니다.
C++은 될 지 말지 잘 몰랐었는데 C++도 어짜피 C 문법을 그대로 계승하기도 했고 예전 C의 헤더파일도 참조할 수 있어서 호출이 가능했습니다. (직접 해봄)
단 인터페이스가 C로 제공되기 때문에 시스템 콜 함수 호출 시 문자열을 넘겨 주고 싶으면 당연히 C++ String 같은 객체 타입은 그대로 넘겨줄 수 없고 C스타일의 char * 나 char [] 문자열로 넘겨야 합니다. C++ String을 문자열로 넘겨주고 싶다면 String을 char * 타입으로 변환하는 String 멤버 함수 c_str() 등을 이용해 형변환을 하고 함수 인자에 넘겨줘야 합니다.
https://www.youtube.com/watch?v=arizVwcqq9w
시스템 콜 제너레이트 루미너스 엘리먼트 라이트닝 셰이프 디스차지!
위는 소아온에서 나오는 시스템 콜입니다. 마법을 쓸때 부르는 일종의 주문(?) 인데 관리자 권한으로 시스템을 조작하는것과 관련이 있습니다. 권한이 필요해서 뭔가 말로 요청한다는점에서 지금 설명한 시스템 콜과 비슷합니다 ㅋㅋ. 어렴풋이 생각나서 가져와봤습니다. 솔직히 글이 오늘따라 너무 재미 없기도 하고요 소아온 1기와 더불어서 4기는 볼만하니깐 보실분들은 보셔도 좋을듯
이름 지을때 컴퓨터에서 말하는 시스템 콜을 따서 지은건 진 잘 모르겠습니다 (아마 관련 없겠지..?)
시스템 소프트웨어(System Software)
드디어 나온 메인 토픽입니다. 사실 앞까지 읽으면 그냥 운영체제 시스템 콜 글이 아닌가 싶을정도로 운영체제 내용이 대부분 이였습니다만 뭐 시스템 소프트웨어가 사실 OS와 관련이 있는거라 어쩔 수 없네요..
시스템 소프트웨어를 앞에서 간단히 소개하기로 UI가 없는 개발을 위해 사용하는 프로그램이라고 했죠.
우선 우리가 Java라는 언어를 써서 프로그래밍 하는 행위를 Java 프로그래밍(또는 Java로 프로그래밍 한다) 이라고 합니다. 시스템 프로그래밍은 시스템 콜 또는 어셈블리를 사용해서 프로그래밍 하는걸 말하고, 결국 시스템 프로그래밍으로 만든 SW가 시스템 소프트웨어가 되는것 입니다.
일반적으로 C언어(또는 C++)로 시스템 콜을 열심히 호출해서 프로그래밍 하는게 시스템 프로그래밍이고, 이걸로 만들어진 프로그램이 바로 시스템 소프트웨어란 것입니다. 그렇게 어렵지 않죠?
리눅스의 cp, rm, mkdir, ls 와 같은 명령어도 근본적으로 '프로그램' 인데 이것도 내부적으로 열심히 시스템 콜을 호출시켜서 구현되어 있습니다. (시스템 소프트웨어란 거죠.)
* 현대 운영체제들은 보통 수 백개의 시스템 콜들을 가지고 있다고 합니다. 리눅스 & Open BSD는 300개가 넘는 수, NetBSD는 500개, 윈도우 7인 경우 700개 가까이 존재한다고 하네요.
시스템 콜은 종류가 매우 많은 만큼 제공하는 기능에 딱딱 맞춰져 있고, 이름도 짧으며 직관적인 사용방법을 가집니다. 기능에 딱딱 맞춰져 있다는 것은 어떻게 보면 단일 함수들이 매우 한정적인 기능들만 존재한다는 의미입니다. 즉 시스템 콜을 호출해서 시스템 소프트웨어를 제작하는건 엄청난 노가다를 동반하고.. 매우 힘든일입니다.
일반적으로 Java나 Python 같은 추상화가 많이 되어 있는 언어로 프로그램을 짜는건 그림을 그리는거에 비유하자면, 브러쉬나 페인트 같은 붓을 이용해서 큼직 큼직하게 그림을 쉽게 그리는거에 비교할 수 있겠고,
시스템 콜로 시스템 소프트웨어를 제작하는건 점묘화 (점 하나하나 찍어서 그리는 노가다 그림) 나 도트찍기 라고 보시면 되겠습니다. C에는 심지어 예외처리 문법도 없어서 시스템 콜이 반환하는 오류코드 (-1 등) 을 일일히 if문으로 확인하면서 넘어가야 합니다. (함수로 래핑하면 좀더 낫긴 합니다)
물론 시스템 프로그래밍이 힘들뿐이지 시스템 콜의 갯수는 아주 많기에 프로세스도 생성가능하고(fork), 프로세스간 통신도 지원하고 (메세지 큐, 공유 메모리), 심지어 쓰레드 까지 만들 수 있습니다. 쓰레드 간 동기화도 당연히 지원하구요 (세마포어, Mutex). OS에서 제공하는 다양한 기능을 C언어 API로 마음껏 음미(?) 해볼 수 있습니다.
특히 리눅스에서 시스템 프로그래밍 하면 UNIX 시스템 콜의 특징상 매우 간결한 이름과 간결한 사용법을 지니기 때문에 시스템에 대해 제대로만 이해했다면 C라이브러리 공부하듯이 호출 방법과 코드 예제만 잘 보시면 됩니다. (대표적으로 쓰레드 동기화에 사용되는 세마포어나, Mutex Lock은 볼 때 코드는 아주 간단한데, 개념이 상당히 이해하기 까다롭죠.)
번외 - C언어의 내부적 사정
C언어에서 printf(...) 함수를 호출하면 터미널 (콘솔) 화면에 글자들이 찍힙니다.
실제로 printf() 의 내부 사정을 보면 write() 라는 시스템 콜을 사용해서 모니터에 글자를 찍고 있었습니다.
write() 는 파일에 내용을 쓰는 시스템 콜 입니다. 엥? 화면은 파일이 아닌데요 라고 생각할 수 있겠지만 UNIX 계열 운영체제를 기준으론 터미널이나 키보드 입력 역시 전부 파일로 다루고 있기에 가능합니다.
비슷한 예시로 scanf(...) 역시 read() 라는 시스템 콜을 이용하여 키보드에서 입력을 받습니다.
C언어 아래서 돌아가는 더 Low-Level 한 무언가의 존재가 있었다는 것이죠 (소오름)
출처(참고문헌)
Randal E. Bryant , “Computer Systems: A Programmer's Perspective”, Prentice Hall
'CS > System' 카테고리의 다른 글
[시스템 소프트웨어] 쓰레드(Thread)를 알아보자!! - 시스템의 핵심 (0) | 2023.05.08 |
---|---|
[시스템 소프트웨어] 스택 프레임(Stack Frame) 이란 무엇인가? : 어셈블리 명령어로 알아보자 (0) | 2023.01.22 |
[시스템 소프트웨어] 어셈블리어 개요 / 어셈블리어(Assembly)란? (0) | 2022.12.26 |