进程的切换和一般执行过程

知识总结

操作系统原理中介绍了大量进程调度算法,这些算法从实现的角度看仅仅是从运行队列中选择一个新进程,选择的过程中运用了不同的策略而已。

对于理解操作系统的工作机制,反而是进程的调度时机与进程的切换机制更为关键。​

1.不同类型的进程有不同需求的调度需求:

第一种分类:

—I/O-bound:频繁的进行I/O,通常会花费很多时间等待I/O操作的完成

—CPU-bound:计算密集型,需要大量的CPU时间进行运算

第二种分类:

—批处理进程:不必与用户交互,通常在后台运行;不必响应很快;

—实时进程:有实时需求,不被低优先级的进程阻塞;响应时间短,稳定;

—交互式进程:需要经常与用户交互;响应时间要快

2.进程调度的时机

中断处理过程(包括时钟中断、I/O中断、系统调用和异常)中,直接调用schedule(),或者返回用户态时根据need_resched标记调用schedule();

用户态进程只能被动调度。

内核线程可以直接调用schedule()进行进程切换,也可以在中断处理过程中进行调度,也就是说内核线程作为一类的特殊的进程可以主动调度,也可以被动调度;

内核线程是只有内核态没有用户态的特殊进程。内核线程可以主动调度,也可以被动调度。

用户态进程无法实现主动调度,仅能通过陷入内核态后的某个时机点进行调度,即在中断处理过程中进行调度。

schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换

next = pick_next_task(rq, prev);//进程调度算法都封装这个函数内部

context_switch(rq, prev, next);//进程上下文切换

switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

3.linux进程调度与进程切换

实验流程

如之前一样,克隆menu,然后重新编译内核,并启动gdb调试



内核启动



gdb调试



在schedule(),context_switch(),pick_next_task()打入断点



按c执行,停在schedule函数处



按c继续执行到pick_next_task断点处



按c继续执行到context_switch断点处,用来实现进程的切换。

代码分析

linux调度的核心函数为schedule,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);
rcu_note_context_switch(cpu);
prev = rq->curr; schedule_debug(prev); if (sched_feat(HRTICK))
hrtick_clear(rq); smp_mb__before_spinlock();
raw_spin_lock_irq(&rq->lock); switch_count = &prev->nivcsw;
if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
if (unlikely(signal_pending_state(prev->state, prev))) {
prev->state = TASK_RUNNING;
} else {
deactivate_task(rq, prev, DEQUEUE_SLEEP);
prev->on_rq = 0; if (prev->flags & PF_WQ_WORKER) {
struct task_struct *to_wakeup; to_wakeup = wq_worker_sleeping(prev, cpu);
if (to_wakeup)
try_to_wake_up_local(to_wakeup);
}
}
switch_count = &prev->nvcsw;
} if (task_on_rq_queued(prev) || rq->skip_clock_update < 0)
update_rq_clock(rq); next = pick_next_task(rq, prev);
clear_tsk_need_resched(prev);
clear_preempt_need_resched();
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); post_schedule(rq); sched_preempt_enable_no_resched();
if (need_resched())
goto need_resched;
} 当切换进程已经选好后,就开始用户虚拟空间的处理,然后就是进程的切换switch_to()。所谓进程的切换主要就是堆栈的切换,这是由宏操作switch_to()完成的。这里的输出部分有三个参数,表示这段程序执行后有三项数据会有改变。
asm volatile("pushfl\n\t"
"pushl %%ebp\n\t"
"movl %%esp,%[prev_sp]\n\t"
"movl %[next_sp],%%esp\n\t"
"movl $1f,%[prev_ip]\n\t"
"pushl %[next_ip]\n\t"
__switch_canary
"jmp __switch_to\n"
"1:\t"
"popl %%ebp\n\t"
"popfl\n" /* output parameters */
: [prev_sp] "=m" (prev->thread.sp),
[prev_ip] "=m" (prev->thread.ip),
"=a" (last), /* clobbered output registers: */
"=b" (ebx), "=c" (ecx), "=d" (edx),
"=S" (esi), "=D" (edi) __switch_canary_oparam /* input parameters: */
: [next_sp] "m" (next->thread.sp),
[next_ip] "m" (next->thread.ip), /* regparm parameters for __switch_to(): */
[prev] "a" (prev),
[next] "d" (next) __switch_canary_iparam : /* reloaded segment registers */
"memory");

总结

一次一般的进程切换过程,其中必须完成的关键操作是:切换地址空间、切换内核堆栈、切换内核控制流程,加上一些必要的寄存器保存和恢复。这里,除去地址空间的切换,其他操作要强调“内核”一词。这是因为,这些操作并非针对用户代码,切换完成后,也没有立即跑到next的用户空间中执行。用户上下文的保存和恢复是通过中断和异常机制,在内核态和用户态相互切换时才发生的。schedule()是内核和其他部分用于调用进程调度器的入口,选择哪个进程可以运行,何时将其投入运行。就如switch_to中的方法,通过压栈出栈交换prev_ip和next_ip。然后返回,从而完成进程调度。而用哪个作为下来的进程,则通过优先级的算法和进程调度算法来决定。

