代码分析根据3.10版本

通过对前面的学习我们知道Linux的调度分为两种

周期调度 完成周期性算法参数的更新和系统其它实际的检查

主调的 真正的调度过程

我们现在来看下主调的的代码框架。

入口

根《调度发生的情况》的学习,我们知道所有的调度最后都会到 schedule 函数中。因此我们就先从schedule函数入手。

asmlinkage void __sched schedule(void)

{

struct task_struct *tsk = current;

sched_submit_work(tsk);//获取当前current 并且加锁。

__schedule();

}

schedule 函数并没有太多的操作,只是获取当前task,然后加锁,最后都交给了**__schedule()**函数。

主要框架

主要函数__schedule分析

static void __sched __schedule(void)

{

struct task_struct *prev, *next;

unsigned long *switch_count;

struct rq *rq;

int cpu;

need_resched:

preempt_disable();

cpu = smp_processor_id();

rq = cpu_rq(cpu);//找到当前cpu拿取队列

prev = rq->curr;//保持此时此刻的任务

.....

pre_schedule(rq, prev);//做一些预处理

....

put_prev_task(rq, prev);

next = pick_next_task(rq);//选取下一个进程

clear_tsk_need_resched(prev);

rq->skip_clock_update = 0;

if (likely(prev != next)) {//选好了,

rq->nr_switches++;

rq->curr = next;

++*switch_count;//计数加一

...

context_switch(rq, prev, next); /* unlocks the rq */真正的切换堆栈帧

...

cpu = smp_processor_id();

rq = cpu_rq(cpu);

} else

raw_spin_unlock_irq(&rq->lock);

....

if (need_resched())//是否需要重新调度

goto need_resched;

}

其实**__schedule**还是比较长的,但是我们这里选择了一些主要的流程分析,流程如下:

1、拿到当前cpu的队列rq

2、进行一些与操作处理

3、选取下一个进程

4、堆栈帧context_switch 切换

5、是否需要重新调度

关于重新调度,设计到一些内核抢占的知识,我们暂时不分析。而context_switch,是硬件堆栈的切换,我们后文会认真分析这个函数,在这个过程中我们主要关注如何选取下一个进程。

如何选取下一个任务 pick_next_task 函数分析

static inline struct task_struct * pick_next_task(struct rq *rq)

{

const struct sched_class *class;

struct task_struct *p;

/*

* Optimization: we know that if all tasks are in

* the fair class we can call that function directly:

*/

if (likely(rq->nr_running == rq->cfs.h_nr_running)) {检查当前cpu队列中是否所有的都是cfs,如果是就直接掉用cfs的调度类

p = fair_sched_class.pick_next_task(rq);

if (likely(p))

return p;

}

for_each_class(class) {循环遍历每一个调度类

p = class->pick_next_task(rq);

if (p)

return p;

}

}

pick_next_task 还是比较简单的只是有两部, 1、查看当前cpu队列是否所有的都是cfs 2、遍历所有调度类。 对于是不是全部cfs的检查是有必要的,会减少开销。我们再来看下遍历

#define sched_class_highest (&stop_sched_class)

#define for_each_class(class) \

for (class = sched_class_highest; class; class = class->next)

extern const struct sched_class stop_sched_class;

extern const struct sched_class rt_sched_class;

extern const struct sched_class fair_sched_class;

extern const struct sched_class idle_sched_class;

我们看到是从stop_sched_class开始,

const struct sched_class stop_sched_class = {

.next= &rt_sched_class,

....

}

const struct sched_class rt_sched_class = {

.next= &fair_sched_class,

....

}

const struct sched_class fair_sched_class = {

.next= &idle_sched_class,

....

}

const struct sched_class idle_sched_class = {

/* .next is NULL */

....

}

可以看到是这么个列表。

stop_sched_class --》rt_sched_class--》fair_sched_class--》idle_sched_class--》NULL

以cfs为例看看如何选取task

static struct task_struct *pick_next_task_fair(struct rq *rq)

{

struct task_struct *p;

struct cfs_rq *cfs_rq = &rq->cfs;

struct sched_entity *se;

if (!cfs_rq->nr_running)

return NULL;

do {

se = pick_next_entity(cfs_rq);

set_next_entity(cfs_rq, se);

cfs_rq = group_cfs_rq(se);

} while (cfs_rq);

p = task_of(se);

if (hrtick_enabled(rq))

hrtick_start_fair(rq, p);

return p;

}

这部分代码也是组调度流程的基础,现在看起来是比较简单的,但是接下来分析组调度的时候就会详细的展开分析。 我们看这个简单的过程:

全局的rq 拿到cfs_rq

cfs_rq 通过pick_next_entity 拿到算法算好的调度类entity----se。

进行组调度----目前先忽略

将se 转换成task 这样就结束了主调的的所有过程。

