深入理解linux进程切换

QGroundControl高级配置与自定义功能实战指南 本文深入探讨了QGroundControl(QGC)的高级配置与自定义功能,为无人机开发者、系统集成商和高级用户提供实战指南。内容涵盖从品牌界面定制、自定义MAVLink消息处理,到插件开发与自动化部署的全流程,旨在帮助用户解锁QGC的隐藏潜力,打造专属的行业解决方案。 阅读详情

实验要求:深入理解进程切换

  • 参考《庖丁解牛Linux操作系统分析》相关内容,跟踪分析进程切换的过程完成实验并写一篇实验报告,总结进程切换的工作机制以及sp和ip在不同体系结构下汇编代码的切换方法,深入理解进程切换。具体要求如下:

实验原理

进程切换:简述用户态进程X切换到用户态进程Y的过程

  1. 正在运行的用户态进程X。
  2. 发生中断(包括异常、系统调用等),CPU完成load cs:rip(entry of a specific ISR)即跳转到中断处理程序入口。
  3. 中断上下文切换,具体包括如下几点:
    • swapgs指令保存现场,可以理解CPU通过swapgs指令给当前CPU寄存器状态做了一个快照。
    • rsp point to kernel stack,加载当前进程内核堆栈栈顶地址到RSP寄存器。
    • save cs:rip/ss:rsp/rflags:将当前CPU关键上下文压入进程X的内核堆栈,快速系统调用是由系统调用入口处的汇编代码实现的。
    此时完成了中断上下文切换,即从进程X的用户态到进程X的内核态。
  4. 中断处理过程中或中断返回前调用了schedule(),完成进程调度算法选择next进程、进程地址空间切换、switch_to关键的进程上下文切换等。
  5. switch_to调用了__switch_to_asm做关键的进程上下文切换。将当前进程X的内核堆栈切换到进程调度算法选出来的next进程(进程Y)的内核堆栈,并完成eip的状态切换,之后运行Y。
  6. 中断上下文恢复,进程Y进行中断的上下文恢复。
  7. 中断上下文恢复最后一步iret - pop cs:rip/ss:rsp/rflags,从Y的内核堆栈中弹出(3)中对应的压栈内容,完成中断上下文的切换,即从Y的内核态返回到Y的用户态。
  8. 继续运行用户态进程Y。

详细分析

在linux中的上下文切换以content_switch 为核心,位于kernel/sched/core.c 中,分析并深入理解进程切换

static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
         struct task_struct *next, struct rq_flags *rf)
{
  prepare_task_switch(rq, prev, next);
  /*
   * For paravirt, this is coupled with an exit in switch_to to
   * combine the page table reload and the switch backend into
   * one hypercall.
   */
  arch_start_context_switch(prev);
  /*
   * kernel -> kernel   lazy + transfer active
   *   user -> kernel   lazy + mmgrab() active
   *
   * kernel ->   user   switch + mmdrop() active
   *   user ->   user   switch
   */
  if (!next->mm) {                                // to kernel
    enter_lazy_tlb(prev->active_mm, next);
    next->active_mm = prev->active_mm;
    if (prev->mm)                           // from user
      mmgrab(prev->active_mm);
    else
      prev->active_mm = NULL;
  } else {                                        // to user
    membarrier_switch_mm(rq, prev->active_mm, next->mm);
    /*
     * sys_membarrier() requires an smp_mb() between setting
     * rq->curr / membarrier_switch_mm() and returning to userspace.
     *
     * The below provides this either through switch_mm(), or in
     * case 'prev->active_mm == next->mm' through
     * finish_task_switch()'s mmdrop().
     */
    switch_mm_irqs_off(prev->active_mm, next->mm, next);
    if (!prev->mm) {                        // from kernel
      /* will mmdrop() in finish_task_switch(). */
      rq->prev_mm = prev->active_mm;
      prev->active_mm = NULL;
    }
  }
  rq->clock_update_flags &= ~(RQCF_ACT_SKIP|RQCF_REQ_SKIP);
  prepare_lock_switch(rq, next, rf);
  /* Here we just switch the register state and the stack. */
  switch_to(prev, next, prev);
  barrier();
  return finish_task_switch(prev);
}

