首页 > 系统相关 >原子上下文、进程上下文和中断上下文

原子上下文、进程上下文和中断上下文

时间:2024-05-26 23:34:02浏览次数:24  
标签:中断 用户 原子 空间 内核 进程 上下文

进程上下文、中断上下文及原子上下文

转自:进程上下文、中断上下文及原子上下文_知秋一叶-CSDN博客

​ 谈论进程上下文 、中断上下文 、 原子上下文之前,有必要讨论下两个概念:

a -- 上下文

​ 上下文是从英文context翻译过来,指的是一种环境。相对于进程而言,就是进程执行时的环境;

​ 具体来说就是各个变量和数据,包括所有的寄存器变量、进程打开的文件、内存信息等。

b -- 原子

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

一、为什么会有上下文这种概念

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

​ 其中处理器总处于以下状态中的一种:

​ 内核态,运行于进程上下文,内核代表进程运行于内核空间;

​ 内核态,运行于中断上下文,内核代表硬件运行于内核空间;

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

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

二、进程上下文

​ 所谓的进程上下文,就是一个进程在执行的时候,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 中断上下文

​ 内核可以处于两种上下文:进程上下文和中断上下文。

在系统调用之后,用户应用程序进入内核空间,此后内核空间针对用户空间相应进程的代表就运行于进程上下文。

异步发生的中断会引发中断处理程序被调用,中断处理程序就运行于中断上下文。

中断上下文和进程上下文不可能同时发生。

  运行于进程上下文的内核代码是可抢占的,但中断上下文则会一直运行至结束,不会被抢占。因此,内核会限制中断上下文的工作,不允许其执行如下操作:

a -- 进入睡眠状态或主动放弃CPU

​ 由于中断上下文不属于任何进程,它与current没有任何关系(尽管此时current指向被中断的进程),所以中断上下文一旦睡眠或者放弃CPU,将无法被唤醒。所以也叫原子上下文(atomic context)。

b -- 占用互斥体

​ 为了保护中断句柄临界区资源,不能使用mutexes。如果获得不到信号量,代码就会睡眠,会产生和上面相同的情况,如果必须使用锁,则使用spinlock。

c -- 执行耗时的任务

​ 中断处理应该尽可能快,因为内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能。在中断处理例程中执行耗时任务时,应该交由中断处理例程底半部来处理。

d -- 访问用户空间虚拟内存

​ 因为中断上下文是和特定进程无关的,它是内核代表硬件运行在内核空间,所以在中断上下文无法访问用户空间的虚拟地址

e -- 中断处理例程不应该设置成reentrant(可被并行或递归调用的例程)

​ 因为中断发生时,preempt和irq都被disable,直到中断返回。所以中断上下文和进程上下文不一样,中断处理例程的不同实例,是不允许在SMP上并发运行的。

f -- 中断处理例程可以被更高级别的IRQ中断

如果想禁止这种中断,可以将中断处理例程定义成快速处理例程,相当于告诉CPU,该例程运行时,禁止本地CPU上所有中断请求。这直接导致的结果是,由于其他中断被延迟响应,系统性能下降。

五、原子上下文

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

#define in_irq() (hardirq_count()) //在处理硬中断中
#define in_softirq() (softirq_count()) //在处理软中断中
#define in_interrupt() (irq_count()) //在处理硬中断或软中断中
#define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != 0) //包含以上所有情况
这四个宏所访问的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: 0x000000ff

SOFTIRQ_MASK: 0x0000ff00

HARDIRQ_MASK: 0x0fff0000

​ 凡是上面4个宏返回1得到地方都是原子上下文,是不容许内核访问用户空间,不容许内核睡眠的,不容许调用任何可能引起睡眠的函数。而且代表thread_info->preempt_count不是0,这就告诉内核,在这里面抢占被禁用。

但 是,对于in_atomic()来说,在启用抢占的情况下,它工作的很好,可以告诉内核目前是否持有自旋锁,是否禁用抢占等。但是,在没有启用抢占的情况 下,spin_lock根本不修改preempt_count,所以即使内核调用了spin_lock,持有了自旋锁,in_atomic()仍然会返回 0,错误的告诉内核目前在非原子上下文中。所以凡是依赖in_atomic()来判断是否在原子上下文的代码,在禁抢占的情况下都是有问题的。

