Idle-task Scheduler
어떠한 스케줄러보다 우선 순위가 낮아 다른 스케줄러에서 태스크가 동작해야 하는 상황이되면 언제나 preemption 된다. idle 태스크는 core 마다 1개씩 지정되어 있어 다른 cpu로의 migration이 필요 없다.
- 각 core의 부트업 처리가 완료되면 cpu_startup_entry() 함수를 호출하여 idle 태스크로의 역할을 수행한다.
- 부트업 프로세스가 사용하는 메모리 환경을 그대로 사용한다. (init_mm 공유)
- 참고: cpu_startup_entry() | 문c
select_task_rq_idle()
kernel/sched/idle_task.c
select_task_rq_idle(struct task_struct *p, int cpu, int sd_flag, int flags) { return task_cpu(p); /* IDLE tasks as never migrated */ }
migration을 허용하지 않는다.
check_preempt_curr_idle()
kernel/sched/idle_task.c
/* * Idle tasks are unconditionally rescheduled: */ static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int flags) { resched_curr(rq); }
항상 preemption 한다.
dequeue_task_idle()
kernel/sched/idle_task.c
/* * It is not legal to sleep in the idle task - print a warning * message if some code attempts to do it: */ static void dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags) { raw_spin_unlock_irq(&rq->lock); printk(KERN_ERR "bad: scheduling from the idle thread!\n"); dump_stack(); raw_spin_lock_irq(&rq->lock); }
idle 태스크는 엔큐 및 디큐 개념이 없다. 따라서 호출되는 경우 경고 메시지를 출력한다.
task_tick_idle()
kernel/sched/idle_task.c
static void task_tick_idle(struct rq *rq, struct task_struct *curr, int queued) { }
task 틱마다 아무런 동작도 하지 않는다.
update_curr_idle()
kernel/sched/idle_task.c
static void update_curr_idle(struct rq *rq) { }
아무런 동작도 하지 않는다.
switched_to_idle()
kernel/sched/idle_task.c
static void switched_to_idle(struct rq *rq, struct task_struct *p) { BUG(); }
설계상 이 idle 태스크로의 스위칭은 불가능하다.
prio_changed_idle()
kernel/sched/idle_task.c
static void prio_changed_idle(struct rq *rq, struct task_struct *p, int oldprio) { BUG(); }
idle 태스크 자체가 가장 낮은 순위의 태스크로 별도로 우선 순위를 변경할 수 없다.
get_rr_interval_idle()
kernel/sched/idle_task.c
static unsigned int get_rr_interval_idle(struct rq *rq, struct task_struct *task) { return 0; }
idle 태스크는 preemption되지 않는 경우 계속 수행되어야 하므로 idle 스케줄러는 인터벌을 사용하지 않는다.
다음 idle 태스크 선택
pick_next_task_idle()
kernel/sched/idle_task.c
static struct task_struct * pick_next_task_idle(struct rq *rq, struct task_struct *prev) { put_prev_task(rq, prev); schedstat_inc(rq, sched_goidle); return rq->idle; }
기존 태스크에 대한 런타임 계산 등을 끝내고 idle 태스크를 반환한다.
put_prev_task_idle()
kernel/sched/idle_task.c
static void put_prev_task_idle(struct rq *rq, struct task_struct *prev) { idle_exit_fair(rq); rq_last_tick_reset(rq); }
idle 태스크의 실행 시각이 끝난 경우 이에 대한 처리를 수행한다.
- 코드 라인 3에서 런큐의 러너블 로드 평균을 갱신한다.
- 코드 라인 4에서 nohz full 을 허용한 시스템인 경우 last_sched_tick에 현재 시각(jiffies)를 기록한다.
Idle-task 스케줄러 OPS
kernel/sched/idle_task.c
/* * Simple, special scheduling class for the per-CPU idle tasks: */ const struct sched_class idle_sched_class = { /* .next is NULL */ /* no enqueue/yield_task for idle tasks */ /* dequeue is not valid, we print a debug message there: */ .dequeue_task = dequeue_task_idle, .check_preempt_curr = check_preempt_curr_idle, .pick_next_task = pick_next_task_idle, .put_prev_task = put_prev_task_idle, #ifdef CONFIG_SMP .select_task_rq = select_task_rq_idle, #endif .set_curr_task = set_curr_task_idle, .task_tick = task_tick_idle, .get_rr_interval = get_rr_interval_idle, .prio_changed = prio_changed_idle, .switched_to = switched_to_idle, .update_curr = update_curr_idle, };
참고
- Scheduler -1- (Basic) | 문c
- Scheduler -2- (Global Cpu Load) | 문c
- Scheduler -3- (PELT) | 문c
- Scheduler -4- (Group Scheduling) | 문c
- Scheduler -5- (Scheduler Core) | 문c
- Scheduler -6- (CFS Scheduler) | 문c
- Scheduler -7- (Preemption & Context Switch) | 문c
- Scheduler -8- (CFS Bandwidth) | 문c
- Scheduler -9- (RT Scheduler) | 문c
- Scheduler -10- (Deadline Scheduler) | 문c
- Scheduler -11- (Stop Scheduler) | 문c
- Scheduler -12- (Idle Scheduler) | 문c – 현재 글
- Scheduler -13- (Scheduling Domain 1) | 문c
- Scheduler -14- (Scheduling Domain 2) | 문c
- Scheduler -15- (Load Balance 1) | 문c
- Scheduler -16- (Load Balance 2) | 문c
- Scheduler -17- (Load Balance 3 NUMA) | 문c
- Scheduler -18- (Load Balance 4 EAS) | 문c
- Scheduler -19- (초기화) | 문c
- PID 관리 | 문c
- do_fork() | 문c
- cpu_startup_entry() | 문c
- 런큐 로드 평균(cpu_load[]) – v4.0 | 문c
- PELT(Per-Entity Load Tracking) – v4.0 | 문c