调度器概述

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/rikeyone/article/details/87783365

调度类

现代版本的内核中,比如笔者使用的Linux 4.0,已经去除了O(N)和O(1)调度器的实现。默认实现了另外更新的4种调度器:deadline,realtime,idle和CFS。内核使用struct sched_class来描述一个调度类,也就是一个调度器。
这几个调度类在内核中的定义如下:

rt_sched_class --------- realtime调度器
fair_sched_class -------- CFS调度器
idle_sched_class -------- idle调度器
dl_sched_class ---------- deadline调度器

调度策略:

内核中定义了6中类型的调度策略,用户空间的进程可以通过系统调用设置对应进程的调度策略sched_setscheduler()。内核中的定义如下:

 /*
  * Scheduling policies
  */
 #define SCHED_NORMAL        0
 #define SCHED_FIFO      1
 #define SCHED_RR        2
 #define SCHED_BATCH     3
 /* SCHED_ISO: reserved but not implemented yet */
 #define SCHED_IDLE      5
 #define SCHED_DEADLINE      6

不同的调度策略使用的调度器是不同的,对应关系如下:

调度策略 调度类(调度器)
SCHED_NORMAL/SCHED_BATCH CFS调度器
SCHED_FIFO/SCHED_RR RT调度器
SCHED_IDLE idle调度器
SCHED_DEADLINE deadline调度器

调度框架

内核实现了一套调度框架代码,把调度器类型以一个数据结构来描述,也就是上文提到过的struct sched_class,其核心目的就是为了抽象不同类型的调度器,这样同一套代码可以方便的支持不同类型的调度器,而保持对上的接口不变。
我们看下调度类定义:

struct sched_class {
    const struct sched_class *next;

    void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
    void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
    void (*yield_task) (struct rq *rq);
    bool (*yield_to_task) (struct rq *rq, struct task_struct *p, bool preempt);

    void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags);

    /*
     * It is the responsibility of the pick_next_task() method that will
     * return the next task to call put_prev_task() on the @prev task or
     * something equivalent.
     *
     * May return RETRY_TASK when it finds a higher prio class has runnable
     * tasks.
     */
    struct task_struct * (*pick_next_task) (struct rq *rq,
                        struct task_struct *prev);
    void (*put_prev_task) (struct rq *rq, struct task_struct *p);

#ifdef CONFIG_SMP
    int  (*select_task_rq)(struct task_struct *p, int task_cpu, int sd_flag, int flags);
    void (*migrate_task_rq)(struct task_struct *p, int next_cpu);

    void (*post_schedule) (struct rq *this_rq);
    void (*task_waking) (struct task_struct *task);
    void (*task_woken) (struct rq *this_rq, struct task_struct *task);

    void (*set_cpus_allowed)(struct task_struct *p,
                 const struct cpumask *newmask);

    void (*rq_online)(struct rq *rq);
    void (*rq_offline)(struct rq *rq);
#endif

    void (*set_curr_task) (struct rq *rq);
    void (*task_tick) (struct rq *rq, struct task_struct *p, int queued);
    void (*task_fork) (struct task_struct *p);
    void (*task_dead) (struct task_struct *p);

    /*
     * The switched_from() call is allowed to drop rq->lock, therefore we
     * cannot assume the switched_from/switched_to pair is serliazed by
     * rq->lock. They are however serialized by p->pi_lock.
     */
    void (*switched_from) (struct rq *this_rq, struct task_struct *task);
    void (*switched_to) (struct rq *this_rq, struct task_struct *task);
    void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
                 int oldprio);
 
     unsigned int (*get_rr_interval) (struct rq *rq,
                      struct task_struct *task);
 
     void (*update_curr) (struct rq *rq);
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
     void (*task_move_group) (struct task_struct *p, int on_rq);
 #endif
};

不同类型的调度器通过next指针链接在一起,他们的连接方式如下:

stop_sched_class-->dl_sched_class-->rt_sched_class-->fair_sched_class-->idle_sched_class-->NULL

猜你喜欢

转载自blog.csdn.net/rikeyone/article/details/87783365
今日推荐