'프로세스 의미' 태그의 글 목록 :: YJcode

프로세스는 쉽게 말하면 실행 중인 모든 각각의 프로그램을 말한다.

즉, 지금 이 페이지를 보고 있는 웹 브라우저 또한 커널 입장에서 보면 프로세스라고 볼 수 있다.

이러한 프로그램이 실행될 때는 커널이 프로그램의 정보를 정의한 바이너리 코드를 메모리에 올리고, 프로그램을 위한 변수 공간을 할당하고, 프로세스에 대한 정보를 담을 별도의 데이터 구조를 준비하게 된다.

 

커널이 보기에 이 프로세스들은 전부 자신이 관리하고 있는 컴퓨터 제원을 나눠서 할당하고, 관리해야 할 대상이 된다.

여기서 메모리나 CPU와 같이 무한정 제공되지 않는 한정된 자원의 경우, 커널은 처음에는 최소한의 자원만을 할당하고, 프로세스가 존재하는 동안 각각의 프로세스들이 요구하는 자원의 정도를 확인하고 적절하게 추가 배분하는 등 프로세스의 전체적인 조율을 하는 역할을 하게 된다. 이후 종료되는 프로세스가 있다면 할당하였던 자원을 반납받고, 필요로 하는 다른 프로세스에게 자원을 할당하거나 여유자원으로 가지고 있게 된다.

 

프로세스는 다음의 세그먼트로 구분할 수 있다.

 

  • 텍스트 : 프로세스의 정의,명령
  • 데이터 : 프로그램이 사용하는 정적 변수
  • 힙 : 프로그램이 사용하는 동적 변수(프로그램이 필요에 따라 추가적으로 변수 공간 할당을 요청하면 이곳에 할당)
  • 스택 : 함수의 호출, 반환에 따라 쌓이고, 줄어드는 메모리 영역

 

프로세스는 fork() 호출을 통해 새로운 프로세스를 만들 수 있다. 이때, 호출을 하는 프로세스를 부모 프로세스, 호출에 따라 새로이 생성되는 프로세스를 자식 프로세스라고 한다. 프로세스가 fork()를 호출하면 커널은 이 요청을 받아들여 부모 프로세스의 모든 것(변수, 현재 상태 등 모든 정보)들을 복사해서 새로운 프로세스를 만들어 내게 된다. 이렇게 새로 생성된 자식 프로세스는 생성이 끝난 후부터는 독립된 프로세스로서 부모 프로세스와는 다른 변수를 생성할 수도, 삭제할 수도, 별도의 독립된 함수를 실행할 수도 있게 된다. 혹은, execve() 호출을 통해 기존의 부모 프로세스로부터 물려받은 모든 세그먼트(텍스트, 데이터, 힙, 스택)들을 제거하고 완전히 새로운 코드에 따라 세그먼트를 구성할 수도 있다.

 

각각의 프로세스에는 고유한 ID(고유한 정수 - 다른 프로세스와 구분하기 위한 유일한 숫자)를 가지고 있다. 이를 PID라고 부르며, 마찬가지로 각각의 프로세스에는 자신을 생성한 부모 프로세스 또한 가지고 있다. 이것을 PPID라고 부른다.

 

프로세스는 보통 두 가지 방식으로 종료될 수 있다. _exit() 시스템 호출(or exit() 라이브러리 함수)을 통해 스스로 종료하기를 커널에게 요청하거나, 외부로부터 종료 시그널을 받아 종료되는 경우가 있다.

이때 두 가지 경우 모두 왜 종료하였는 지, 어떤 방식으로 종료되었는지를 알리는 종료 상태를 생성되는데, 프로세스가 스스로 종료하는 경우 종료 상태를 스스로 생성해서 반환하고, 외부에서 종료시키는 경우 외부에서 온 시그널이 어떤 종류의 시그널이냐에 따라 종료 상태가 결정된다.

이러한 종료 상태는 보통 0은 정상종료를 의미하고, 0이 아닌 모든 수를 비정상 종료, 즉 에러가 발생함에 따라 종료된 것을 뜻한다. 대부분의 쉘에서 마지막으로 실행된 프로그램의 종료 상태를 $?라는 쉘 변수를 통해서 얻을 수 있다.

 

각 프로세스는 다음과 같은 여러 사용자 ID(UID)와 그룹 ID(GID)가 관련되어 있다.

 

  • 실제 사용자 ID 와 실제 그룹 ID : 프로세스가 속한 사용자, 그룹. 새 프로세스는 이 정보를 부모로부터 물려받는다.
  • 유효 사용자 ID 와 유효 그룹 ID : 프로세스 간의 통신 객체와 같은 보호된 자원에 대한 접근권한을 결정하기 위해 쓰인다. 보통은 유효 ID와 실제 ID가 같지만, 특별한 경우 유효 ID를 바꾸게 되면, 프로세스가 다른 사용자나 그룹의 권한을 가질 수 있게 된다. 이러한 UID와 GID는 부모로부터 물려받게 된다.
  • 보조 그룹 ID : 프로세스가 속한 추가적인 그룹. 마찬가지로 부모로부터 물려받게 된다.

 

