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

2023-03-30 14:01:34 浏览数 (1)

文章目录

  • 一、rt_sched_class 结构体变量类型 sched_class
  • 二、next 字段值
  • 三、enqueue_task 函数指针值
  • 四、dequeue_task 函数指针值
  • 五、yield_task 函数指针值
  • 六、pick_next_task_rt 函数
  • 七、pick_next_task_rt 函数

一、rt_sched_class 结构体变量类型 sched_class


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

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

代码语言:javascript复制
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 结构体类型的 , 这是 调度类 类型 , 该结构体的 字段 和 函数指针 含义在

  • 【Linux 内核】调度器 ② ( sched_class 调度类结构体源码 | 源码路径 linux-5.6.18kernelschedsched.h )
  • 【Linux 内核】调度器 ③ ( sched_class 调度类结构体分析 | next 字段 | enqueue_task 函数 | dequeue_task 函数 )
  • 【Linux 内核】调度器 ④ ( sched_class 调度类结构体分析 | yield_task 函数 | heck_preempt_curr 函数 | task_struct 函数 )
  • 【Linux 内核】调度器 ⑤ ( put_prev_task、set_next_task 函数 | select_task_rq 函数 | migrate_task_rq 函数 )
  • 【Linux 内核】调度器 ⑥ ( task_woken 函数 | set_cpus_allowed 函数 | rq_online 函数 | rq_offline 函数 )

博客中 , 有详细的介绍 ;

二、next 字段值


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

代码语言:javascript复制
.next			= &fair_sched_class,

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

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

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

代码语言:javascript复制
const struct sched_class *next;

源码路径 : linux-5.6.18kernelschedsched.h#1709 ;

三、enqueue_task 函数指针值


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

代码语言:javascript复制
.enqueue_task		= enqueue_task_rt,

enqueue_task_rt 函数如下 :

代码语言:javascript复制
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

;

  • 进程 是一个 调度实体 ;
  • 执行队列 是一个 红黑树 ;
代码语言:javascript复制
void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);

源码路径 : linux-5.6.18kernelschedsched.h#1715 ;

四、dequeue_task 函数指针值


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

代码语言:javascript复制
.dequeue_task		= dequeue_task_rt,

dequeue_task_rt 函数如下 :

代码语言:javascript复制
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

;

  • 进程 是一个 调度实体 ;
  • 执行队列 是一个 红黑树 ;
代码语言:javascript复制
void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);

源码路径 : linux-5.6.18kernelschedsched.h#1716 ;

五、yield_task 函数指针值


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

代码语言:javascript复制
.yield_task		= yield_task_rt,

yield_task_rt 函数如下 :

代码语言:javascript复制
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 时间片 的 执行权限 , 先将进程从 " 执行队列 " 中出队 , 然后再 放入到队列末尾 ;

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

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

代码语言:javascript复制
void (*yield_task)   (struct rq *rq);

源码路径 : linux-5.6.18kernelschedsched.h#1717 ;

六、pick_next_task_rt 函数


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

代码语言:javascript复制
	.pick_next_task		= pick_next_task_rt,

pick_next_task_rt 函数如下 :

代码语言:javascript复制
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 函数 , 选择 " 执行队列 " ( 红黑树 ) 中将要被调度出执行的任务 , 其返回值是将要被调度的任务 ;

代码语言:javascript复制
	.put_prev_task		= put_prev_task_rt,

put_prev_task_rt 函数如下 :

代码语言:javascript复制
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);
}

0 人点赞