Tuesday, April 1, 2008

Basics on Process

리눅스 프로세스에 대한 기초를 복습해보자. 음,. 프로세스는 pid로 구별된다. idle process는 0, init process는 1이다. init의 command-line parameter를 통해서 프로세스를 실행시킬 수 있다. 커널은 init의 위치를 아래 네가지 순서대로 찾아 다닌다.
  1. /sbin/init
  2. /etc/init
  3. /bin/init
  4. /bin/sh (init을 못찾으면 Bourne shell 이라도 실행시킨다)

프로세스는 옛날 Unix 시스템과의 호환을 위해 32768개 이상 띄울 수 없게 되어 있으나, /proc/sys/kernel/pid_max 값을 조절하여 더 키울 수 있다.

프로세스는 ppid가 부모 프로세스이고, user group 접근 권한도 가지고 있다. 이 접근 권한과 헷갈리면 안되는 것이 process group인데, 프로세스 그룹은 예를 들어 'ps aux | grep aaa' 같이 파이프로 묶여 실행되는 프로세스 들이라고 생각하면 된다. process group을 알면 전체 파이프 라인된 프로세스들에게 시그널을 보낼 수 있어 좋다. job 명령이 이 process group과 관련이 있다.

프로세스는 pid_t 로 표기 되는데, getpid(), getppid() 등으로 자신과 부모의 프로세스를 알 수 있다. (통상 이를 출력할 때 unsigned int로 간주한다.)

프로세스 실행 방법은 두가지가 있는데, exec과 fork이다.

exec은 excel(path, arg, ...) 처럼 실행 바이너리 경로와 인자를 주어 실행한다. 아래는 vi를 싱행하는 예다.



int ret;

ret = excel ("/bin/vi", "vi", NULL);
if (ret == -1) perror("excel");

일반적으로 excel은 리턴되지 않는다(당연하다). exec이 실행되면 pending signal이 없어지고, 메모리 lock도 없어지고 thread관련된 값들도 default로 바뀌고, 프로세스 관련 값들도 변하고, mmap 되어 있던 부분도 drop된다. pid, ppid, priority, 권한 등은 유지된다. 그리고 열려있는 파일들도 exec 후 상속된다. 하지만 일반적으로 exec 하기 전에는 열려있는 파일들은 닫는다. exec은 인자나 실행 파일을 어떻게 알려주느냐에 따라 execve를 wrapping한 execle, execv, execvp, execve, execlp 등으로도 제공되고 있다.

fork()는 알다시피 자식 프로세스를 만든다. 리턴값이 0이면 자식이고, 아니면 부모이다. signal은 clear되고, file lock 등은 자식에게 상속되지 않는다. 많은 경우 fork는 exec과 같이 사용된다. "fork plus exec".

Copy-on-write 개념을 알아둘 필요가 있는다. 이는 매번 자식 프로세스가 생성될 때마다 부모 프로세스를 복사하기 부담 스러우니, 자식 프로세스와 부모 프로세스가 달라지는 시점이 되서야 비로소 프로세스를 copy하자는 개념이다. fork plus exec의 경우에는 사실 프로세스 복사가 무의미 하므로 이러한 copy-on-write를 통해 부담을 줄일 수 있다. 대부분의 COW 매커니즘은 프로세서의 MMU를 통해 하드웨어 적으로 지원되고 있다.


아예 fork 할 때 부모 프로세스를 복사하지 않고, 자식 프로세스가 종료하거나 exec할 때까지 기다리는 vfork()도 있는데, 리눅스에서는 (정식 버전에서는) vfork를 구현한 적이 없다. 자식이 exec 하다 실패한 경우 부모 프로세스가 멈출 수 있는 잠재적인 버그를 가지고 있다. 비추다.

No comments:

Post a Comment