Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

948
469
422439


[리눅스커널] 프로세스 상태: 언제 TASK_RUNNING 변경할까? Linux-Kernel Analysis

이번 시간에 프로세스를 RUNNING 상태로 누가 언제 변경하는지 알아봅시다.

wake_up_new_task()
[set_filter 가능 함수]
wake_up_new_task() 함수는 _do_fork() 함수에서 프로세스를 생성하는 과정에서 호출됩니다.

코드를 봅시다.
[https://elixir.bootlin.com/linux/v4.14.70/source/kernel/sched/core.c]
1 void wake_up_new_task(struct task_struct *p)
2 {
3 struct rq_flags rf;
4 struct rq *rq;
5
6 raw_spin_lock_irqsave(&p->pi_lock, rf.flags);
7 p->state = TASK_RUNNING;

7번째 줄 코드에서 TASK_RUNNING 로 프로세스 상태를 변경합니다.

wake_up_new_task() 함수 코드를 조금 더 보면 알겠지만, 프로세스를 스케줄러에게 실행 요청합니다.

wake_up_new_task() 함수는 _do_fork() 함수에서 호출된다고 했습니다.
관련 코드를 봅시다.
[https://elixir.bootlin.com/linux/v4.14.70/source/kernel/fork.c]
1 long _do_fork(unsigned long clone_flags,
2       unsigned long stack_start,
3       unsigned long stack_size,
4       int __user *parent_tidptr,
5       int __user *child_tidptr,
6       unsigned long tls)
7 {
8 struct task_struct *p;
9 int trace = 0;
10 long nr;
...
11 p = copy_process(clone_flags, stack_start, stack_size,
12  child_tidptr, NULL, trace, tls, NUMA_NO_NODE);
13 add_latent_entropy();
14
15 if (!IS_ERR(p)) {
16 struct completion vfork;
17 struct pid *pid;
18
19 trace_sched_process_fork(current, p);
...
20 wake_up_new_task(p);

20번째 줄에서 wake_up_new_task() 함수를 호출합니다.

_do_fork() 함수에서 copy_process() 함수 위치를 눈으로 따라가봅시다.
프로세스 기본 정보를 새로운 프로세스에 복제한 다음 wake_up_new_task() 함수를 호출하는 것입니다.

ttwu_do_wakeup()  
[set_filter 가능 함수]
ttwu_do_wakeup() 함수에서도 프로세스를 RUNNING 상태로 변경합니다.

[https://elixir.bootlin.com/linux/v4.14.70/source/kernel/sched/core.c]
1 static void ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags,
2    struct rq_flags *rf)
3 {
4 check_preempt_curr(rq, p, wake_flags);
5 p->state = TASK_RUNNING;
6 trace_sched_wakeup(p);

6번째 줄 코드를 보면 프로세스 상태를 TASK_RUNNING 으로 변경합니다.

ttwu_do_wakeup() 함수를 다음 함수에서 호출됩니다.
ttwu_do_activate() / ttwu_remote() / try_to_wake_up_local()

여기서 프로세스를 깨운다는 의미를 잠깐 더 생각해 봅시다.

프로세스를 깨운다는 문장은 프로세스 동작을 쉽게 표현한 것입니다.
위 문장을 조금 더 공학적으로 바꿔서 표현해 보겠습니다.
런큐에게 프로세스 실행 요청을 합니다. 이 때 런큐에서 실행을 기다리는 프로세스들과 우선 순위를 참고해서
실제 실행은 스케줄러가 수행합니다.

프로세스를 깨운다는 의미는 프로세스 실행을 스케줄러에게 요청한다는 것입니다.

yield() 함수
[set_filter 가능 함수]
yield() 함수 코드를 봅시다.
[https://elixir.bootlin.com/linux/v4.14.70/source/kernel/sched/core.c]
1 void __sched yield(void)
2 {
3 set_current_state(TASK_RUNNING);
4 sys_sched_yield();
5 }

3번째 줄 코드를 보면 set_current_state() 함수 호출로 프로세스 상태를 TASK_RUNNING으로 변경합니다.

do_nanosleep()

do_nanosleep() 함수 코드를 보겠습니다.
[set_filter 가능 함수]
[https://elixir.bootlin.com/linux/v4.14.70/source/kernel/time/hrtimer.c]
1 static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode)
2 {
3 struct restart_block *restart;
4
...
5 __set_current_state(TASK_RUNNING);

5번째 줄 코드와 같이 프로세스 상태를 TASK_RUNNING 으로 변경합니다.


#Reference 시스템 콜


Reference(워크큐)
워크큐(Workqueue) Overview


덧글

댓글 입력 영역