본문 바로가기

Studying!!/공부를하자

Linux Scheduler 분석

 

소스코드 분석

 

struct task_struct *prev, *next;

long *switch_count;

struct rq *rq;

int cpu;

 

prev는 현재 실행중인 프로세스, next는 다음에 실행권한을 줄 프로세스이다.(struct task_struct *prev, *next)

rq는 이 프로세스 스케줄러의 실행 큐이다.(struct rq *rq)

cpu는 프로세서넘버를 받을 변수이다.(int cpu)

 

 

 

need_resched:

preempt_disable();

cpu = smp_processor_id();

rq = cpu_rq(cpu);

rcu_qsctr_inc(cpu);

prev = rq->curr;

switch_count = &prev->nivcsw;

release_kernel_lock(prev);

 

프로세스 스케줄링 처리 중에는 프로세스 스케줄링 요청이 계속해서 반복되지 않도록 금지한다.(preempt_disble()) 현재 사용 중인 프로세서 넘버를 cpu에 넘기고(cpu = smp_processor_id()), rqcpu에서 실행 중인 큐의 정보를 넘긴다.(rq = cpu_rq(cpu)) CPU 고유의 RCU (Read Copy Update) 구조체 내부의 gsctr를 증가(increment) 한다. (rcu_qsctr_inc(cpu))

prev에 현재 실행중인 큐의 current를 넘긴다.(prev = rq->curr) switch_count에 현재 실행중인 task의 구조체 내부 변수 nicsw를 넘긴다.(switch_count = &prev->nivcsw)

Context Switching이 발생할 때 schedule() 함수 안에서 (release_kernel_lock()) 함수를 통해 프로세스가 소유한 모든 커널 잠금을 해제한다. 이때 RCU에 대한 커널 잠금도 해제된다. (따라서 Context Switching이 발생하면 grace period가 지났다고 판단하는 기준이 된다.)

 

 

 

need_resched_nonpreemptible:

schedule_debug(prev);

spin_lock_irq(&rq->lock);

clear_tsk_need_resched(prev);

__update_rq_clock(rq);

 

인터럽트(interrupt)를 금지시키고, Spinlock를 획득한다. (spin_lock_irq(&rq->lock))

프로세스의 thread_info 구조체의 flags 필드에 있는 TIF_NEED_RESCHED를 지운다.(clear_tsk_need_resched(prev))

실행되고 있는 큐의 clock을 업데이트 한다. (__update_rq_clock(rq))

 

 

 

if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {

if (unlikely((prev->state & TASK_INTERRUPTIBLE) &&

unlikely(signal_pending(prev)))) {

prev->state = TASK_RUNNING;

} else {

deactivate_task(rq, prev, 1);

}

switch_count = &prev->nvcsw;

}

 

만약, 시그널 수신이 가능한 상태(TASK_INTERRUPTIBLE)이며, 시그널을 수신한 경우(signal_pending(prev))에는 실행 가능 상태(prev->state = TASK_RUNNING)로 간다. 그렇지 않고, 지금까지 실행 권한을 갖고 있었던 프로세스 prev가 대기 상태가 되면 프로세스 스케줄러는 해당 프로세스 prev를 실행 큐에서 제거한다.(deactivate_task(rq, prev, 1))

 

 

 

if (unlikely(!rq->nr_running))

idle_balance(cpu, rq);

 

프로세스 스케줄러가 담당하고 있는 실행 큐 rq에서 실행 가능한 프로세스가 없을 경우(unlikely(!rq->nr_running))에는 다른 CPU용의 프로세스 스케줄러가 관리하고 있는 실행 큐에서 프로세스를 가져온다.(idle_balnce(cpu, rq))

prev->sched_class->put_prev_task(rq, prev);

next = pick_next_task(rq, prev);

 

prev task_struct 내부의 sched_class기록(prev->sched_class->put_prev_task(rq, prev))하고, 실행 큐 내부에서 다음에 실행할 프로세스를 next라는 task_struct에 저장한다.(next = pick_next_task(rq, prev))

 

 

 

sched_info_switch(prev, next);

 

현재 실행중인 태스크와 다음 실행중인 태스크의 info switch한다.(sched_info_switch(prev, newxt))

 

 

 

if (likely(prev != next)) {

rq->nr_switches++;

rq->curr = next;

++*switch_count;

context_switch(rq, prev, next);

} else

spin_unlock_irq(&rq->lock);

 

다음에 동작해야 할 프로세스 next가 결정되면(likely(prev != next)) run queue context switch가 일어난 회수를 증가(rq->nr_switches++)하고, 현재 프로세스 스케줄링에 의해 선택된 프로세스 next가 될 것이다.(rq->curr = next))  그리고 switch_count를 증가하고(++*switch_count), 디스패처(context_switch(rq, prev, next))를 호출하여 프로세스 prev를 프로세스 next로 콘텍스트를 바꾼다.

그렇지 않다면, Spinlock을 해제하고, 인터럽트(interrupt)금지를 해제한다.(spin_unlock_irq(&rq->lock))

 

 

 

if (unlikely(reacquire_kernel_lock(current) < 0)) {

cpu = smp_processor_id();

rq = cpu_rq(cpu);

goto need_resched_nonpreemptible;

}

preempt_enable_no_resched();

if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))

goto need_resched;

 

프로세스 스케줄링을 처리하는 동안에 새로운 스케줄링 요청이 들어오는 경우 프로세스 스케줄링을 처리하고 있는 도중에 같은 CPU 상에서 다른 프로세스 스케줄링이 처리되게 되면 프로세스 스케줄링과 관련된 데이터 구조의 일관성이 손상된다. 프로세스 스케줄링 처리 중에는 스케줄링 요청이 반복되지 않게 금지한다. (preempt_enable_no_resched())

만약 프로세스 스케줄링을 처리하는 도중에 발생하게 된 새로운 스케줄링 요청이 있다면 현재 실행 하고 있는 프로세스 스케줄링 처리가 완전히 종료된 시점 (if (unlikely(test_thread_flag(TIF_NEED_RESCHED))))에서 프로세스 스케줄링 처리를 처음부터 다시 시작한다(goto need_resched).

 

 

 

 




 -prev process 수행 1




-prov process 수행 2




-시그널 수신할경우와 prev가 대기상태일경우




-실행 큐에 실행가능 프로세스 없을경우




-next process 선택




-next process prev process switch




-실행중에 외부에서 스케줄링 요청 경우

'Studying!! > 공부를하자' 카테고리의 다른 글

Pipe vs Shared Memory  (0) 2008.12.05
어셈블리 Linked List Operation (insert/remove/sort/search/empty)  (0) 2008.11.18
어셈블리 strcmp_length strcmp_byte 구현  (0) 2008.10.17
Code Optimizing  (0) 2008.10.15
어셈블리 GCD  (0) 2008.10.07