进程切换将CPU的控制权从一个进程转移到另一个进程。在多任务操作系统中,多个进程轮流执行,通过进程切换来实现任务的切换和调度。

1. prepare_task_switch(rq, prev, next)准备进程切换,传递了相关参数。rq 指向running queue(就绪队列);prev 和 next 分别指向切换前后进程的进程描述符

2. 根据下一个进程的mm字段是否为空来判断进程切换的类型。如果为空,表示将要切换到内核空间;否则,表示将要切换到用户空间。

 if (!next->mm) {                                // to kernel
    enter_lazy_tlb(prev->active_mm, next);
    next->active_mm = prev->active_mm;
    if (prev->mm)                           // from user
      mmgrab(prev->active_mm);
    else
      prev->active_mm = NULL;
  } else {                                        // to user
    membarrier_switch_mm(rq, prev->active_mm, next->mm);
    /*
     * sys_membarrier() requires an smp_mb() between setting
     * rq->curr / membarrier_switch_mm() and returning to userspace.
     *
     * The below provides this either through switch_mm(), or in
     * case 'prev->active_mm == next->mm' through
     * finish_task_switch()'s mmdrop().
     */
    switch_mm_irqs_off(prev->active_mm, next->mm, next);
    if (!prev->mm) {                        // from kernel
      /* will mmdrop() in finish_task_switch(). */
      rq->prev_mm = prev->active_mm;
      prev->active_mm = NULL;
    }
  }
  • 切换到内核空间的处理:
enter_lazy_tlb(prev->active_mm, next);
next->active_mm = prev->active_mm;
if (prev->mm)     // from user
  mmgrab(prev->active_mm);
else
  prev->active_mm = NULL;

从用户空间切换到内核空间时的处理。先调用enter_lazy_tlb()来处理TLB(转换后备缓冲)的延迟更新,再将下一个进程的active_mm设置为当前进程的active_mm。如果当前进程是从用户空间切换过来(即prev->mm不为空),则调用mmgrab()对active_mm进行引用计数增加操作。最后,将当前进程的active_mm设置为NULL。

  • 切换到用户空间的处理:
membarrier_switch_mm(rq, prev->active_mm, next->mm);
switch_mm_irqs_off(prev->active_mm, next->mm, next);
if (!prev->mm) {    // from kernel
  rq->prev_mm = prev->active_mm;
  prev->active_mm = NULL;
}

从内核空间切换到用户空间时,先调用membarrier_switch_mm()来处理内存屏障相关的操作,再调用switch_mm_irqs_off()来切换页表,并关闭中断。如果当前进程是从内核空间切换过来的(即prev->mm为空),则将当前进程的active_mm保存到rq->prev_mm中,并将prev->active_mm设置为NULL。

3. prepare_lock_switch(rq, next, rf)准备锁的切换,传递了相关参数。

4. switch_to(prev, next, prev)实际的上下文切换函数,将当前进程切换到下一个进程。它保存当前进程的寄存器状态和堆栈,加载下一个进程的寄存器状态和堆栈。

ENTRY(__switch_to_asm)
  UNWIND_HINT_FUNC
  /*
   * Save callee-saved registers
   * This must match the order in inactive_task_frame
   */
  pushq  %rbp
  pushq  %rbx
  pushq  %r12
  pushq  %r13
  pushq  %r14
  pushq  %r15

  /* switch stack */
  movq  %rsp, TASK_threadsp(%rdi) // 保存旧进程的栈顶
  movq  TASK_threadsp(%rsi), %rsp // 恢复新进程的栈顶

  /* restore callee-saved registers */
  popq  %r15
  popq  %r14
  popq  %r13
  popq  %r12
  popq  %rbx
  popq  %rbp

  jmp  __switch_to
END(__switch_to_asm)