2019-2020-1 20199303《Linux内核原理与分析》第九周作业的更多相关文章

  1. 2019-2020-1 20199303<Linux内核原理与分析>第二周作业

    2019-2020-1 20199303第二周作业 1.汇编与寄存器的学习 寄存器是中央处理器内的组成部份.寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令.数据和位址.在中央处理器的控制部件中 ...

  2. 20169219 linux内核原理与分析第二周作业

    "linux内核分析"的第一讲主要讲了计算机的体系结构,和各寄存器之间对数据的处理过程. 通用寄存器 AX:累加器 BX:基地址寄存器 CX:计数寄存器 DX:数据寄存器 BP:堆 ...

  3. 2019-2020-1 20199314 <Linux内核原理与分析>第二周作业

    1.基础学习内容 1.1 冯诺依曼体系结构 计算机由控制器.运算器.存储器.输入设备.输出设备五部分组成. 1.1.1 冯诺依曼计算机特点 (1)采用存储程序方式,指令和数据不加区别混合存储在同一个存 ...

  4. Linux内核原理与分析-第一周作业

    本科期间,学校开设过linux相关的课程,当时的学习方式主要以课堂听授为主.虽然老师也提供了相关的学习教材跟参考材料,但是整体学下来感觉收获并不是太大,现在回想起来,主要还是由于自己课下没有及时动手实 ...

  5. 2019-2020-1 20199314 <Linux内核原理与分析>第一周作业

    前言 本周对实验楼的Linux基础入门进行了学习,目前学习到实验九完成到挑战二. 学习和实验内容 快速学习了Linux系统的发展历程及其简介,学习了下的变量.用户权限管理.文件打包及压缩.常用命令的和 ...

  6. Linux内核原理与分析-第二周作业

    写之前回看了一遍秒速五厘米:如果

  7. 2018-2019-1 20189221《Linux内核原理与分析》第一周作业

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  8. 2020-2021-1 20209307 《Linux内核原理与分析》第九周作业

    这个作业属于哪个课程 <2020-2021-1Linux内核原理与分析)> 这个作业要求在哪里 <2020-2021-1Linux内核原理与分析第九周作业> 这个作业的目标 & ...

  9. 2019-2020-1 20199329《Linux内核原理与分析》第十三周作业

    <Linux内核原理与分析>第十三周作业 一.本周内容概述 通过重现缓冲区溢出攻击来理解漏洞 二.本周学习内容 1.实验简介 注意:实验中命令在 xfce 终端中输入,前面有 $ 的内容为 ...

  10. 2019-2020-1 20199329《Linux内核原理与分析》第十二周作业

    <Linux内核原理与分析>第十二周作业 一.本周内容概述: 通过编程理解 Set-UID 的运行机制与安全问题 完成实验楼上的<SET-UID程序漏洞实验> 二.本周学习内容 ...

随机推荐

  1. WiX 自定义

    WiX 允许用户做一些自定义操作 用户界面向导 对于安装界面,用户可以用自己的位图.图标和许可证文本替换默认的.它们的路径存储在变量中,您可以在命令行或直接在源代码中指定这些变量: <WixVa ...

  2. NKOJ 【NOIP2015 Day2】运输计划

    时间限制 : 20000 MS   空间限制 : 262144 KB 评测说明 : 2s,256m 问题描述 公元 2044 年,人类进入了宇宙纪元. L 国有 n 个星球,还有 n−1 条双向航道, ...

  3. MATLAB实现一个EKF-2D-SLAM(已开源)

    1. SLAM问题定义 同时定位与建图(SLAM)的本质是一个估计问题,它要求移动机器人利用传感器信息实时地对外界环境结构进行估计,并且估算出自己在这个环境中的位置,Smith 和Cheeseman在 ...

  4. 百度在PWA中阐述的弹性布局-[CSS]

    原文链接 响应式布局 自从进入移动互联网时代,响应式布局这个词经常出现在 Web 设计和开发领域,它让 Web 页面在不同尺寸的设备上都具有良好的浏览体验. 开始之前 在讲解响应式布局之前,需要先了解 ...

  5. 使用gulp搭建一个传统的多页面前端项目的开发环境

    1.简介 使用gulp搭建一个传统的多页面前端项目的开发环境 支持pug scss es6编译支持 支持开发环境和打包生成sourceMap 支持文件变动自动刷新浏览器,css是热更新(css改动无需 ...

  6. PTA数据结构与算法题目集(中文) 7-18

    PTA数据结构与算法题目集(中文)  7-18 7-18 银行业务队列简单模拟 (25 分)   设某银行有A.B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗 ...

  7. C++头文件中的模板类

    C++头文件中的模板类 这已经是我的第三篇关于头文件的博客了,没想到我还是踩了个巨坑. 大家都知道要在头文件里声明类成员,在源文件中实现. 但是今天写数据结构作业,在头文件(Stack.h)定义了一个 ...

  8. Vim中实现PHP函数tags跳转

    编译安装ctags 下载地址:http://ctags.sourceforge.net/ 下载文件:ctags-5.8.tar.gz 解压ctags:tar -zxcf ctags-5.8.tar.g ...

  9. scrapy中使用selenium来爬取页面

    scrapy中使用selenium来爬取页面 from selenium import webdriver from scrapy.http.response.html import HtmlResp ...

  10. Linux基础篇,磁盘及文件使用管理

    在windows系统下,我们可以使用图形化界面很明了的看出当前硬盘使用量与某个文件的占用空间大小和文件数量.但是在linux系统中,我们应该如何得到这些信息呢? 当然是功能强大的df与du了. 一.d ...