Linux 内核实时调度类 ⑤ ( 实时调度类 rt_sched_class 源码分析 | 结构体字段及函数指针分析 )

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux 内核实时调度类 ⑤ ( 实时调度类 rt_sched_class 源码分析 | 结构体字段及函数指针分析 )相关的知识,希望对你有一定的参考价值。

文章目录





一、rt_sched_class 结构体变量类型 sched_class



【Linux 内核】实时调度类 ③ ( 实时调度类 rt_sched_class 源码 | 调度类 sched_class 源码 ) 博客中 , 简单介绍了 实时调度类 rt_sched_class 结构体 , 下面开始分析该结构体的具体字段含义 ,

rt_sched_class 结构体 在 Linux 内核源码的 linux-5.6.18\\kernel\\sched\\rt.c 源文件中定义 ;

const struct sched_class rt_sched_class = 
	.next			= &fair_sched_class,
	.enqueue_task		= enqueue_task_rt,
	.dequeue_task		= dequeue_task_rt,
	.yield_task		= yield_task_rt,

	.check_preempt_curr	= check_preempt_curr_rt,

	.pick_next_task		= pick_next_task_rt,
	.put_prev_task		= put_prev_task_rt,
	.set_next_task          = set_next_task_rt,

#ifdef CONFIG_SMP
	.balance		= balance_rt,
	.select_task_rq		= select_task_rq_rt,
	.set_cpus_allowed       = set_cpus_allowed_common,
	.rq_online              = rq_online_rt,
	.rq_offline             = rq_offline_rt,
	.task_woken		= task_woken_rt,
	.switched_from		= switched_from_rt,
#endif

	.task_tick		= task_tick_rt,

	.get_rr_interval	= get_rr_interval_rt,

	.prio_changed		= prio_changed_rt,
	.switched_to		= switched_to_rt,

	.update_curr		= update_curr_rt,

#ifdef CONFIG_UCLAMP_TASK
	.uclamp_enabled		= 1,
#endif
;


rt_sched_class 结构体变量 是 sched_class 结构体类型的 , 这是 调度类 类型 , 该结构体的 字段 和 函数指针 含义在

博客中 , 有详细的介绍 ;





二、next 字段值



Linux 系统中的 " 调度类 " 链表中 , 下一个 " 调度类 " 指针 , 指向一个 公平调度类 地址 ;

.next			= &fair_sched_class,

参考资料 : 【Linux 内核】调度器 ③ ( sched_class 调度类结构体分析 | next 字段 | enqueue_task 函数 | dequeue_task 函数 )

整个 Linux 系统中有 多个 " 调度类 " , 按照 优先级进行排序 , 这些 " 调度类 " 放在一个 " 链表 " 中 , 优先级高的 " 调度类 " 先执行 , 优先级低的后执行 ;

sched_class 调度类结构体 中的 next 字段 , 就是指向 " 调度类 " 链表 中的 下一个 " 调度类 " ; ( 优先级低于本调度类 )

const struct sched_class *next;

源码路径 : linux-5.6.18\\kernel\\sched\\sched.h#1709 ;





三、enqueue_task 函数指针值



将一个 task 任务 enqueue_task_rt , 存放到 " 执行队列 " ( 红黑树 ) " 尾部 " ( 最右侧 ) ;

.enqueue_task		= enqueue_task_rt,

enqueue_task_rt 函数如下 :

static void
enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags)

	struct sched_rt_entity *rt_se = &p->rt;

	if (flags & ENQUEUE_WAKEUP)
		rt_se->timeout = 0;

	enqueue_rt_entity(rt_se, flags);

	if (!task_current(rq, p) && p->nr_cpus_allowed > 1)
		enqueue_pushable_task(rq, p);


参考资料 : 【Linux 内核】调度器 ③ ( sched_class 调度类结构体分析 | next 字段 | enqueue_task 函数 | dequeue_task 函数 )

sched_class 调度类结构体 中的 enqueue_task 函数指针 , 指向一个函数 , 调用该函数 , 可以将 " 进程 " 加入到 " 执行队列 " 中 , 同时 nr_running 自增 1 1 1 ;

  • 进程 是一个 调度实体 ;
  • 执行队列 是一个 红黑树 ;
void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);

源码路径 : linux-5.6.18\\kernel\\sched\\sched.h#1715 ;





四、dequeue_task 函数指针值



将一个 task 任务 dequeue_task_rt , 从 " 执行队列 " ( 红黑树 ) " 尾部 " ( 最右侧 ) 移除 ;