linux 进程调度源码分析,Linux调度器源码分析相关推荐

  1. xxl-job源码解读:调度器schedule

    xxl-job源码解读:调度器schedule 本文基于xxl-job的2.3.1版本 基本说明 基本原理概述 调用器主要的用于判断定时任务的执行时间,按时调用触发器(trigger),再由触发器去获 ...

  2. go语言调度器源代码情景分析之五:汇编指令

    本文是<go调度器源代码情景分析>系列 第一章 预备知识的第4小节. 汇编语言是每位后端程序员都应该掌握的一门语言,因为学会了汇编语言,不管是对我们调试程序还是研究与理解计算机底层的一些运 ...

  3. Linux进程里运行新代码,linux调度器源码分析 - 新进程加入(三)

    中专门描述了copy_process()这个创建函数,而里面有一个函数专门用于进程调度的初始化,就是sched_fork(),其代码如下 int sched_fork(unsigned long cl ...

  4. golang源码分析:调度器chan调度

    golang调度机制chan调度 golang的调度策略中,碰见阻塞chan就会将该chan放入到阻塞的g中,然后再等待该chan被唤醒,这是golang调度器策略的主动调度策略之一,其中还有其他的主 ...

  5. linux 音频播放器源码,Android音乐播放器源码

    相当完整的Android音乐播放器,直接上效果图及源代码,自己欣赏,具体不再解释了,可以说是一个很给力的Android音乐播放器. 示例代码: /* * Copyright (C) 2009 Tele ...

  6. Kubernetes调度器源码学习(三):Preempt抢占机制、调度失败与重试处理

    本文基于Kubernetes v1.22.4版本进行源码学习 5.Preempt抢占机制 当高优先级的Pod没有找到合适的节点时,调度器会尝试抢占低优先级的Pod的节点.抢占过程是将低优先级的Pod从 ...

  7. linux进程调度采取的是,Linux进程调度

    进程状态 进程调度就是让进程从一种状态切换到另一种状态.Linux中进程的主要状态如下, 值 状态 缩写 含义 0 TASK_RUNNING R 正在运行或可运行 1 TASK_INTERRUPTIB ...

  8. android+小米文件管理器源码,小米开源文件管理器MiCodeFileExplorer-源码研究(2)-2个单实例工具类...

    从本篇开始,讲解net.micode.fileexplorer.util工具包中的类. 这个包下的类,功能也比较单一和独立.很多代码的思想和实现,可以用于JavaWeb和Android等多种环境中. ...

  9. arm linux 进程调度,详解ARM Linux 2.4.x进程调度

    Linux2.4.x是一个基于非抢占式的多任务的分时操作系统,虽然在用户进程的调度上采用抢占式策略,但是而在内核还是采用了轮转的方法,如果有个内核态的线程恶性占有CPU不释放,那系统无法从中解脱出来, ...

  10. linux 进程调度ppt,第章 Linux进程调度.ppt

    第章 Linux进程调度 * * SCHED_FIFO 与 SCHED_RR 的区别是: 当进程的调度策略为前者时,当前实时进程将一直占用 CPU 直至自动退出,除非有更紧迫的. 优先级更高的实时进程 ...

最新文章

  1. 太拼了:谷歌第一编程语言小白也能学会!
  2. ASA用ASDM管理时报unable to launch device manager xxx.xxx.xxx.xxx
  3. c++中的输入输出方法
  4. JavaScript从内容中筛选出手机号码集合
  5. 由动态分配和静态分配的数据在内存组成区别
  6. 第三次学JAVA再学不好就吃翔(part64)--自动装箱和自动拆箱
  7. python采用强制缩进if_Python缩进和选择解析
  8. tiny4412u-boot烧写及根文件系统制作(不进入终端问题)
  9. 高强度的加密软件怎么制作
  10. 一篇关于Dataset与泛型、自定义集合的讨论
  11. 祝愿父亲节里的父亲们快乐!
  12. 《经济学原理》——读书笔记(一)
  13. CORBA Programming with TAO - 3.IDL Data Type(数据类型与Mapping)例子常见问题篇
  14. excel文档中了宏病毒--
  15. Qt 3D 官方实例1 simple-qml
  16. Serenity框架官方文档翻译3.2(多租户)
  17. Apache Kudu 1.15.0的分布式集群部署
  18. SAP系统接口对接历险记
  19. 期望风险最小化、经验风险最小化、结构风险最小化
  20. Python(大蟒蛇)与云计算

热门文章

  1. 60+ 安全厂商的选择,为何 TA 一直坚持做威胁情报供应商?
  2. 云原生全景图之六 | 托管 Kubernetes 和 PaaS 解决什么问题
  3. java http 1.1_java11新特性HttpClient
  4. linux dd 重装系统,发现用dd装系统真是简单快捷通用
  5. amd核芯显卡控制面板自定义分辨率_主流显卡的一位猛将:蓝宝石Radeon RX 5500XT显卡首测...
  6. linux磁盘配额edquota,Linux磁盘配额(Quota)
  7. spring5.x cxf3.4.x 服务端和客户端 非maven版本
  8. Error starting userland proxy: listen tcp 0.0.0.0:8080: bind: address already in use.
  9. Sublime Text 3 快捷键总结(详细版本)
  10. mysql 插入数据时 自动设置创建时间和更新时间