文章目录

  • 前言
  • 用户空间与内核空间
    • 内核态与用户态
  • 进程上下文和中断上下文
    • 上下文
    • 原子
    • 进程上下文
    • 中断上下文
    • 进程上下文VS中断上下文
    • 原子上下文

前言

  • 之前在学习嵌入式linux系统的时候,一直对于中断上下文,进程上下文很迷,听着都很熟悉,但是强行让自己去解释着写概念总是很难去说清,所以奔着弄清楚这几个概念的目的,在网上看了好多的资料。对于这些概念的学习是一个不断累积的过程。

用户空间与内核空间

  • 我们知道现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操心系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核,保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将**最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。**每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。空间分配如下图所示:

  • 有了用户空间和内核空间,整个linux内部结构可以分为三部分,从最底层到最上层依次是:硬件–>内核空间–>用户空间。如下图所示:

  • 需要注意的是:
    (1) 内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据。不管是内核空间还是用户空间,它们都处于虚拟空间中
    (2) Linux使用两级保护机制:0级供内核使用,3级供用户程序使用

内核态与用户态

(1)当一个任务(进程)执行系统调用而陷入内核代码中执行时,称进程处于内核运行态(内核态)。此时处理器处于特权级最高的(0级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。

(2)当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。此时处理器在特权级最低的(3级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。

进程上下文和中断上下文

上下文

  • 上下文是从英文 context 翻译过来的。指的是一种环境。相对于进程而言,就是进程执行时的环境;具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。

原子

  • 原子(atom)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意为"不可被中断的一个或一系列操作" 。

而为什么会有上下文这种概念呢?

  • 内核空间和用户空间是现代操作系统的两种工作模式,内核模块运行在内核空间,而用户态应用程序运行在用户空间。它们代表不同的级别,而对系统资源具有不同的访问权限。内核模块运行在最高级别(内核态),这个级下所有的操作都受系统信任,而应用程序运行在较低级别(用户态)。在这个级别,处理器控制着对硬件的直接访问以及对内存的非授权访问。内核态和用户态有自己的内存映射,即自己的地址空间。

  • 其中处理器总处于以下状态中的一种:
    (1)内核态,运行于进程上下文内核代表进程运行于内核空间;内核态,运行于中断上下文,内核代表硬件运行于内核空间;
    (2)用户态,运行于用户空间

  • 系统的两种不同运行状态,才有了上下文的概念。用户空间的应用程序,如果想请求系统服务,比如操作某个物理设备,映射设备的地址到用户空间,必须通过系统调用来实现。(系统调用是操作系统提供给用户空间的接口函数)。

  • 通过系统调用,用户空间的应用程序就会进入内核空间,由内核代表该进程运行于内核空间,这就涉及到上下文的切换,用户空间和内核空间具有不同的 地址映射,通用或专用的寄存器组,而用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户 空间继续执行。

进程上下文

所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈上的内容,当内核需要切换到另一个进程时,它 需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

  • 一个进程的上下文可以分为三个部分:用户级上下文、寄存器上下文以及系统级上下文
    用户上下文:正文、数据、用户堆栈以及共享存储区;
    寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);
    系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈。
    当发生进程调度时,进行进程切换就是上下文切换(context switch)。
  • 操作系统必须对上面提到的全部信息进行切换,新调度的进程才能运行。而系统调用进行的是模式切换(mode switch)。模式切换与进程切换比较起来,容易很多,而且节省时间,因为模式切换最主要的任务只是切换进程寄存器上下文的切换。
  • 进程上下文主要是异常处理程序和内核线程。内核之所以进入进程上下文是因为进程自身的一些工作需要在内核中做。例如,系统调用是为当前进程服务的,异常通常是处理进程导致的错误状态等。所以在进程上下文中引用current是有意义的。

中断上下文

  • 硬件通过触发信号,向CPU发送中断信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核, 内核通过这些参数进行中断处理。
    所以,“中断上下文”就可以理解为硬件传递过来的这些参数和内核需要保存的一些环境,主要是被中断的进程的环境。
    内核进入中断上下文是因为中断信号而导致的中断处理或软中断。而中断信号的发生是随机的,中断处理程序及软中断并不能事先预测发生中断时当前运行的是哪个进程,所以在中断上下文中引用current是可以的,但没有意义。
    事实上,对于A进程希望等待的中断信号,可能在B进程执行期间发生。例如,A进程启动写磁盘操作,A进程睡眠后B进程在运行,当磁盘写完后磁盘中断信号打断的是B进程,在中断处理时会唤醒A进程。

进程上下文VS中断上下文

  • 内核可以处于两种上下文:进程上下文和中断上下文
    在系统调用之后,用户应用程序进入内核空间,此后内核空间针对用户空间相应进程的代表就运行于进程上下文
  • 异步发生的中断会引发中断处理程序被调用,中断处理程序就运行于中断上下文
    中断上下文和进程上下文不可能同时发生。
    运行于进程上下文的内核代码是可抢占的,但中断上下文则会一直运行至结束,不会被抢占。因此,内核会限制中断上下文的工作,不允许其执行如下操作
  1. 进入睡眠状态或主动放弃CPU
    由于中断上下文不属于任何进程,它与current没有任何关系(尽管此时current指向被中断的进程),所以中断上下文一旦睡眠或者放弃CPU,将无法被唤醒。所以也叫原子上下文(atomic context)。
  2. 占用互斥体
    为了保护中断句柄临界区资源,不能使用mutexes。如果获得不到信号量,代码就会睡眠,会产生和上面相同的情况,如果必须使用锁,则使用spinlock。
  3. 执行耗时的任务
    中断处理应该尽可能快,因为内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能。在中断处理例程中执行耗时任务时,应该交由中断处理例程底半部来处理。
  4. 访问用户空间虚拟内存
    因为中断上下文是和特定进程无关的,它是内核代表硬件运行在内核空间,所以在中断上下文无法访问用户空间的虚拟地址
  5. 中断处理例程不应该设置成reentrant(可被并行或递归调用的例程)
    因为中断发生时,preempt和irq都被disable,直到中断返回。所以中断上下文和进程上下文不一样,中断处理例程的不同实例,是不允许在SMP上并发运行的。
  6. 断处理例程可以被更高级别的IRQ中断
    如果想禁止这种中断,可以将中断处理例程定义成快速处理例程,相当于告诉CPU,该例程运行时,禁止本地CPU上所有中断请求。这直接导致的结果是,由于其他中断被延迟响应,系统性能下降。

原子上下文

内核的一个基本原则就是:在中断或者说原子上下文中,内核不能访问用户空间,而且内核是不能睡眠的。也就是说在这种情况下,内核是不能调用有可能引起睡眠的任何函数。一般来讲原子上下文指的是在中断或软中断中,以及在持有自旋锁的时候。内核提供 了四个宏来判断是否处于这几种情况里:

  • 这四个宏所访问的count都是thread_info->preempt_count。这个变量其实是一个位掩码。最低8位表示抢占计数,通常由spin_lock/spin_unlock修改,或程序员强制修改,同时表明内核容许的最大抢占深度是256。
  • 8-15位是软中断计数,通常由local_bh_disable/local_bh_enable修改,同时表明内核容许的最大软中断深度是256。
  • 16-27位是硬中断计数,通常由enter_irq/exit_irq修改,同时表明内核容许的最大硬中断深度是4096。
  • 第28位是PREEMPT_ACTIVE标志。用代码表示就是:
    PREEMPT_MASK: 0x000000ffSOFTIRQ_MASK: 0x0000ff00HARDIRQ_MASK: 0x0fff0000

凡是上面4个宏返回1得到地方都是原子上下文,是**不容许内核访问用户空间,不容许内核睡眠的,不容许调用任何可能引起睡眠的函数。**而且代表thread_info->preempt_count不是0,这就告诉内核,在这里面抢占被禁用。
但 是,对于in_atomic()来说,在启用抢占的情况下,它工作的很好,可以告诉内核目前是否持有自旋锁,是否禁用抢占等。但是,在没有启用抢占的情况 下,spin_lock根本不修改preempt_count,所以即使内核调用了spin_lock,持有了自旋锁,in_atomic()仍然会返回 0,错误的告诉内核目前在非原子上下文中。所以凡是依赖in_atomic()来判断是否在原子上下文的代码,在禁抢占的情况下都是有问题的。

博客内容参考:https://mp.weixin.qq.com/s?src=11&timestamp=1563710917&ver=1742&signature=QR4lcgtbcKzOvDFLwoqFNplQTjSK7GewpVDBCvNpaXRozYEwcUOrFTqWKf5XsDAp00ySWlARSnQsnzf01DCZW4ANXbnv0iDVukCI4NLwjfqfXrqxwXEwoEGjfqzOoY6B&new=1

嵌入式之linux用户空间与内核空间,进程上下文与中断上下文相关推荐

  1. 对Linux内核中进程上下文和中断上下文的理解

    内核空间和用户空间是操作系统理论的基础之一,即内核功能模块运行在内核空间,而应用程序运行在用户空间.现代的CPU都具有不同的操作模式,代表不同的 级别,不同的级别具有不同的功能,在较低的级别中将禁止某 ...

  2. linux 中断和进程 传递,Linux内核之进程上下文和中断上下文的区别

    进程上下文和中断上下文是操作系统中很重要的两个概念,这两个概念在操作系统课程中不断被提及,是最经常接触.看上去很懂但又说不清楚到底怎么回事.造成这种局面的原因,可能是原来接触到的操作系统课程的教学总停 ...

  3. linux中断--进程上下文和中断上下文

    一.前言 中断发生以后,CPU跳到内核设置好的中断处理代码中去,由这部分内核代码来处理中断.这个处理过程中的上下文就是中断上下文. 为什么可能导致睡眠的函数都不能在中断上下文中使用呢? 首先睡眠的含义 ...

  4. 《Linux操作系统 - 驱动开发》第9章 进程上下文、中断上下文及原子上下文

    谈论进程上下文 .中断上下文.原子上下文之前,有必要讨论下两个概念: a – 上下文 上下文是从英文context翻译过来,指的是一种环境.相对于进程而言,就是进程执行时的环境: 具体来说就是各个变量 ...

  5. linux 物理内存用完了_Linux用户空间与内核空间(理解高端内存)

    Linux内核地址映射模型 x86 CPU采用了段页式地址映射模型.进程代码中的地址为逻辑地址,经过段页式地址映射后,才真正访问物理内存. 段页式机制如下图. Linux内核地址空间划分 通常32位L ...

  6. Linux 用户空间和内核空间

    最近在微信群里看到有人提这个问题,然后查了下资料,觉得这篇文章是写得最能让人看懂的,分享给大家. 欢迎大家评论说出自己的见解,让更多的人更容易理解这部分知识. 之前的相关文章 Linux内存,先看这篇 ...

  7. Linux用户空间与内核空间(理解高端内存)

    目录 Linux内核地址映射模型 Linux内核地址空间划分 Linux内核高端内存的由来 Linux内核高端内存的理解 Linux内核高端内存的划分 常见问题 小结 1.虚拟内核空间到物理空间的映射 ...

  8. linux 各用户内存_Linux用户空间与内核空间(理解高端内存)

    Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...

  9. Linux用户空间与内核空间

    Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数 ...

最新文章

  1. python百度云资源-python学习资源--百度云
  2. Oracle-index索引解读
  3. IOS笔记-计算机中的进制 反码补码 和存储细节
  4. onclick 传参,用转义符进行转义。
  5. 前出塞数据挖掘的一些必须了解的概念
  6. DataTable.ImportRow()与DataTable.Rows.Add()的区别
  7. python是什么类型的编程语言-2.python是什么编程语言。
  8. Eclipse上索爱手机开发平台的配置
  9. matlab读取第一行是汉字csv,在MATLAB中使用`textscan`从csv文件中读取数据
  10. word打开文档很久很慢_解决直接打开Word、Excel文档很慢,而通过先打开WORD、EXCEL程序再打开文档则很快的问题...
  11. 量化框架backtrader之一文读懂Indicator指标
  12. 商标注册过程中,如何避免字体侵权?
  13. redhat enterprise 5 上安装oracle 10.2.0.1
  14. java getfiles_Java基础教程——File类、Paths类、Files类
  15. U盘文件打不开了怎么恢复
  16. ROS机器人实践---小乌龟画圆
  17. 程序员面试金典——空格替换
  18. 疯狂英语口语突破-突破句型2
  19. 《中国金融稳定报告(2018)》及分析(附全文下载)
  20. JS Typed Array 定型数组

热门文章

  1. 屏保问题(即背光灯的关闭)
  2. ef连接mysql报root没有权限_EF下使用自定义的connectionString避免数据库密码泄露
  3. 使用awk提取文本 awk处理条件 awk流程控制 awk扩展应用
  4. unity ugui image组件ngui uisprite 对称显示功能
  5. OCR财务报表识别方案应用
  6. 高考成绩查询2021汕头市,2021汕头市地区高考成绩排名查询
  7. 对ARM紧致内存TCM的理解 转
  8. 简单的STM32蓝牙遥控小车完整项目及资料分享,超全
  9. 【asm基础】nasm和masm的一些区别
  10. 自己搭建RTMP流媒体服务器