프로세스 정의
프로세스란?
- 실행 중인 프로그램 : 프로그램은 저장장치에, 프로세스는 메인 메모리에 존재
- 시스템 콜을 통해 자원을 요구하는 주체(경쟁하는 주체)
- 멀티 프로세싱 혹은 멀티 태스킹(프로세스와 task는 같은 의미) -> 멀티 태스킹을 더 많이 사용함
- 시분할 시스템의 경우 여러
- 하나의 프로그램이 수행 중 여러 개의 프로세스개의 프로세스를 동시에 수행을 만드는 경우도 있음(ex> child)
- 사용자 프로세스와 시스템 프로세스로 나누어짐 - 자원 경쟁 측면에서는 동일
- 사용자 프로세스 - 응용 프로그램이 실행되는 것
- 시스템 프로세스 - 운영체제가 필요에 의해 생성
프로세스의 문맥(context)
- 문맥 : 시분할 시스템에서는 중단과 속개를 반복하게 됨. 중단, 속개 2개의 상태가 있기 때문에 프로세스는 동적인 상태 변화를 하는 객체이다. 프로세스의 모든 실행 정보가 중단될 당시 어디 보호되고 속개될 때 복구되어야 한다. 프로세스의 모든 수행 정보를 문맥이라고 한다. 문맥은 프로세스의 모든 실행 상태를 담고 있기 때문에 간단하지는 않다.
프로세스 문맥의 구성
- 사용자 수준 문맥(User-level context) - 메인 메모리 현재 상태
커널공간이랑 나머지는 프로세스. 한 프로세스가 커널 공간을 제외하면 마치 전체 공간 차지하는 것을 차지하는 것처럼 보인다(가상 메모리이기 때문) 각 프로세스는 가상 메모리 기법 에 의해서 전체 메모리 공간을 사용할 수 있다고 간주하고 넘어가도록 한다.
맨 밑에 text 영역, 그 위에 해당 프로그램에서 선언된 전역변수가 배치되는 부분, 이 광역변수 영역은 data와 bss부분으로 나뉜다. heap은 c에서 malloc으로 동적 메모리 할당 받는 요청이 왔을때 할당하고, free함수가 불리면 회수하는 동적인 곳. runtime시 일어나기 때문에 늘엇다 줄었다 하는 곳이다(힙이 운영된다) 맨 위가 stack인데 stack은 보통 프로그램의 함수가 호출될 때마다 call stack의 자료가 push가 되고 return될때 pop up 된다.
stack에서 다뤄지는 것 중에 지역변수라는 것이 있다. 지역변수는 call stack 내에서 잡히게 되어서 그 함수가 호출될때 stack에 push되고 함수가 return될 때 pop된다.
char g_ch =0 ; 이 부분에서 0으로 선언한 것은 컴파일 시부터 절대 잃어버리면 안되기 때문에 프로그램이 프로세스화 되는 과정에서 메인 메모리가 탑재해주는 그 시점부터 0으로 초기화 시켜줘야 한다.
char g_str[1024]와 int g_int 는 컴파일한 바이너리 코드를 다 잡고 있어야 할 필요가 없다. 초기화 정보가 없는 광역변수가 bss에 해당한다. bss는 속도가 빠르다.
- 텍스트 영역 - 프로그램 코드 부분 : 코드는 binaray code를 의미, binary code가 메모리에 탑재된 것을 텍스트 영역
- 자료 영역 - 프로그램 광역변수 부분 : 광역변수가 차지하는 메인메모리 상의 부분
- 스택 영역 - 프로그램 실행시간 스택 부분 : 콜 스택을 의미
- 힙, bss
https://shrtorznzl.tistory.com/82
cf> Call Stack 프레임 - 파라미터, 지역변수, return address, frame point가 frame이다. stack에 들어가는 push, pop되는 시스템. Call stack 안에 call stack 프레임이 들어간것.
- 파라미터 : 호출되는 함수의 인자에 assign 되는 값
- 지역변수 : 호출되는 함수 내에서만 생성되는 변수
- return address : 호출되는 함수 종료 시 되돌아가 수행을 계속해 가기 위하여 jump해 가야 할 주소, 함수를 호출한 그 라인의 다음라인이 됨.
- frame point(stack frame pointer) : 스택 상의 프레임 시작 주소, 이 frame이 push가 될 때, 그 전 frame (push되기 전에 top에 있던 프레임)의 frame 시작주소를 여기 기억하고 있다. push 당한 놈의 frame 시작주소를 기억하고 있어야지만 된다.
- 프레임 : 함수호출 시 스택 상에서 운용되는 내용(데이터)
- 프레임 포인터 : 스택 상의 프레임 시작 주소(베이스 주소)
- 프레임의 크기가 함수마다 다르기 때문에 바로 이전 프레임의 프레임 포인터 값을 프레임 내에 간직하고 있어야 함.
Stack Pointer : 콜 스택의 최상위 메모리 주소, stack pointer를 가지고 있어야만 스택 operation을 원할히 할 수 있다. push나 pop같은 것을 수행하기 위해 가지고 있는것. 현재 어디까지 썼는지 stack을. 마지막에 저장된 데이터의 주소.
func1에 10,20을 호출하였을 경우
위에 부분이 main함수의 frame이 된다. main함수의 frame을 보면 frame의 base주소가 있을것이다. 약자로 mfp라고 썼다. main frame의 시작주소를 가리키고 있다. func1이 call일어나면 먼저 파라미터 2개를 push하고 return address를 적고 점프를 한다.
새로 불린 함수 내에서는 ebp(frame pointer)의 값을 copy해서 pop됐을때 다시 복구하기 위한 준비를 한다(mfp값을 caller's frame pointer에 save해두고) ebp에는 현재의 frame base 주소를 ebp에다가 넣어준다. 그리고 지역변수들을 stack에 push된다. stack pointer register는 intel에서는 esp레지스터가 된다. func를 호출하고 나면은 ebp와 esp는 다음을 가리키게 되고 있을 것이고, 나중에 pop up을 하기 위한 대비책으로는 즉 메인 프레임 포인터 값은 mfp에 save해두고 나중에 돌아갈 수 있게 해놓았다.
방금 한것을 assembly 언어로 해석한것
foobar.c -> foo가 불리게 되면 bar(111,222)호출해서 a,b에 assign된다.
main함수가 없어도 compile되어서 생성된 것 볼 수 있다. gcc 컴파일 돌려서 -S하면 assemble 코드가 생성됨.
-m32는 32bit machine assembly code로 생성해달라는 의미이다. 출력해서 나온 파일을 보면, foo에 해당하는 assembly line이 있고 bar에 해당하는 assembly라인이 있다.
foo로부터 bar를 호출하는 부분이 어디냐 하면은 빨간색, movl $222은 esp(stack pointer)가 포인팅하는 곳에다가 222를 move한다는 것은 push하는 것이다. movl $111 %esp도 push를 하는것이다. 그리고나서 call bar를 하면은 instruction ptr을 push하고, foo로 점프를 하는 것이다.
foo로 한 것이 3갱이다. 222 push하고, 111 push하고, instruction ptr값 push하고.
ESP는 stack pointer이고 EBP는 frame pointer이다. frame 내에서의 상대적인 주소들을 적절하게 다루기 위해서 EBP라는 변수를 별도로 두고 있다. 만약에 frame pointer를 따로 쓰지 않는 경우, 특히 frame이라는 개념자체가 없는 경우에는 EBP를 일반 레지스터로 쓸 수 있지만, 일반적으로는 EBP를 사용한다.
instruction ptr은 program counter인데, intel 32bit에서는 EIP(ip가 instruction pointer의 약자이다)레지스터. 프로그램 카운터라고 보면 된다. call을 하면 instruction ptr까지도 push를 하니까 3개가 push가 된것이고, bar로 점프를 하게 되는 것이다.
bar에서는 ebp, 즉 현재까지의 frame pointer register의 값, 그거를 다시 stack에 push를 하는 것이다. 그리고 나서 ebp의 값을 옮기는 것이다. push해서 save했으니까 ebp의 값을 현재 bar의 frame의 base값으로 삼는다. 그리고 나서는 local 변수와 계산들에 대한 operation을 상대적인 주소로 진행한다. (ebp로 operation한다) pop 했을때도 ebp값을 복구해주어야만 돌아가서도 제대로 동작한다는 것이다. ebp값을 save하는 것이 중요하다.
코드상으로는 그렇고 그림으로 그려보면
foo가 돌릴때도 ebp save하는 것이 있었고, bar를 부르기 위해 222,111 push. call이 일어나면 현재의 instruction pointer값을 push하고 3개가 stack에 들어가 있고, ebp값을 copy해서 return됐을 때 복구할 수 있도록 해놓고, 현재의 esp값이 바로 새로운 ebp값이 만들어지는 것이다.
마지막 그림이 call이 이루어진 다음의 상태이다.
- 커널 수준 문맥(Kernel-level context) - 커널이 관리하는 내용
- CPU 내의 각종 특수 레지스터의 내용 : 특수 레지스터의 종류
- 프로그램 카운터(PC) : 다음 수행할 명령어의 주소를 담고 있는 레지스터
- 스택 포인터(SP) : 스택 운영에 필요함
- CPU 상태 레지스터(PSR, Program Status Register) : 예를 들어 모드비트도 상태 레지스터의 한 비트에 해당한다.
// -> 커널이 관리해야 하는 중요한 문맥에 해당한다.
- CPU 내의 각종 범용 레지스터 내용 - 특수 레지스터와 달리 일반 계산용 레지스터가 된다.
- 프로세스의 현재의 각종 자원 사용 정보
- 커널의 프로세스 관리 정보
특수 레지스터에 어떤 것들이 있고, 각각의 역할이 무엇인지 이해하려면 CPU내의 레지스터를 중심으로하는 동작구조를 이해할 필요가 있다.
시작은 먼저 PROGRAM COUNTER(파란색부분)에서 시작해야 한다. CPU는 기본적으로 fetch(가져온다), decode, execute과정을 계속해서 반복하는 것이다. 메인메모리로부터 명령어 하나씩을 순차적으로 읽어오게 된다. 즉, fetch를 하게 된다. 그래서 Program Counter는 다음으로 읽어올 명령어의 주소를 담고 있는 것이 되고, 이 주소를 아래의 Address Buffer에 실으면 어떤 하드웨어적인 동작을 통해서 해당 명령어가 Instruction Register(명령어 레지스터)로 읽혀들어오게 된다. 어디서 읽혀들어오냐면 메인 메모리의 그 주소로 읽혀들어오게 된다. 여기까지가 fetch의 과정이다. 그러면 그 내용을 가지고 decode를 하게 된다. decode는 이 명령어를 해독하는 것이니까 그 다음에는 execute를 시키는 것이다. execute는 옆에 있는 연산 논리 회로(ALU)에 의해서 진행된다. 그러한 과정에서 PC라는 것은 CPU가 이제 다음으로 실행할 명령어의 주소, 즉 다음으로 fetch할 주소를 담고있는 특수 레지스터이다. 만약 방금전에 실행한 명령어가 조건 명령어였고, 그 결과로 특정 명령어로 jump를 해야할 일이 생겼다면 jump해갈 주소를 여기 담게 된다. 결과가 jump할 필요가 없었다면 계속 수행해야될 것이 되니까 조건 명령어의 바로 다음 주소가 Program Counter에 담겨있게 된다. 기본적으로 PC값은 현재 수행한 명령어의 바로 다음 명령어 주소로 자동으로 설정되도록 되어 있다. 그러니까 jump가 멀리 일어나지 않는다면, 자동적으로 그 다음 명령어가 수행되게 된다. 그런데 이게 왜 문맥으로 중요하냐? 시분할 시스템에서 하필이면 어떤 명령어에서 딱 time slice가 소진이 되어서 스케쥴링이 일어났는데, 우선순위가 떨어져서 다른 프로세스에게 그 다음 슬라이스를 주게되었을 경우 그렇게 되면, 현재 돌던 것은 잠시 중지된다. 중지된다는것, 어느 주소까지 수행되고 중지된다 그런 후에 나중에 다시 어떤 조건이 만족되어서 속개된다면 어디서부터 속개되어야 할까? 바로 현재까지 실행되었던 명령어 그 다음 주소의 명령어부터 실행이 되어야 한다. 그래서 그 다음 주소가 어디 담겨있냐하면 Program Counter에 담겨있다. 그래서 이 Program Counter값을 반드시 보존해야지만, 즉, 문맥으로 보존해야지만 시분할 시스템에서 잠시 중단되었다가 속개될때 문제가 없게 된다. 즉, Program Counter가 문맥을 형성하는 중요한 특수 레지스터이다.
그렇게 fetch 해온 데이터를 decode해서 실행하게 되면, 그 결과로 특정한 상태가 발생할 수 있게 되는데, 그러한 상태를 flag register에 반영을 한다. 상태는 다양한 것들이 있는데, 예를 들면 덧셈이나 곱셈을 했는데 캐리가 발생했다던지, 이런것들이 상태에 해당한다. 아까의 process 상태와는 다르게 CPU의 상태를 의미한다. PSR(Program State Register)이라고 하는 상태 레지스터가 있게 되는데, 현재 명령어 실행 후, 상태를 기록하는 것이 기본역할이기도 하지만, 그거 이외에도 decode한 명령어를 수행할 때 조건으로도 작용될 수 있고, 다음 명령어 수행할 때 중요한 정보로 반영되기도 하는 아주 중요한 레지스터이다. 예를 들어 덧셈을 했는데 올림이 생기면 올림이 생겼다는 것을 상태 레지스터에 기록을 해두고, 공교롭게도 덧셈 명령어 수행하고 난 다음에 time slice가 딱 끝나서 다른 process가 잠시 돌았다 그거 돌고 다시 속개될때 올림이 일어났다는 정보를 까먹었다, 어디다 기록하지 않았었다. 그렇게 되면 숫자가 날라가게 된다. 그렇게 되면, 연산에 오류가 생긴다. 상태 자체를 잘 보존해야 한다. 즉 PSR이라는 특수 레지스터의 값이 문맥의 중요한 역할이 된다.
Stack Pointer(SP)가 process 수행 시 call stack에 운영된다고 하는데 이 call stack의 탑에 해당하는 주소를 저장하는데 사용되는 특수 레지스터이다. 이것도 함수 중심의 프로그램을 수행할 때는 굉장히 중요한 역할을 하게 된다. 문맥으로도 따로 관리를 해야하는 부분이다. PC, PSR, SP 레지스터는 시분할 시스템에서 프로세스가 번갈아 가면서 수행될 때, 중단과 속개를 오류없이 반복하기위해서 잘 보존되어야 하는 중요한 레지스터들이 된다.
범용 레지스터들 : 사칙연산이나 논리 연산들을 수행하는 명령어에 사용이 된다. 특히, 그러한 명령어에 operand로 사용되는 계산 목적의 레지스터로서 이 범용 레지스터의 내용도 process가 중단되었다가 속개될때, 잘 보존되었다가 복구되어야만 process가 원할히 돌 수 있다.
사용자 수준의 문맥과 PC, SP, PSR과 어떤 연관관계를 가지고 있을까? 임의 프로세스가 현재 실행되고 있다고 볼 때, Call stack의 탑 주소 관리는 SP 레지스터가 하고, 그리고 text 내에 다음 수행할 명령어의 주소는 PC 레지스터에 담겨있다. 물론 그 명령어가 하나하나 실행되고 난 결과로 생겨나는 CPU의 상태는 PSR에 저장된다. 이렇게 현 프로세스가 진행될 때에는 이러한 특수 레지스터들이 그 수행에 주어진 역할들을 함께 하게 된다. 근데 스케쥴링에 의해서 다른 프로세스가 돌아가기 시작하면 이 값들을 덮어쓰고 만다. 그러면 다시 속개될때 수행에 문제가 생긴다. 따라서 다른 프로세스가 수행을 시작하기 전에 반드시 그 시점의 특수 레지스터 값들을 어딘가에 save해야 된다. 그곳이 바로 PCB이다. 즉, 프로세스 컨트롤 블록이라는 것인데, 그곳에 save를 했다가 다시 속개될때 그곳으로부터 restore를 해야지만 원할하게 돌아가게 된다. 특수 레지스터만 이렇게 PCB를 이용해서 save와 restore를 반복하는 것은 아니다. 범용 레지스터들도 마찬가지이다. (여기 그림에는 안나타냄) PCB가 이러한 레지스터 값들만 보존하는 것일까? 그것은 아니다. 그보다 더 많은 정보들을 담고 있는데, 이에 대해서는 나중에 설명한다.
PC 레지스터와 SP레지스터는 이름 자체가 의미하는 바가 있기 때문에 그 역할을 금방 이해할 수 있다. 그러나 PSR, 즉, Program Status Register 또는 Flag Register는 추가 설명이 필요하다. PSR은 PSW(Program Status Word)라고도 부른다.
예를 보면, Pentium Flag CPU의 경우, 다음과 같은 Flag Register를 갖고 있다.
flag register는 위와 같은 내용을 담고 있다는 것인데, 프로세스의 중단과 속개를 위해서는 반드시 보존되어야하는 주요한 내용인 것이다. 예를 들어, AND 명령어를 수행하고 난 결과가 true이면, ZF 비트가 1이 된것이다. 곧바로 스케쥴링이 되어서 다른 프로세스를 진행시킨 후에 나중에 속개하게 될때 이 flag ZF가 0일지 1일지 보장이 안되면, 만약에 0으로 바뀌어있으면, 속개된 후 프로세스는 엉망이 된다. 따라서, 잘 보존했다가 속개 시에 꼭 리스트화를 하고 속개해야 된다.
ARM 계열의 CPU의 PSR의 사례이다. 여기도 28번에서 31번 bit에 유사한 flag들이 있다. NZCV가 대표적인 4가지 flag이다. 이러한 flag뿐만 아니라 interrupt enable, disable이런 다양한 flag들을 여기에 담고있다. 참고로 ARM process의 경우, processor 수행 모드가 여러가지가 있어서 모드에 따라서 적합하게 작동하도록 아주 정교하게 설계가 되어있다. Fast Interrupt, Trap과 관련된 다양한 모드들이 함께 구분되어 동작되도록 되어있다. 즉, Rest, Data Abort, FIQ... 이러한 여러가지 모드가 있다. 이런 모드로 적절하게 변경을 해가면서 수행이 될 수 있도록 되어있다. 참고로 NZCV(Negative, Zero, Carry, Overflow)의 약자이다. 이런 것들이 상태 플래그가 된다.
문맥교환
- CPU를 다른 프로세스로 넘기는 작업( CPU라는 자원 입장에서 )
- 실행이 정지되는 프로세스의 문맥은 보존되고, 새로 실행되는 프로세스의 문맥이 활성화됨
- 사용자 수준 문맥은 메모리에 남아 있다( 원래 메모리에 있었음 ), 메모리의 현재 상태를 이야기한다. 원래 메모리에 있었기 때문에 그대로 두면 문맥이 보존된다. 커널 수준의 문맥이 문맥 교환에서 중요하다.
- 커널 수준의 문맥 중에서 Program Counter, Stack Pointer, PSR, 범용 레지스터.
- CPU에 있던 레지스터의 내용들은 추후의 복구를 위해 저장(save)되고(왜냐하면 다른 프로세스가 될 때 이 값들을 뭉게버리기 때문에), 스케쥴링된 새로운 프로세스의 문맥이 적재(restore)됨.
- 실행 중단 프로세스의 범용 레지스터와 특수 레지스터 값들을 저장해두고(PCB에 저장한다), 그 다음에 스케쥴링에 의해서 속개될 프로세스 문맥 정보를 그 프로세스 PCB로부터 restore하는 과정을 문맥 교환이라고 한다.
- 그 이외의 커널 수준 문맥, 각종 자원 정보와 프로세스 관리정보들은 어떻게 해야 할까? 그건 PCB에 이미 담겨있기때문에 그대로 두면 보존이 된다.
- 문맥 교환은 프로세스의 중단과 속개를 반복할 때 일어나는 문맥의 보존과 복구의 절차이다.
문맥교환의 시점
- 프로세스가 중단되고 다른 프로세스가 수행되는 경우에 발생한다고 볼 수 있다. 문맥 교환의 시점이라는 것이 프로세스의 상태라는 주제로 넘어가게 되고, 스케쥴링과 PCB에 대한 설명으로도 이어지게 된다.
- 문맥교환이 일어나는 시점은 4가지로 이루어질 수 있는데, ( 스케쥴링, 인터럽트, 입출력 요청, 시그널 대기요청 )
-> 스케쥴링과 인터럽트는 비자발적 문맥교환 // 입출력 요청과 시그널 대기요청은 자발적 문맥교환
- 첫번째가 시분할 기반의 스케쥴링. 스케쥴링이 일어나는 시점에 문맥교환이 일어날 수 있다. 스케쥴링은 기본적으로 타임 슬라이스가 소진되었을때 스케쥴링이 일어난다.
- 두번째가 인터럽트로 인해 CPU가 선점 당할 때.
- 세번째로 프로세스 스스로가 입출력 요청을 하게 되면, 당연히 다른 프로세스가 CPU를 돌려야 한다. 그 경우 문맥교환이 일어날 수 있다.
- 네번째로 프로세스 스스로가 다른 프로세스가 보낼 시그널에 대한 대기 요청을 하여 CPU를 반납할 때. 즉, 다른 프로세스의 상태 변화를 기다리기 위해서 대기를 해야할 경우 마냥 대기할 수 없으니까 CPU를 반납함으로써 잠시 다른 프로세스가 돌아야되는데 그것을 위해서 문맥교환이 일어난다.
// 문맥, 문맥교환 전부 시분할 시스템이 전제되어 있다.
프로세스의 상태 천이
중단과 속개 2개의 상태보다는 더 복잡하고 다양한 상태가 존재한다. 특히 운영체제의 종류에 따라서 상태들의 종류가 다르다.
프로세스의 상태(영어로 알아두면 좋다.)
- 생성(new) : 프로세스가 생성된 상태, PCB와 메모리 상의 주소 공간이 마련된 상태.
- 준비(ready) : CPU의 배정을 기다리는 상태. 큐에 스케쥴링 되기를 기다리는 상태
- 실행(running) : 프로세스가 CPU에 의해 실행되고 있는 상태. 예를 들어 core가 하나라면 한순간에 돌리는 process는 하나.
- 대기(blocked) : 프로세스가 어떤 사건(event)이 발생하기를 기다리고 있는 상태 (사건의 예 : 입출력의 완료 또는 시그널의 접수)
- 종료(terminated) : 프로세스가 종료된 상태
비자발적 문맥교환(할당시간 경과, 인터럽트 발생) 이 경우는 곧바로 준비상태로 처리한다. 사건을 기다리기 위해 block될 이유가 없기 때문이다. 입출력 요청이나 시그널 대기는 대기상태로 천이했다가, 입출력 완료 또는 시그널 접수 되면 준비상태로 천이된다.
실행상태가 되기 위해서는 준비상태를 거쳐서야만 실행상태로 천이될 수 있다. 즉, 스케쥴러에 의해서 CPU가 할당되어야만 실행상태로 가게 된다.
준비상태 : 스케쥴링에 의하여 언제든지 실행이 될 수 있는 상태
여기서 준비 상태를 빠져나가는 화살표는 하나, 그 대상은 실행상태로 가는 경우이다. 즉, 프로세스가 CPU에 의해서 실행되기 위해서는 반드시 준비 상태를 거쳐야 한다. 결국, 준비 리스트(ready list), 준비 큐(ready queue)를 통과해야만 한다는 것이다. 왜 준비 큐만 얘기하지 않고, 준비 리스트라고 하는지? -> 스케쥴러가 큐만 사용하는 것은 아니다. 큐라고 하면 FIFO이 원칙인데, FIFO 원칙만 사용하는 것은 아니기 때문에 혼용해서 부를 수 밖에 없다.
- 준비상태로 천이되어 오는 경우(그림에서 3가지)
1. 프로세스 생성 후, 선정되어 CPU 할당을 대기하고 있게 되거나, (생성상태에서 들어오는 경우)
2. 프로세스가 실행되던 도중에 비자발적인 문맥교환이 일어났거나, (실행상태에서 들어오는 경우, 비자발적 문맥교환)
- CPU의 독점 방지를 위해서 타임 슬라이스 소진 시,
- 또는 인터럽트 발생으로 커널이 CPU를 회수하고 프로세스를 일시 중지시킨 상태
3. 대기하고 있던 입출력 또는 시그널 사건이 완료된 경우(대기 상태에서 들어오는 경우)
- 상태천이도를 놓고 볼 때 스케쥴링이란 준비 상태에 있는 준비리스트 또는 준비 큐에 있는 것을 뭔가의 원칙에 의해서 하나 선택해서 CPU가 수행할 수 있도록 타임슬라이스를 배정해 주는 것.
실행 상태 : CPU가 프로세스를 실행하는 상태
- 실행상태에서 천이되는 경우
1. 실행 상태 -> 준비 상태
실행상태에서 할당시간이 지나고 나면, 회수를 당해서 준비상태로 천이되게 되고, 그렇게 되면 스케쥴링을 통해서 다른 프로세스에 있는 프로세스들과 우선순위 경쟁을 하게 된다.
물론 할당시간이 모두 경과되지 않더라도 입출력 제어기로부터 어떤 인터럽트가 발생했다, 이 프로세스랑 관련이 있는 인터럽트이든, 관련이 없는 인터럽트이든 입출력 제어기로부터 어떤 인터럽트가 발생하면 이때도 역시 준비상태로 천이가 된다. 이렇게 할당시간이 경과되거나 인터럽트 발생하면 비자발적 문맥 교환을 거쳐 준비상태로 천이된다.
2. 실행 상태 -> 대기 상태
: 주어진 할당시간 동안 프로세스를 진행하다보면 두 개의 모드 중에 한 모드에 있게 된다. 사용자 프로그램이 사용자 모드로 수행되다가 시스템 콜을 실행하면 커널 모드로 들어가서 커널 부분을 실행하게 되는데 그러다가 입출력 요청이나 시그널 대기하는 내용을 수행하면 대기 상태로 들어가게 되어있다.
3. 실행 상태 -> 종료 상태 : 퇴출(exit)
대기 상태
대기 상태로 가면 블럭되게 된다. 블럭된 기간 동안은 CPU가 더 이상 프로세스를 수행할 필요가 없어진다. 따라서 CPU를 반납을 하게 되는데, 이렇게 대기 상태로 들어가면 프로세스는 사건별로 구성된 대기 리스트로 이동을 해서 대기를 하게 된다. 그런 후 대기하던 사건이 완료되면, 다시 준비 상태로 천이하게 된다. 사건만 해당하는 것은 아니고 입출력도 해당한다. 대기 상태인 동안 입출력 장치는 입출력을 진행하고 있을 것이고, 어떤 프로세스는 이 프로세스에게 시그널을 보낼 준비를 하고 있을 것이다. CPU는 준비 상태에 있던 프로세스들 중 하나를 스케쥴러를 통해 선택해서 실행시키고 있을 것이다. 대기 상태로 존재한다는 것은 입출려과 CPU가 overlap되어서 동시에 동작할 수 있는 기회를 제공하는 것이다.
PCB(Process Control Block)
문맥, 상태는 과연 어디에 보관되어 있을까? 보관의 실체는 어디일까? PCB라고 하는 것이다.
PCB는 프로세스의 일생 동안 해당 프로세스의 모든 정적 및 동적인 정보를 저장하느 저장소이다. 결국 프로세스의 문맥을 저장하는 자료구조이자 현재 프로세스의 상태, 그리고 메모리나 파일 통신 등 각종 자원 정보가 저장되는 저장소이다.
커널이 프로세스를 관리하기 위한 실체 - 커널은 PCB를 통해 프로세스 관리.
( 리눅스의 경우 PCB에 해당하는 커널 내 자료구조의 이름은 task struct이다 )
- 프로세스 상태 천이도에 있었던 준비 리스트나 대기 리스트는 결국에는 PCB의 포인터의 리스트였던 것이다.
단, PCB라는 자료구조 자체가 리스트들로 이리저리 옮겨다니도록 구현하진 않고, PCB의 포인터가 리스트를 옮겨다닐 것이다. C가 왜 시스템 언어로 적합한지가 이런 이유이다.
- 실행상태 시에 PCB는 준비리스트에 존재하며, 상태표시만 RUNNING 상태로 변경
5가지 상태 중 실행상태가 있었는데 실행상태라는 것은 리스트를 담고있는것이 아니고, 프로세스가 실행된다는 사실이다. 상태 표시만 있는 것이다. 실질적으로 CPU가 프로세스를 돌리는 것이다. 그래서 PCB에 실행상태 즉 RUNNING이라고 상태를 표시하는 것이다. 단, PCB는 그냥 준비리스트에 존재한다. CPU가 프로세스를 타임슬라이스 동안 실행시키는 특수 상태가 실행상태이다.
프로세스 하나마다 커널 내의 자료구조인 PCB가 만들어져서 사실은 커널은 PCB를 관리하는 것이다는 내용이다.
CPU 스케쥴링 정보 : 스케쥴링은 스케쥴링 알고리즘에 의해서 실행되는데 스케쥴링 알고리즘은 각종 정보를 분석해서 최고의 우선순위의 프로세스를 결정해주어야 하기 때문에, 이를 위해서 어딘가 저장해야 되는데 그게 PCB이다.
PCB라는 것이 커널이 프로세스를 관리하는 실체이다.
문맥교환에는 PCB가 반드시 이용되게 된다.
시스템 호출, 인터럽트, 문맥교환
프로세스의 생성과 종료
'CS > 운영체제' 카테고리의 다른 글
Race condition / Critical Section (0) | 2022.06.07 |
---|---|
[4] 컴퓨터 구조와 OS 연계 (0) | 2022.03.21 |
[3] 컴퓨터 구조와 OS 연계 (0) | 2022.03.14 |
[2] 시분할 시스템, 실시간 시스템 (0) | 2022.03.09 |
[1] 운영체제의 발전 (0) | 2022.03.07 |