5.barrier()内存屏障,用于确保在继续执行之前,前面的所有内存操作都已完成。

6. return finish_task_switch(prev)用于完成进程切换,传递了当前进程的参数,会执行一些与进程切换相关的清理工作,并返回之前的进程。

实现进程切换的过程,根据下一个进程的mm字段是否为空,判断切换的类型(内核空间或用户空间)进行相应的处理,包括TLB更新、页表切换、中断关闭等。最后调用实际的上下文切换函数将控制权从当前进程转移到下一个进程,并完成一些清理工作。

ComfyUI 局部重绘工作流示例 本文介绍了使用ComfyUI进行图像局部重绘的基础工作流程,重点讲解如何修改人物眼睛颜色和表情。主要内容包括:1.准备工作(可选下载DreamShaperv8模型);2.加载素材图片和工作流文件;3.使用遮罩编辑器绘制需要修改的区域;4.修改提示词控制生成内容;5.调整denoise参数优化效果。教程提供了详细的提示词示例(如"smile,blackeyes"等)和参数设置建议,帮助用户通过多次尝试获得理想效果。该工作流适用于修改图像局部区域而不影响整体画面。 阅读详情

相关推荐

华为铁三角(AR、SR、FR)的考核指标设计

以和为核心,通过和实现协同。考核维度分为和,并随市场阶段动态调整权重。

从技术实践立足,从项目管理方法论延伸思考 2769

【汇编】CS、IP寄存器与代码段,用汇编语言写的源程序,jmp指令

在汇编语言中,CS(Code Segment)和IP(Instruction Pointer)寄存器是与代码执行密切相关的两个重要寄存器。它们与代码段直接关联,通过jmp(Jump)指令,程序能够实现无条件跳转到指定的代码段和偏移地址。本文将深入探讨CS、IP寄存器、代码段的关系,以及jmp指令的作用和使用。

m0_62599305的博客 3459

浮点数运算的陷阱与启示:FP16加法器/乘法器开发中的常见误区

本文深入探讨FP16加法器和乘法器开发中的常见误区,包括FP16格式解析、阶码对齐陷阱、尾数运算风险及规格化处理。通过Verilog实战代码展示防御性编程技巧,帮助开发者避免边界条件处理和异常状态管理中的错误,提升硬件设计的可靠性和效率。

dell8的博客 249

CSAPP错题本

这一遍做的是真题,因此所有的错题和疑问点不只是罗列知识点,会附加相关的知识点。

zhousiyuan0515的博客 6383

【PLC】三菱plc控件安装 component Movedata had the following error ... Error Number:-119

Windows 10 专业版/企业版本版本号:22H2操作系统内部版本:19045.3448。

少莫千华 8001

EB tresos配置指南:CAN通信信号收发全流程解析

本文详细解析了使用EB tresos配置工具实现AUTOSAR架构下CAN通信信号收发功能的全流程。从环境准备、COM模块信号定义、PduR路由配置、CanIf硬件抽象到CAN驱动层设置,提供了清晰的步骤指南和关键配置要点,帮助开发者快速打通从应用层到物理层的数据链路,实现可靠的CAN通信。

weixin_29192141的博客 508

汇编语言基础:寄存器和寻址方式

寄存器分类AX、BX、CX、DX 一般用来存放数据,所以被称为数据寄存器。8位寄存器AX,BX,CX,DX在8086中为16位寄存器,每个寄存器的高位和低位均可以作为8位寄存器访问。x32构架x32架构中,通用寄存器都在16位版本的基础上扩展成为32位版本,名字加了E作为前缀。x64构架在x64架构中,通用寄存器都扩展成为64位版本,名字也进行了升级。SI和DI功能和BX相同,可以用于间接寻址。主要用于存放存储单元在段内的偏移量。但是SI、DI不可分割成8位寄存器。在16为构架中,16位的指针只能访问64k

hustlei的专栏 1万+

Cadence Virtuoso实战:NMOS差分放大器设计与SPICE仿真全解析