유닉스에서 특권 프로세스는 유효 사용자 ID가 0인(슈퍼유저)인 프로세스를 말한다. 이런 프로세스는 관리자 권한을 가지고, 커널이 적용하고 제한하는 대부분의 권한 제한에서 자유롭다. 이외의 프로세스는 비특권 프로세스라고 불리며, 커널이 강제하는 권한 제한을 적용받아, 해당 권한을 얻기 위해선 커널의 승인을 받아야 한다.

 

위의 내용들을 토대로 생각할 수 있지만 언급하자면, 특권 프로세스가 생성한(커널에게 생성을 요청한) 프로세스는 마찬가지로 특권 프로세스가 된다. 왜냐하면, 자식 프로세스는 부모로부터 유효 UID와 GID를 물려받기 때문이다.

비특권 프로세스가 특권 프로세스가 되는 방법은 set-user-ID 방식으로, 프로세스를 실행한 프로그램 파일의 사용자 ID가 그 프로세스의 유효 사용자 ID가 된다.

 

시스템을 부팅하면 커널은 /sbin/init 프로그램 파일을 실행하여 모든 프로세스의 부모 프로세스인 init 프로세스를 만든다. init 프로세스의 ID는 1이고, 언제나 슈퍼유저의 특권을 가지고 있다. init 프로세스는 어떠한 경우에도 종료시킬 수 없으며(그럴 일은 없겠지만 init프로세스가 종료되면 커널은 그 순간 동작을 멈추게 된다. 그렇기에 슈퍼유저 권한을 가지고 있더라도 강제로 종료시킬 수가 없다.) 커널이 종료되는 순간에만 같이 종료된다. init 프로세스는 주로 여러 프로세스를 생성하고, 정상 동작하는지에 대한 감시를 하게 된다.

 

데몬 프로세스는 많이들 들어보았을 것이다. 이 프로세스는 다른 프로세스와는 구별되는 몇 가지 특징이 있다.

 

  • 누군가가 강제로 종료시키지 않는 이상 커널이 부팅될 때부터 커널이 종료될 때까지 계속 존재하고 있다
  • 보통 백그라운드에서 실행되고 제어받는 대상이 아니다.
  • 다른 프로세스를 보조하거나, 다른 프로세스의 행위를 기록하는 일을 한다.(게임으로 치면 액티브 스킬이 아니라 패시브 스킬이라고 보면 된다.)

 

이러한 데몬 프로세스로 시스템 로그 메시지를 기록하는 syslogd, 우분투 리눅스에서 영어가 아닌 한글을 입력하기 위해 존재하는 iBus-hangul, 데이터베이스 서버 등이 있다.

 

각 프로세스는 환경 목록이라는 환경변수의 집합을 가지고 있다. 이 목록의 각 요소는 이름과 값의 쌍으로 이루어져 있고, fork()를 통해 새로운 프로세스가 만들어지면, 이 환경 목록을 그대로 복사해서 물려주게 된다.(사실은 이러한 과정이 있기 때문에 자식 프로세스가 부모프로세스로 부터 각종 정보를 물려받을 수 있는 것이다.) 이 환경목록 또한 execve() 함수를 통해 새로이 지정된 환경으로 대치하여 물려받을 수도 있다.

 

각 프로세스는 열람 중인 파일, 메모리, CPU 시간 등의 자원을 항상 소비한다. setrlimit() 호출을 하면 이러한 프로세스의 자원 사용에 상한선을 지정할 수 있다. 이러한 자원 한도는 연성한도 와 경성 한도의 쌍으로 이루어지는데, 연성 한도는 프로세스가 소비할 수 있는 자원의 한도, 경성 한도는 연성 한도를 조절할 수 있는 상한선을 말한다.

비특권 프로세스는 특정 자원의 연성 한도를 0부터 경성 한도까지의 범위에서 자유롭게 변경해서 사용할 수는 있으나, 경성 한도는 오직 낮출 수만 있고 올려 잡을 수는 없다. 즉, 경성 한도는 무조건 지켜져야 하는 외부에서 지정한 최대한도, 연성 한도는 자체적으로 조율이 가능한 내부 한도라고 볼 수 있다.

 

fork()를 통해 새로운 프로세스가 생성되면, 부모의 자원 한도 설정 또한 물려받게 된다.

 

+ Recent posts