본문 바로가기
컴퓨터 기초/운영체제 이론

[실습과 그림으로 배우는 리눅스 구조] 2.사용자 모드로 구현되는 기능

by 인생여희 2020. 6. 5.

기본적으로 사용자 모드의 프로세스 처리부터, 시스템 콜을 통한 커널 처리를 호출하는 방식.

 

시스템콜

프로세스는 프로세스의 생성이나 하드웨어의 조작 등 커널의 도움이 필요한 경우 시스템 콜을 통해 커널에 처리 요청을 한다.

예) 프로세스 생성 , 삭제. 메모리 확보, 해제. 프로세스간 통신. 네트워크. 파일시스템 다루기. 파일 다루기.

 

cpu의 모드 변경

시스템콜은 cpu의 특수한 명령을 실행해야만 호출된다. 프로세스는 보통 사용자 모드로 실행되고 있지만 커널에 처리를 요청하고자 시스템 콜을 호출하면 cpu에서는 인터럽트 이벤트가 발생한다. 인터럽트 이벤트가 발생하면 cpu는 사용자 모드에서 커널모드로 변경되며, 요청한 내용을 처리하기 위해 커널은 동작하기 시작한다. 요청한 내용처리가 끝나면 커널 내의 시스템 콜 처리가 종료된다. 그리고 다시 사용자 모드로 돌아가 프로세스의 동작을 계속 진행한다.

 

커널은 프로세스가 요청한 내용을 처리하기 전에 프로세스의 요구가 유효한지 확인한다. (예컨대, 시스템 메모리 용량의 이상의 메모리를 요구하는 것 등..) 요구사항이 맞지 않으면 커널은 시스템 콜을 실패했다고 처리한다.

 

시스템 콜 호출의 동작 순서

프로세스가 어떤 시스템 콜을 호출 했는가는 strace 명령어를 통해서 확인 할 수 있다. 

 

[코드]

[컴파일]

gcc -o hello hello.c

 

[실행]

./hello

 

[로그 저장]

strace -o hello.log ./hello

 

[로그확인]

cat hello.log

strace 각각의 줄은 1개의 시스템 콜이다. 이 프로그램은 여러 줄을 출력했는데, 아래쪽을 보면 write() 시스템콜이 hello world를 화면에 출력하고 있다. write() 시스템 콜 이외에도 hello.c 의 main 함수의 앞뒤로 실행된 것들로,

프로그램의 시작과 종료 처리와 관련있는 시스템 콜이다. 

 

프로세스가 사용자 모드와 커널 모드 중 어느쪽에서 실행되고 있는지의 비율은 sar 명령어로 확인 할 수 있다. (여기서는 각 cpu 코어가 어떤 종류의 처리를 실행하는지 1초 단위로 측정). 한줄에 1개의 cpu코어가 대응하고 있으므로 이 시스템에 탑재된 cpu 코어 각각에 대해 정보가 출력되고 있다. (여기서는 cpu 코어가 1개 뿐이다.) 사용자모드는 user+ nice 의 합, 커널모드는 system 으로 얻을 수 있다.  모든 cpu코어는 대부분의 시간동안 idel 이 100가까운값. idel은 cpu 코어상에 프로세스도, 커널도 움직이고 있지 않은 ‘아이들 상태’ 인것을 의미 한다.

 

 

시스템 콜을 호출하지 않고 무한루프를 도는 프로그램

[코드]

 

[컴파일]

gcc -o loop loop.c

 

[실행]

./loop &

 

[성능확인]

sar -P ALL 11

루프문만 있는 프로세스의 cpu 사용 통계를 보면 1초 동안 유저 프로세스, 즉 cpu가 루프문을 처리하기 위해서 유저 모드로 동작을 하고 있었다는것을 알 수 있다. 

 

부모 프로세스 id를 얻는 getppid() 시스템 콜을 무한 루프하는 프로그램을 실행해서 측정 

[코드]

 

[컴파일]

gcc -o ppidloop ppidloop.c

 

[실행]

./ppidloop &

 

[성능확인]

sar -P ALL 11

이번에는 user가 76%의  cpu를 차지했고 커널이 24%의 cpu를 차지한것을 알 수 있다. 대체로 system의 수치가 크면 시스템 콜이 너무 많이 호출되고 있거나, 시스템에 과부하가 걸려있는 등의 좋지 않은 상태를 의미한다.

 

시스템 콜의 소요시간

strace에 -T 옵션을 붙여 각종 시스템 콜 처리에 걸린 시간을 마이크로초 단위로 정밀하게 측정할 수 있다.

 

시스템 콜의 wrapper 함수

os의 도움이 없을때

리눅스에는 프로그램의 작성을 도와주기 위해 프로세스 대부분에 필요한 여러 라이브러리 함수가 있다.

시스템 콜은 보통의 함수 호출과는 다르게 c언어 등의 고급언어에서는 직접 호출이 불가능하다. 아키텍처에 의존하는 어셈블리 코드를 사용해 호출할 필요가 있다. os가 없다면 각 프로그램은 시스템 콜을 호출 할때마다 아키텍처에 의존하는 어셈블리 언어를 써서 고급언어로부터 어셈블리 코드를 호출해야만 했을것이다. 이방식은 프로그램을 작성하는 데 시가이 오래 걸릴 뿐더러, 다른 아키텍처에도 사용할 수 없어 이식성도 매우 낮으며, 이식할수 없는 경우도 있다.

 

이문제를 해결하기 위해서 os는 내부적으로 시스템 콜을 호출하는 일만 하는 함수를 제공하는데 이를 시스템 콜 래퍼라고 한다. 래퍼 함수는 아키텍처별로 존재한다.

고급언어로 작성된 사용자 프로그램부터는 각 언어에 대응하여 준비된 시스템 콜의 래퍼 함수를 호출하기만 하면 된다.

 

표준 c 라이브러리

c언어에는 iso에 의해 정해진 표준 라이브러리가 있다. 대부분의 c프로그램은 glibc를 링크하고 있고, glibc는 시스템콜의 래퍼 함수를 포함한다.

 

os가 제공하는 프로그램

-시스템 초기화 : init

-os의 동작 변경 : sysctl, nice, sync

-파일관련 : touch, mkdir

-텍스트 데이터 가공 : grep, sort, uniq

-성능측정 : sar, iostat

-컴파일러 : gcc

-스크립트 언어 실행환경 : perl, python, ruby.

-셸 : bash

-웬도우 시스템 : X

 

 

글 및 사진 출처 : 도서 실습과 그림으로 배우는 리눅스 구조 (한빛미디어)