本文详细解析了使用Cadence Virtuoso设计NMOS差分放大器并进行SPICE仿真的全流程。从基础设计要点、原理图绘制到工作点分析与性能调优,提供了实用的设计技巧和常见问题解决方案,帮助工程师高效完成模拟集成电路设计。重点介绍了差分放大器的关键参数设置、饱和区优化及版图设计注意事项,适用于ADC、DAC等高性能电路开发。

weixin_28340315的博客 610

linux kernel 进程管理,Linux内核进程管理:进程的“内核栈”、current宏、进程描述符...

目录linux 进程内核栈概念在每一个进程的生命周期中,经常会通过系统调用(SYSCALL)陷入内核。在执行系统调用陷入内核之后,这些内核代码所使用的栈并不是原先用户空间中的栈,而是一个内核空间的栈,这个称作进程的“内核栈”。每个task的栈分成用户栈和内核栈两部分,进程内核栈在kernel中的定义是:union thread_union {struct thread_info thread_in...

weixin_39618275的博客 667

100天精通Python(基础篇)——第3天:运算符全解析(算术运算符、比较运算符、逻辑运算符、赋值运算符及其优先级规则)

100天精通Python(基础篇)——第3天:运算符全解析(算术运算符、比较运算符、逻辑运算符、赋值运算符及其优先级规则)

努力让自己发光,对的人才能迎着光而来 14万+

14、脑肿瘤复发预测与转移瘤跟踪的自动化方法

本文介绍两种脑肿瘤相关自动化方法:一种用于预测胶质瘤切除术后的肿瘤复发位置,结合图像配准、静态模型和动态模拟模型,利用患者的DTI数据进行预测;另一种用于在纵向扫描中跟踪转移性脑肿瘤,通过联合求解配准参数估计和图像变化标记问题,提高肿瘤跟踪的准确性和效率。文章同时分析了两种方法的优势与挑战,并提出了未来研究方向,旨在为脑肿瘤的诊断和治疗提供更可靠的工具。

defi6farmer的博客 115

Linux内核模块调试一

在windows 下编程最舒服的就是其面向事件的线程同步互斥机制,在最开始的时候我就考虑一个问题,事件会不会丢失?其实对于会不会丢失要看他的底层实现机制,如果底层是一个队列当然不会丢失,底层要仅仅是一行位图,那写100次1和写1一次1的区别就是你的识别够不够快,你能不能辨别出这个1变化了一百次。...

张飞online博客 2884

Arcgis模型构建器01——写一个简单的模型

在使用模型构建器解决这个需求之前,我们要想清楚如果我们手动解决的话,应该如何去处理,因为构建模型的过程正是基于我们手动处理的过程来构建的。我有一个全国的dem影像数据和一个陕西省边界范围矢量,现在我想获取陕西省的dem影像的坡度数据。填写完之后点击确定,我们发现,两个输入数据和工具连接起来了,并且通过裁剪工具得到一个中间结果,即。我们发现工具框和中间数据框都存在阴影,说明已经运行过了这个模型,不报错就说明模型运行成功!现在我们就把数据和工具都串联起来了,成功构建好了模型。

爱吃雪糕的小布丁的博客 918

深入理解Linux系统进程切换

在Linux这样的多任务操作系统中,进程切换(context switching)是核心功能之一。它允许多个进程"同时"运行在单个CPU上,通过快速切换创造并行执行的假象。理解进程切换的机制对于系统性能调优、内核开发以及深入理解操作系统原理都至关重要。

pengdott的专栏 893

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Linux深入理解进程切换

从现在起,内核在新进程的内核态栈上操作,所以,这条指令才是执行旧进程切换到新进程的开始。其中,content_switch 函数有三个参数:rq、prev、next,rq即使上面我们说的running queue(就绪队列),prev 指向切换前进程的进程描述符,next 指向切换后进程的进程描述符。switch_to 调用3个参数,prev、next和last,prev和next分别指向新旧进程的描述符地址,last,是一个输出参数,用来记录是从哪个进程切换来的。将新进程的栈指针加载到esp寄存器中。

qq_43541346的博客 1012

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Linux内核进程上下文切换深入理解

我都知道操作系统的一个重要功能就是进行进程管理,而进程管理就是在合适的时机选择合适的进程来执行,在单个cpu运行队列上各个进程宏观并行微观串行执行,多个cpu运行队列上的各个进程之间完全的并行执行。进程管理是个复杂的过程,例如进程的描述、创建和销毁、生命周期管理、进程切换、进程抢占、调度策略、负载均衡等等。本文主要关注进程管理的一个切入点,那就是进程的上下文切换,来理解linux内核是如何进程进程上下文切换的,从而揭开上下文切换的神秘面纱。 (注意:本文以linux-5.0内核源码讲解,采用arm64架构)

lx123010的专栏 7622

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

深入理解Linux内核进程上下文切换

作者简介韩传华,就职于南京大鱼半导体有限公司,主要从事linux相关系统软件开发工作,负责Soc芯片BringUp及系统软件开发,乐于分享喜欢学习,喜欢专研Linux内核源代码。我都知道...

宋宝华 1万+

Linux作业:深入理解进程切换

本文主要分析 Linux 5.4.34 版本内核中进程切换的基本操作与基本代码框架。

fatetogate的博客 368

lab5:深入理解Linux进程切换

让进程来占用处理器,实质上是把某个进程存放在私有堆栈中寄存器的数据(前一次本进程被中止时的中间数据)再恢复到处理器的寄存器中去,并把待运行进程的断点送入处理器的程序指针PC,于是待运行进程就开始被处理器运行了,也就是这个进程已经占有处理器的使用权了。在进程未占用处理器时,进程的上下文是存储在进程的私有堆栈中的。通过代码可知,如果要切换的进程是内核级进程,next->active_mm = prev->active_mm 直接把切换前进程的mm传递给此内核级进程,即内核级线程借用用户进程地址空间运行。

qq_44689207的博客 452

深入理解Linux 0.11进程切换机制

通过gdb调试可以观察到:切换前0号进程的TSS中保存了它被中断时的执行现场,而1号进程的TSS则包含了它将要恢复执行的现场。当发生进程切换时,当前运行进程的寄存器状态会被保存到它的任务状态段(TSS)中,然后从目标进程的TSS中恢复其寄存器状态。在进程切换过程中,TR寄存器的值会发生变化,指向新进程的TSS。通过分析TR寄存器的变化,可以清楚地看到CPU是如何找到并切换到新进程的任务状态段的。通过观察0号进程和1号进程的剩余时间片,可以深入理解调度器是如何决定何时进行进程切换的。

SilvermistOwl67的博客 958

如何切换目录_深入理解Linux内核进程上下文切换

在原作者基础上修改了些文字描述,让文章更加通俗易懂作者简介韩传华,就职于南京大鱼半导体有限公司,主要从事linux相关系统软件开发工作,负责Soc芯片BringUp及系统软件开发,乐于分享喜欢学习,喜欢专研Linux内核源代码。我们都知道操作系统的一个重要功能就是进行进程管理,而进程管理就是在合适的时机选择合适的进程来执行,在单个cpu运行队列上各个进程宏观并行微观串行执行,多个cpu运...

weixin_39998859的博客 289

Linux操作系统-深入理解进程切换

当一个进程正在运行时触发系统调用或被中断,将进行中断上下文的切换,之后执行ISR中断服务,在中断处理结束后,使用_schedule()函数进行进程切换。schedule()函数首先从CPU任务队列中取出当前进程的标识符记为prev进程。然后通过进程调度算法确定下一个要被换上的进程,记为next进程。之后,检查next如果和prev进程不一样,调用context_switch()函数进行上下文切换,next进程进入CPU运行。

weixin_44598934的博客 751
上一篇: 以time/gettimeofday系统调用为例分析ARM64 Linux 5.4.34
下一篇: 一文读懂传统目标检测和YOLO
Flyy.
博客等级 码龄7年 6粉丝 9原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Flyy.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值