.dequeue_task		= dequeue_task_rt,

dequeue_task_rt 函数如下 :

static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags)

	struct sched_rt_entity *rt_se = &p->rt;

	update_curr_rt(rq);
	dequeue_rt_entity(rt_se, flags);

	dequeue_pushable_task(rq, p);



参考资料 : 【Linux 内核】调度器 ③ ( sched_class 调度类结构体分析 | next 字段 | enqueue_task 函数 | dequeue_task 函数 )

dequeue_task 调度类结构体 中的 dequeue_task 函数指针 , 指向一个函数 , 调用该函数 , 可以 从 " 执行队列 " 中删除 " 进程 " , 同时 nr_running 自减 1 1 1 ;

  • 进程 是一个 调度实体 ;
  • 执行队列 是一个 红黑树 ;
void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);

源码路径 : linux-5.6.18\\kernel\\sched\\sched.h#1716 ;





五、yield_task 函数指针值



调用该 yield_task_rt 函数指针 指向的 函数 , 主动放弃执行 ;

.yield_task		= yield_task_rt,

yield_task_rt 函数如下 :

static void yield_task_rt(struct rq *rq)

	requeue_task_rt(rq, rq->curr, 0);


参考资料 : 【Linux 内核】调度器 ④ ( sched_class 调度类结构体分析 | yield_task 函数 | heck_preempt_curr 函数 | task_struct 函数 )

sched_class 调度类结构体 中的 yield_task 函数指针 , 指向一个函数 , 调用该函数 , 该 " 进程 "放弃 已分配的 CPU 时间片执行权限 , 先将进程从 " 执行队列 " 中出队 , 然后再 放入到队列末尾 ;

  • 进程 是一个 调度实体 ;
  • 执行队列 是一个 红黑树 ;

也就是说 调用该函数 , 将 调度实体 ( 进程 ) 存放到了 红黑树 ( 执行队列 )最右端 ( 末尾 ) ;

void (*yield_task)   (struct rq *rq);

源码路径 : linux-5.6.18\\kernel\\sched\\sched.h#1717 ;





六、pick_next_task_rt 函数



调用 pick_next_task_rt 函数 , 选择 " 执行队列 " ( 红黑树 ) 中将要被调度的任务 ;

	.pick_next_task		= pick_next_task_rt,

pick_next_task_rt 函数如下 :

static struct task_struct *pick_next_task_rt(struct rq *rq)

	struct task_struct *p;

	if (!sched_rt_runnable(rq))
		return NULL;

	p = _pick_next_task_rt(rq);
	set_next_task_rt(rq, p, true);
	return p;





七、pick_next_task_rt 函数



调用 put_prev_task_rt 函数 , 选择 " 执行队列 " ( 红黑树 ) 中将要被调度出执行的任务 , 其返回值是将要被调度的任务 ;

	.put_prev_task		= put_prev_task_rt,

put_prev_task_rt 函数如下 :

static void put_prev_task_rt(struct rq *rq, struct task_struct *p)

	update_curr_rt(rq);

	update_rt_rq_load_avg(rq_clock_pelt(rq), rq, 1);

	/*
	 * The previous task needs to be made eligible for pushing
	 * if it is still active
	 */
	if (on_rt_rq(&p->rt) && p->nr_cpus_allowed > 1)
		enqueue_pushable_task(rq, p);

以上是关于Linux 内核实时调度类 ⑤ ( 实时调度类 rt_sched_class 源码分析 | 结构体字段及函数指针分析 )的主要内容,如果未能解决你的问题,请参考以下文章

Linux 内核实时调度类 ① ( 进程分类 | 实时进程普通进程 | Linux 内核 SCHED_FIFOSCHED_RR 调度策略 | 实时调度实体 sched_rt_entity )

Linux 内核实时调度类 ⑦ ( 实时调度类核心函数源码分析 | dequeue_task_rt 函数 | 从执行队列中移除进程 )

Linux 内核调度器 ⑦ ( 调度器类型 | 停机调度类 stop_sched_class | 限期调度类 dl_sched_class | 实时调度类 | 公平调度类 | 空闲调度类 )

Linux 内核实时调度类 ② ( 实时调度实体 sched_rt_entity 源码分析 | run_listtimeoutwatchdog_stamptime_slice 字段 )

Linux 内核实时调度类 ④ ( 实时运行队列 rt_rq 源码分析 | 实时运行队列 rt_rq 结构体字段分析 | activert_nr_runningcurrnext 字段 )

实时调度类