Computer System/운영체제

[운영체제] 04-3. Context Switching

쥥이 2025. 1. 3. 15:52
출처 서울대학교 홍성수 교수님, [K-MOOC] 운영체제의 기초, 4주차 Processes and Threads

 

시스템 콜과 유저 레벨의 function call의 공통점과 차이점

공통점

컨트롤이 caller 함수에서 다른 sub routine으로 이동한다.

현재 프로세스의 컨텍스트는 변화하지 않는다.

 

차이점

유저 모드의 function call은 모드 전환이 일어나지 않는다.

시스템 콜은 모드 전환이 발생한다. 오버헤드가 더 크다.

 

유저 모드 스택과 커널 모드 스택

유저 프로세스가 유저 레벨 함수를 호출하면 유저 스페이스 공간의 메모리 공간에 있는 유저 스택을 사용한다.

유저 프로세스가 시스템 콜을 호출한 경우에는 커널 함수는 유저 스택과 별개의, 커널 스페이스에 있는 커널 스택을 사용한다. 

즉, 유저 프로세스는 스택을 두 개를 가지고 있다. 유저에게 할당된 메모리 공간에 있는 유저 스택, 그리고 커널 메모리 공간에 있는 커널 스택이다. 유저 프로세스가 유저 레벨 스택을 사용할 때 유저 레벨 컨텍스트에 있다고 한다. 유저 프로세스가 커널 스택을 쓸 때는 커널 컨텍스트에 있다고 한다. 이때의 컨텍스트는 process state의 집합체의 의미가 아니라 어떤 스택을 사용하고 있는지를 의미한다.

 

인터럽트 컨텍스트란?

인터럽트 서비스 루틴도 하나의 함수이다. 이것도 스택이 있다. 이 스택은 커널 레벨 스택을 공유하게 된다.

 

컨텍스트 스위칭

Context Switching은 한 프로세스를 다른 프로세스로 교체할 때, running queue에 있는 프로세스에게 CPU를 할당해줄 때 동작하는 메커니즘이다. 앞에 있는 프로세스의 상태를 온전하게 대피시키고 과거에 수행되던 프로세스의 상태를 온전하게 불러와서 적재시키는 작업이다.

한 프로세스가 CPU를 다른 프로세스에게 양보를 하게 된다면, 그 프로세스가 다시 CPU를 받아서 재실행을 할 때 중단됐던 시점에서부터 정확하게 복원해서 재실행할 수 있어야 한다. 이 프로세스의 컨텍스트가 안전하게 대피시켜야 한다. 한 프로세스의 컨텍스트를 대피시키는 것은 block data move를 필요로 하는데 이는 비싼 operation이다. 그래서 어떤 프로세스가 CPU를 양보해서 나갈 때 프로세스가 기억해서 나가야 하는 최소량의 필수 정보만 인식해서 대피시키고 나머지는 그냥 유지시킨다.

 

원래의 process state를 대피시킨다는 것은 메모리 계층에서 다음 단계의 메모리로 데이터를 복사한다는 것을 의미한다. CPU 레지스터에 있던 값을 메인 메모리로 이동시키는 식이다.

메모리 계층: CPU 안 레지스터 - (캐시 메모리) - 메인 메모리 - 스토리지 디바이스

 

그럼 프로세스가 사용 중이던 메인 메모리에 있는 정보들(코드 세그먼트, 데이터 세그먼트 (글로벌 변수), 스택 세그먼트, 힙 세그먼트)도 스토리지 디바이스에 대피시켜야 할까?  일반적으로 옮길 필요 없다. 멀티 프로그래밍 시스템에서는 메인 메모리에 아직 수행이 끝나지 않은 시스템을 다 적재해놓는다. 그런데 메인 메모리가 너무 작다면? 컨텍스트 스위칭할 때 메인 메모리에 있는 것을 하드 디스크로 대피시켜야 한다. 1970년대 메인 메모리 크기가 작을 때는 그랬다. 전체 이미지를 대피하는 것을 roll-in/roll-out이라고 한다. 

 

컨텍스트 스위칭의 과정

- 기준: 80186 (1980년대 16비트 프로세서)

 

1. 실행을 중지할 프로세스의 상태를 스택에 안전하게 대피시킨다.

- PSW) 원래의 모드 비트를 저장한다. - 사용자 모드 비트인 1

- SEG task, OFF task) 실행을 재개했을 때 실행시킬 다음 명령어 주소 값이다. (프로그램 카운터 값)

- AX ~ ES) 프로세스가 사용 중이던 레지스터 값들을 스택에 push해놓는다.

- 스택의 탑을 가리키는 Stack Pointer는 PCB에 저장해둔다.

 

2. 새롭게 실행시킬 프로세스의 컨텍스트를 복원한다.

- pcb에 있는 스택 포인터를 CPU의 스택 포인터에 저장한다.

- 스택에서 레지스터 값들을 pop시켜서 레지스터에 복원시킨다.

- 스택에 있는 주소를 프로그램 카운터에 저장하고 모드 비트를 원래대로 돌려놓는다.

- ireturn 호출을 통해 인터럽트 모드로부터 사용자 모드로 돌아간다.