유닉스의 커널을 다 이해하기란 어렵습니다. 하지만
차근히 배우다 보면 하나하나 깨닫고 이해하게 되며 나중에는
유닉스 커널을 스스로 하나 만들 수 있는 실력까지 가게 됩니다.
그러나 그정도 까지 될려고는 하지마십시요. 커널소스들고 깊은곳까지
개작할 수 있는 정도만 되어도 세계에서 열손가락안에 들 수 있습니다..
좀 더 깊이 있게 알고자 하는 분들을 위해 아주아주 기초적인 유닉스의
전반적인 커널의 구조를 설명 드리겠습니다..
제가 쓴 글을 첨부터(용어 부터) 이어 나가면서 읽으셔야 앞으로
계속 올라올 글을 읽어 나가는데에 지장이 없으니 이점 참고 하시고
많은 도움 되셨으면 합니다...
앞글에서 프로세스가 뭔지 그리고 멀티태스킹..등의 기본 용어를 봤는데
여기서 프로세스에 대해 깊이 있게 살펴보겠습니다..
(특히 fork() ,exec(), 등과 프로세스를위한 커널내부 등에 대해서)
프로세스를 어떻게 생성시킬까요?
우선 자연적으로 생겨나는 프로세스는 뭐가 있을까요..
당연히 부팅 프로세스가 제일 첫번째로 생겨나겠죠..
요게 pid=0번 프로세스 입니다 근데 이 프로세스는 부팅의 역할을
하고서는 스웨퍼 프로세스란 이름으로 대체됩니다. (부팅시켰으니깐
지 할일 다했다 이 거죠) 이 스웨퍼는 다음에 메모리부분에서 글올리겠습니다.
그 다음에는 이 0번 프로세스가 init라는 1번 프로세스를 자동으로
생성시킵니다.
1번에 의해 각종 데몬 프로세스가 생성되고 로그인 프로세스에 의해
사용자가 로그인 하면 마지막으로 쉘 프로세스(csh,bash.등)를
띄워주게 됩니다.
이렇게 해서 명령을 기다리는 프롬프트가 뜨게 되는 겁니다.
자 이제는 바로 사용자가 프로세스를 생성시켜 주게 되는 거죠.
쉘상에서 우리가 명령어를 쳐주면 쉘 프로세스란 놈이 우리의 명령어를
받아서 새로운 프로세스를 생성시켜 주게 됩니다. 그럼 여기서 이 쉘
프로세스가 부모 프로세스가 되고 우리가 쳐준 명령어는 쉘의
자식 프로세스가 됩니다
디스크상에 저장된 프로그램이 어떻게 실행될까요?.
이는 다시 말해 디스크상에 프로그램이 어떻게 메모리로 올라와서
한 프로세스로의 역할을 하게 되느냐 하는 겁니다.
이과정은 fork(), exec() 시스템 콜에 해당 되는데 한번 살펴보죠..
Fork( ) 시스템콜 이란?
아까 위에서 단순히 생성이란 단어를 사용했는데 이는 사실상
fork( )라는 시스템 콜에 해당됩니다.
(시스템 콜이란 커널의 실행 루틴 모듈을 뜻하는데 우리가
프로그래밍 할때보면 함수를 만들듯이 유닉스 커널에 fork( )
라는 함수가 있는데 외부에서 이 커널내부의 함수를 실행시킨다는
의미에서 시스템 콜이라합니다.)
이 fork( )가 하는일은 우선 실행시킬 프로그램을 위해 부모프로세스와
똑같은 거를 하나 만들어 주게 됩니다 복사본이죠.
그러니까 쉘이 만약 부모였다면 그쉘과 똑같은걸 하나 더 메모리에서
만들어주게 됩니다.
하지만 프로세스 넘버는 새로운걸 할당시켜주며 또 아래 설명되겠지만
프로세스 테이블의 한항목을 차지하게됩니다 두개의 쉘이 동시에
수행되는 상황이죠..그러나 곧이어 바로 exec() 시스템 콜을
수행시키게됩니다.
Exec( ) 시스템콜 이란?
이제 원하던 프로그램을 디스크에서 읽어오고 새롭게 메모리를
할당받아서 거기다가 적재시키게 되는데 이 과정을 exec() 가
해줍니다.
이프로세스가 메모리에 어디에 있다하는건 다음에 보게될 프로세스
테이블에 기록이 되는겁니다.. 아래 프로세스 테이블 항목들을
쭉 한번 살펴 보십시요 그럼 그 구조를 이해 쉽게 이해하실 수 있습니다.
이렇게 해서 디스크상의 한 프로그램이 메모리를 차지하여 실행되기
위한 모든 준비를 마치고 하나의 프로세스의 역할을 하는 겁니다.
프로세스의 메모리 공간 할당
위에서 단순히 메모리 할당이라는 말을 썼는데 이를 자세히 살펴봅시다.
프로세스는 일단 리젼이란 기본 구조로 메모리를 바라다봅니다.
그러니까.. 한 프로세스는 코드 영역, 데이타 영역, 스택 영역의
세부분으로 나뉘어있으며 이들 영역들을 리전(region) 이라 합니다.
그러므로 프로세스는 메모리 할당을 위해 리전을 할당해 줄것을
요청하게 되는데 이 요청이 바로 exec() 에서 하는거죠.
이렇게 해서 커널은 리전할당 모듈을 실행시켜서 리전을 할당 시켜주게
되는데 그럼 이 리전할당모듈 부분에선 실제적인 메모리의 할당을
위해 페이지 단위로 나뉘어진 메모리를 프로그램이 필요로 하는
사이즈 만큼 페이지 테이블에서 할당받아 각 리전을 구성 시키게 됩니다.
이제는 더 깊이 들어가서 이렇게 생성된 프로세스들이 어떻게
관리되는지 알아볼까요!
이를 위해 커널 내부의 프로세스와 관련된 데이타 구조를 보면
대충 돌아가는걸 이해 하실겁니다.
[프로세스를 위한 커널의 기본 데이타 구조]
┌───┐ ┌───┐ ┌──┐ ├──┤
+-->│U Area│ │ │ │ │ ├──┤
| └───┘ ├───┤_________├──┤____├──┤
| /├───┤ ├──┤ ├──┤
| ┌───┐ / /├───┤ │ │ +--├──┤
| │ │ / / /├───┤ │ │ | ├──┤
| ├───┤ / / / │ │ ____├──┤-+ ├──┤
+-->│ │/_/_/ │ │ ├──┤ ├──┤
├───┤ │ │ │ │ ├──┤
│ │ └───┘ └──┘ ├──┤
│ │ 프로세스당 리전테이블 ├──┤
│ │ 영역(리전) 테이블 주메모리
│ │
└───┘
프로세스 테이블
이해 하실라나ㅜㅜ 이게 최대로 노력한건디....(--)(__)
프로세스 테이블 :
여러 프로세스를 커널에서 관리하기 위한 모든 프로세스들의
기본 정보들을 가지고 있는 테이블입니다.
프로세스에 관한 가장 기본이 자료가 되며 여러 프로세스의
목록으로 보시면 됩니다. 각 목록 즉 테이블의 한 항목에는
한 프로세스에 관한 모든 정보가 들어있게됩니다.
뭐가 들어있는지 한번 보죠.. 이것만 봐도 아마 어케 관리되는지
감 잡을 겁니다.
1.상태정보(지금 포그라운드로 수행중에 있는가 아니면 백그라운드 또는
스왑된상태)
2. 리전테이블을 가리키는 포인터 정보와 U Area가리키는 포인터
리전테이블이란 프로세스가 차지하고 있는 메모리위치정보를 말함
U Area란 CPU를 프로세스가 할당받았을때만 필요한 정보들..
3. 사용자의 ID도는 GID(그룹아이디)
4. 프로세스 번호 (PID)
5. 수면상태에 있을때의 이벤트 식별자.
6. 스케쥴링 메개변수
7. Signal 필드
8. 여러가지 타이머
U Area :
이U area는 프로세스마다 하나씩 할당 된것이 아니라 프로세스가
스케쥴러에 의해 cpu를 할당 받아 실행 될때만 생기는 항목입니다.
그러니까 실행중에만 그필요성이 생겨 생성되는 정보들로 보면 됩니다.
다른 프로세스가 cpu를 할당받아 실행되면 이전의
u area정보를 지우고 이 프로세스를 위한 정보로 대치되는겁니다.
다음과 같은 정보가 들어가 있습니다.
1. 실제 사용자 아이디(ID)와 유효사용자 아이디(EID)
2. 타이머(얼마만큼 실행중에 있는지 계산해야 겠죠)
3. 시그널을위한 반응 필드들(여러 시그널이 들어왔을때 대처할행동의
지침, 시그널은 나중에 다시 설명드리겠습니다)
4. 오류필드(실행중 오류가 발생시 관련오류를 요기다가 넣어줌)
5. 복귀값필드(시스템콜을 수행시켰을 경우 그수행의 리턴값이
있다면 나갈때 리턴값들을 요기에 넣어지게 됩니다.)
6. 입출력 매개변수들(화일 읽고쓸때 요기에 이 동작을 위한
기본정보가 있습니다. 얼만큼 읽거나 써야할지 어디서
어디로 보내야할지등)
7. 현재 디렉토리와 루트디렉토리
8. 사용자 화일 디스크립터 테이블(화일 접근을위해 오픈했을때 관련정보)
9. 한계필드(프로세스의 크기와 또 쓸수(write)있는 화일의
크기를 요기서 제한)
10. 허용모드필드(생성한 화일의 모드설정, umask를 아신다면 금방
이해가실 겁니다.)
프로세스당 영역 테이블 :
각 영역(리전)의 메모리상의 위치정보를 관리하는 테이블로서
각 프로세스마다 다 하나씩 가지고 있겠죠..
그래야 자기가 메모리에서 어디에 있는지 알죠..
커널이 한 프로세스를 실행시키기 위해선 그프로그램이
위치해있는 메모리를 찾아가야 하는데 바로 이것이 가장 기초가
되는 정보로 보시면됩니다.. 여기선 단순히 리전별로
묶어서(코드,데이타,스택) 관리하고 개개의 리전은 다시 실제
메모리를 가리키게 하는게 아니라 리전테이블을 가리키게 하고
이 리전 테이블에서 실제 메모리의 페이지들을 주소 정보가
들어가 있게되는겁니다
이렇게 프로세스당 리전 테아블과 리전테이블의 두단계를
거쳐서 메모리를 액세스 하는 이유는 프로세스간에 서로
공유하는 공유메모리 라든가 가상메모리등과 이며 아래에
보면 그 이유를 이해하실겁니다..
리전 테이블 :
메모리를 관리하기 위한 데이타 구조로 보시면됩니다..
만약 이런게 없고 그냥 프로세스의 각 리전안에서 바로
메모리주소 정보를 주면 안될까 하는 생각을 할수있는데
이렇게 되면 위치를 다양화 시킬수 없게 됩니다..
이게 무슨 말이냐 하면 프로세스당 각 리전 테이블에는
가상주소가 들어가 있습니다. 이가상 주소가 실제로 어디를
액세스 할지는 모릅니다.
리전 테이블에 와봐야 그게 이디있는지 알수있죠 그럼 이 리전
테이블에선 그주소가 어디있는지 실제 주소가 들어가 있게 되는데
꼭 메모리가 아닐수도 있다는 겁니다 가상메모리(하드디스크)도
될수있는거죠.
바로 이렇게 정보가 들어가있는 위치를 다양화 시킬수 있게됩니다..
원래 이래요 복잡~~^^