안녕하세요~ 이우영 입니다.


오늘도 전에 이어서 context_switch 를 보도록 하겠습니다.

저번시간에 본 switch_to 함수는 cpu내부의 레지스터 값을 변경하는 부분이였습니다.

리눅스는 mmu를 사용하기 때문에 메모리 영역도 변경 해주어야 합니다.
(원래는 먼저 봤어야 하죠 ㅎㅎ)

kernel/sched.h 에서 context_switch 함수 중 아래 부분이 

메모리 영역을 바꾸어 주는 부분입니다.

2665        if (unlikely(!mm)) {
2666                next->active_mm = oldmm;
2667                atomic_inc(&oldmm->mm_count);
2668                enter_lazy_tlb(oldmm, next);
2669        } else
2670                switch_mm(oldmm, mm, next);


이때 알아두실 부분이 커널 스레드는 메모리 영역을 가지지 않은다는 것입니다.

그래서 mm값에 NULL이 들어값니다.

위에 보면 NULL일 경우(커널 스레드) 현제 스래드의 mm을 빌려서 스위치를 합니다.

일반 스래드의 경우 switch_mm을 통해 mm을 스위치 합니다.

요번에도 mm의 스위치 하는 부분을 한번 화면에 출력 해보도록 하겠습니다.

void test_switch_mm( struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)

switch_mm과 똑같은 인자값을 받는 함수를 만들고 2670줄에 추가 해줍니다.
( {} 잊지 마세요 ㅎㅎ)

08_switch_mm.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kprobes.h>
#include <linux/sched.h>

void my_switch_mm( struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk)
{
	printk("prev   page[%x]   next   page[%x]\n",prev->pgd, next->pgd);
	jprobe_return();
}

static struct jprobe my_probe = {
	.entry = (kprobe_opcode_t *)my_switch_mm
};

int module_start()
{
	my_probe.kp.symbol_name = "test_switch_mm";

	if( register_jprobe(&my_probe) < 0 )
	{
		printk("oop`s!\n");
	}

	return 0;
}

void module_end() 
{
	unregister_jprobe(&my_probe);
}

module_init(module_start);
module_exit(module_end);
MODULE_LICENSE("GPL");

요번에도 jprobe를 이용해서 등록 하겠습니다.

switch_mm이 동작할 경우 스위치 되는 page의 주소를 출력 해보겠습니다.

먼저 07 예제만 했을경우

스크린샷-woo@ubuntu- ~-1.png

위와 같이 문맥 교환이 한눈에 보입니다.

스크린샷-woo@ubuntu- ~-2.png

오늘 예제도 추가해 보았습니다. 

중간에 init 스래드가 동작 할때만 page가 스위치 됩니다. 다른 것들은 커널 스래드 이기 때문입니다.

오늘도 여기 까지입니다.

가독성을 높이기위해 칼라로 만들어 봤는데요  눈이 아플지도 모릅니다 ㅎㅎㅎ

그럼 다음시간에 만나요~

http://ms-osek.org/ <- 쫌더 빨리 보고 싶으신분은 여기로 오세요~