Scheduler -9- (Stop Scheduer)

 

Stop-task Scheduler

Stop 스케줄러는 매우 심플하다. 어떠한 스케줄러보다 우선 순위가 더 높아 preemption되지 않으며 다른 cpu로 migration도 허용하지 않는다. 따라서 모든 요청에 대해 대부분 거절하거나 아무런 일도 하지 않는다. 오직 stop 태스크 수 및 런타임 계산만 허용한다.

 

select_task_rq_stop()

kernel/sched/stop_task.c

static int
select_task_rq_stop(struct task_struct *p, int cpu, int sd_flag, int flags)
{
        return task_cpu(p); /* stop tasks as never migrate */
}

migration을 허용하지 않는다.

 

check_preempt_curr_stop()

kernel/sched/stop_task.c

static void
check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags)
{
        /* we're never preempted */
}

수행 중인 stop 태스크의 preemption을 허용하지 않으므로 preemption 체크를 할 필요없다.

 

yield_task_stop()

kernel/sched/stop_task.c

static void yield_task_stop(struct rq *rq)
{
        BUG(); /* the stop task should never yield, its pointless. */
}

수행 중인 stop 태스크의 preemption을 허용하지 않는다.

 

enqueue_task_stop()

kernel/sched/stop_task.c

static void
enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
{
        add_nr_running(rq, 1);
}

런큐에 동작중인 엔티티의 수를 증가시킨다.

 

dequeue_task_stop()

static void
dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags)
{
        sub_nr_running(rq, 1);
}

런큐에 동작중인 엔티티의 수를 감소시킨다.

 

task_tick_stop()

kernel/sched/stop_task.c

static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued)
{
}

task 틱마다 아무런 동작도 하지 않는다.

 

update_curr_stop()

kernel/sched/stop_task.c

static void update_curr_stop(struct rq *rq)
{
}

아무런 동작도 하지 않는다.

 

switched_to_stop()

kernel/sched/stop_task.c

static void switched_to_stop(struct rq *rq, struct task_struct *p)
{
        BUG(); /* its impossible to change to this class */
}

설계상 이 stop 태스크로의 스위칭은 불가능하다.

 

prio_changed_stop()

kernel/sched/stop_task.c

static void
prio_changed_stop(struct rq *rq, struct task_struct *p, int oldprio)
{
        BUG(); /* how!?, what priority? */
}

stop 태스크 자체가 최고 높은 우선 순위의 태스크로 별도로 수치를 변경할 수 없다.

 

get_rr_interval_stop()

kernel/sched/stop_task.c

static unsigned int
get_rr_interval_stop(struct rq *rq, struct task_struct *task)
{
        return 0;
}

stop 태스크가 스스로 yield하기 전까지 계속 수행되어야 하므로 stop 스케줄러는 인터벌을 사용하지 않는다.

 

put_prev_task_stop()

kernel/sched/stop_task.c

static void put_prev_task_stop(struct rq *rq, struct task_struct *prev)
{
        struct task_struct *curr = rq->curr;
        u64 delta_exec;

        delta_exec = rq_clock_task(rq) - curr->se.exec_start;
        if (unlikely((s64)delta_exec < 0))
                delta_exec = 0;

        schedstat_set(curr->se.statistics.exec_max,
                        max(curr->se.statistics.exec_max, delta_exec));

        curr->se.sum_exec_runtime += delta_exec;
        account_group_exec_runtime(curr, delta_exec);

        curr->se.exec_start = rq_clock_task(rq);
        cpuacct_charge(curr, delta_exec);
}

이전 stop 태스크의 사용이 완료되었으므로 관련 실행 시각을 갱신한다.

  • 코드 라인 6~8에서 stop 태스크가 실행한 delta 시간을 얻어온다.
  • 코드 라인 13에서 stop 태스크의 총 실행 시간을 갱신한다.
  • 코드 라인 14에서 스레드그룹의 총 실행시간을 갱신한다.
  • 코드 라인 16에서 stop 태스크의 시작 실행 시각을 다시 현재 시각으로 설정한다.
  • 코드 라인 17에서 stop 태스크의 cpu accounting 그룹용 총 실행 시간을 갱신한다.

 

 

Stop-task 스케줄러 OPS

kernel/sched/stop_task.c

/*
 * Simple, special scheduling class for the per-CPU stop tasks:
 */
const struct sched_class stop_sched_class = {
        .next                   = &dl_sched_class,

        .enqueue_task           = enqueue_task_stop,
        .dequeue_task           = dequeue_task_stop,
        .yield_task             = yield_task_stop,

        .check_preempt_curr     = check_preempt_curr_stop,

        .pick_next_task         = pick_next_task_stop,
        .put_prev_task          = put_prev_task_stop,

#ifdef CONFIG_SMP
        .select_task_rq         = select_task_rq_stop,
#endif

        .set_curr_task          = set_curr_task_stop,
        .task_tick              = task_tick_stop,

        .get_rr_interval        = get_rr_interval_stop,

        .prio_changed           = prio_changed_stop,
        .switched_to            = switched_to_stop,
        .update_curr            = update_curr_stop,
};

 

참고

 

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.