原文链接:https://blog.csdn.net/zqixiao_09/article/details/50877756

标签:中断,用户,原子,空间,内核,进程,上下文
From: https://www.cnblogs.com/JinBool/p/18214534

相关文章

  • 中断上下文和原子上下文
    目录中断上下文1、定义2、组成3、特点4、中断上下文的实现5、中断上下文和进程上下文的区别原子上下文1、定义2、特点3、应用场景4、实现方式5、与进程上下文和中断上下文的区别中断上下文1、定义中断上下文(InterruptContext)是指当CPU接收到硬件设备的中断请求时,CPU会暂停当......
  • go go-redis 使用lua保证操作的原子性
      Redis是应对高并发的常用工具,在常用缓存技巧中讲过相关技巧。但有些业务场景,使用Redis会遇到问题,如电商里的秒杀、扣减库存等。拿减库存举例,一般需要两步:先扣减库存,获取扣减后的库存值V如果V小于0,说明库存不够,需要将扣减的值再加回去;如果V大于等于0,则执行后续操作......
  • 探索Go语言的原子操作秘籍:sync/atomic.Value全解析
    引言​在并发编程的世界里,数据的一致性和线程安全是永恒的话题。Go语言以其独特的并发模型——goroutine和channel,简化了并发编程的复杂性。然而,在某些场景下,我们仍然需要一种机制来保证操作的原子性。这就是sync/atomic.Value发挥作用的地方。原子性:并发编程的基石​......
  • 01、Cubemx新建工程与LED点亮和蜂鸣器实现(基于正点原子ZET6)
    一、使用Cubemx新建工程    1、正确选择芯片2、正确选择SYS与RCC3、正确配置时钟树输入数字直接回车,然后一直OKK,让它自己配4、正确建立工程结构与工程打开5、Keil5的配置注意看下方Keil5的配置很重要,不配置不能在keil5中开发(本历程主要是完成最简单的几......
  • 原子、组合与汇编
    应用程序里可以任意写SQL语句,到了数据库这层,所有的SQL语句都被做了编排。在应用层可以同步、异步的投递SQL语句:s1,s2,s3,...。混在意大利面条一样的代码里,看不到谁先执行谁后执行。在数据库层,这些语句会被编排。编排后,实际的执行时序可能是s2,25,s1,s3,s4...那么数据库层面......
  • 原子、组合与汇编
    应用程序里可以任意写SQL语句,到了数据库这层,所有的SQL语句都被做了编排。在应用层可以同步、异步的投递SQL语句:s1,s2,s3,...。混在意大利面条一样的代码里,看不到谁先执行谁后执行。在数据库层,这些语句会被编排。编排后,实际的执行时序可能是s2,25,s1,s3,s4...那么数据库层面......
  • 新型数据中台的特性之——原子化
    目录传统数据中台加工逻辑混杂新型原子化数据架构如何实现新型原子化数据处理的优势传统数据中台加工逻辑混杂传统数据中台架构基本都是依赖sql语言硬编码进行开发,硬编码开发模式下,数据、业务耦合度极高,加工逻辑混杂,只能将数据中台的开发开放给下游系统,将中台自身的技术......
  • 鸿蒙HarmonyOS实战-Stage模型(应用上下文Context)
    ......
  • [IMX6ULL驱动开发]-Linux对中断的处理(一)
    目录中断概念的引入ARM架构中断的流程异常向量表Linux系统对中断的处理ARM对程序和中断的处理Linux进程中断处理中断概念的引入如何理解中断,我们可以进行如下抽象。把CPU看做一个母亲,当它正在执行任务的时候,可以看为是一个母亲在看书。此时可能发生许多不同的情况,比......
  • Java中CAS算法的集中体现:Atomic原子类库,你了解吗?
    一、写在开头在前面的博文中我们学习了volatile关键字,知道了它可以保证有序性和可见性,但无法保障原子性,结局原子性问题推荐使用synchronized、Lock或者AtomicInteger;我们还学习过CAS算法,在那篇博文中我们同样也提及atomic。那么今天,我们就来好好学一学Atomic原子库,一个基于CAS算......