Linux 调度流程分析(1) 之切换调度类

Linux 调度流程分析(1)

切换调度类

用户可以通过 int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param) 函数来更改一个任务的调度类。

这个函数实际是通过系统调用 sched_setscheduler() 系统调用来实现的。该系统调用在 kernel/sched/core.c 中定义,系统调用原型为:

SYSCALL_DEFINE3(sched_setscheduler,  pid_t, pid, int, policy, struct sched_param __user*, param)

该系统调用其实是对 int do_sched_setscheduler() 函数的封装。在这个函数中,系统首先找到 pid 对应的任务再通过 _sched_setscheduler() 函数将用户识别的 struct sched_param 参数转化成 struct sched_attr 格式送给 __sched_setscheduler() 去实际处理。

这几个函数的调用关系如下:

sched_setscheduler()
    ===> SYSCALL_DEFINE3(sched_setscheduler,  pid_t, pid, int, policy, struct sched_param __user*, param)
    	===> do_sched_setscheduler()
    		===> sched_setscheduler()
    			===> _sched_setscheduler()
    				===> __sched_setscheduler()

int __sched_setscheduler(struct task_struct *p, const struct sched_attr * attr, bool user, bool pi) 函数是真正去更改任务调度的实现。

  1. 在这个函数中,会首先对参数进行检查:
  • 检查新策略的有效性;
  • 检查传入的标志位是否合法;
  • 检查优先级是否超限;
  • 检查新调度策略与新优先级是否匹配:
    • 优先级 1-99 属于 rt 调度类;
    • 优先级 0 代表 cfs 调度类;
    • 优先级 -1 代表 dl 调度类;
  • 普通用户权限检查:
    • 不允许设置 schedutil kworker 的参数;
    • 通过 security_task_setscheduler() 函数检查是否允许更改任务的调度策略;
    • 如果不具有 CAP_SYS_NICE 权限,还要有以下约束:
      • 对于 cfs 调度类,只能降低 nice 值;
      • 不能更改 rt 调度类的策略,且优先级不能超限
      • 不能更改为 dl 调度策略;
      • 对于 idle 调度策略的 cfs 调度类进程,可以将其提升为 normal 调度策略的进程;
      • 普通进程只能修改与自己具有相同所有者的进程的调度策略;
      • 普通进程无法修改 sched_reset_on_fork 的标志;
  1. 其次会对该任务所在的运行队列进行时间统计;

  2. 如果要更改到 rt/dl 调度类,则需要检查带宽设定是否正确,或者是否有足够的带宽来让其正常工作;

  3. 在设定优先级之前,需要先检查优先级翻转可能带来的问题,从而保证优先级设定之后不会带来优先级翻转的问题;

  4. 如果该任务在运行队列上,则需要调用切换之前的调度类的 dequeue() 函数先将该任务出队;

  5. 如果该任务正在运行中,即是当前任务,则需要调用切换之前的调度类的 put_prev_task() 函数,在任务切换调度类之前做一些处理工作,例如统计时间信息等;

  6. 通过__setscheduler_params() & __setscheduler_prio() 函数进行调度类、调度策略和优先级的设定,此时任务已经从前一个调度类切换到了一个新的调度类上;

  7. 设定任务的 uclamp 限制;

  8. 更改调度类后,任务的状态要和切换之前保持一直:

    • 原来在运行队列上,切换后要通过新调度类的 enqueue() 函数将其入队;
    • 如果原来在运行中,则切换后要通过新调度类的 set_next_task() 函数将其设定成新调度类运行队列上的当前任务;
  9. 如果调度类改变,则通过调用前一个调度类的 switched_from() 函数和新调度类的 switched_to() 函数来通知前一个调度类和后一个调度类做一些处理工作,例如抢占等;

  10. 如果没有更改调度类,只是更改了优先级,则通过调度类的 prio_change() 函数通知调度类;

  11. 最后进行一次负载均衡;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值