介绍
内核中针对task_struct进程描述符专门安排有序执行的模块叫调度器 调度器作用: 1 cpu中央处理器专门管理时间 2 通过进程优先级为依据专门分配时间 当在运行的过程中,某个进程的时间片到了或者缺少某个条件就会发生上下文切换,cpu重新切换一个进程。
调度类
1 调度类结构体sched_class: 内核中提供了一个专门用来调度的进程的类接口sched_class 在内核中,系统中有多个调度类,按调度优先级连接成链表。 kernel/sched/sched.h文件中
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);
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);
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);
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);
#endif
};
常用的接口: enqueue_task:向就绪队列加一个进程,实体添加到红黑树,ns_running++ dequeue_task:将一个进程从就绪队列删除,当某个任务退出可运行状态调用该函数它将从红黑树去掉对应调度实体。 yield_task:在进程想要资源放弃对处理器控制权调用,在sched_yield系统调用,会调用内核api去操作。 check_preempt_curr:抢占式系统才会用到,检查当前运行任务是否被抢占。 pick_next_task:选择下一个要运行的任务 put_prev_task: 将进程放回运行队列中
2 具体调度类: 内核中提供了5种调度类分别是 dl_sched_class: deadline调度类 rt_sched_class:实时调度类 针对实时进程 fair_sched_class:公平调度类 针对普通进程 idle_sched_class:空闲调度类 针对空闲进程 stop_sched_class: 停机调度类 针对停机进程
3: 调度类的组织形式 每个cpu第一个pid=0线程,swapper是一个静态线程,调度类属于idle_sched_class linux调度的核心:选择一个合适的task运行,会按照优先级顺序遍历调度类 pick_next_task函数
调度实体
在内核进程描述task_struct中有几个成员变量是与调度相关的
......
int prio, static_prio, normal_prio;
unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
#ifdef CONFIG_CGROUP_SCHED
struct task_group *sched_task_group;
#endif
struct sched_dl_entity dl;
......
进程根据自己是实时的,还是普通的类型,通过这个成员变量,将自己挂在某一个数据结构里面,和其他的进程排序,等待被调度。如果这个进程是个普通进程,则通过 sched_entity,将自己挂在这棵红黑树上
调度策略
linux内核调度策略源码:/include/uapi/linux/sched.h。 提供了6种调度策略。
#define SCHED_NORMAL 0
#define SCHED_FIFO 1
#define SCHED_RR 2
#define SCHED_BATCH 3
#define SCHED_IDLE 5
#define SCHED_DEADLINE 6
总结
读了这么多代码以及过不好这一生,直接上图,一图胜千言
|