본문 바로가기

Linux(Centos or RHEL)/RHEL 기초

컨텍스트 스위칭과 컨텍스트...?

 

아래의 블로그를 참조하여 공부하였습니다. 제가 공부할 때 참조한 커널 버전은 v2.6.39.4입니다.

http://egloos.zum.com/rousalome/v/9990483

 

[라즈베리파이] 스케줄링: 컨택스트 스위치(Context Switch)이란

CPU에서 실행 중인 프로세스를 비우고 새로운 프로세스를 CPU에서 실행시키는 과정을 컨택스트 스위칭이라고 합니다. 컨택스트 스위치란 다음 그림을 보면서 컨택스트 스위칭란 용어에 대해서 살펴봅시다. CPU에서 E란 프로세스가 실행 중이라고 가정합시다. 어떤 프로세스가 CPU에서 실행 중이란 의미는 CPU 레지스터 세트에 프로세스 실행 정보가 채워져

egloos.zum.com

 

 

컨텍스트 스위칭이란?

 

멀티 프로세스 환경에서 CPU가 하나의 프로세스를 실행하고 있는 도중에, 인터럽트 요청이 오면, 현재 실행 중이던 프로세스의 실행을 멈추고 다른 프로세스를 실행하기 위한 작업을 하고, 다른 프로세스를 실행하기 시작합니다.

이같이 CPU가 다른 프로세스를 수행하기 위해 수행하는 작업을 컨텍스트 스위칭이라 합니다.

 

컨텍스트란?

컨텍스트는 프로세스가 실행 중인 그 자체를 의미합니다. 프로세스 실행을 리눅스에서는 레지스터 세트로 표현합니다. , CPU에서 실행 중인 프로세스의 레지스터 세트를 의미합니다.

 

그럼 리눅스에서는 컨텍스트 스위칭을 어떤식으로 구현해 놓았는지 확인해 보겠습니다.

컨텍스트 스위칭의 소스코드는 아래와 같습니다.

 

[https://elixir.bootlin.com/linux/v2.6.39.4/source/kernel/sched.c#L2949]

 

/*
 * context_switch - switch to the new MM and the new
 * thread's register state.
 */
static inline void
context_switch(struct rq *rq, struct task_struct *prev,
	       struct task_struct *next)
{
	struct mm_struct *mm, *oldmm;

	prepare_task_switch(rq, prev, next);

	mm = next->mm;
	oldmm = prev->active_mm;
	/*
	 * For paravirt, this is coupled with an exit in switch_to to
	 * combine the page table reload and the switch backend into
	 * one hypercall.
	 */
	arch_start_context_switch(prev);

	if (!mm) {
		next->active_mm = oldmm;
		atomic_inc(&oldmm->mm_count);
		enter_lazy_tlb(oldmm, next);
	} else
		switch_mm(oldmm, mm, next);

	if (!prev->mm) {
		prev->active_mm = NULL;
		rq->prev_mm = oldmm;
	}
	/*
	 * Since the runqueue lock will be released by the next
	 * task (which is an invalid locking op but in the case
	 * of the scheduler it's an obvious special-case), so we
	 * do an early lockdep release here:
	 */
#ifndef __ARCH_WANT_UNLOCKED_CTXSW
	spin_release(&rq->lock.dep_map, 1, _THIS_IP_);
#endif

	/* Here we just switch the register state and the stack. */
	switch_to(prev, next, prev);

	barrier();
	/*
	 * this_rq must be evaluated again because prev may have moved
	 * CPUs since it called schedule(), thus the 'rq' on its stack
	 * frame will be invalid.
	 */
	finish_task_switch(this_rq(), prev);
}

 

유저 공간에서 생성된 프로세스에 대한 정보(mm)를 교환하고, CPU의 레지스터들의 값을 바꿔줍니다.

mm이란? [http://egloos.zum.com/rousalome/v/9394482]

 

CPU의 레지스터들의 값을 바꾸는 작업은 CPU의 아키텍처에 따라 다르게 구현되어있는 것을 확인할 수 있습니다.

switch_to() : [https://elixir.bootlin.com/linux/v2.6.39.4/ident/switch_to]