博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux内核中 进程进程上下文,中断上下文,用户上下文,原子上下文 的理解
阅读量:3923 次
发布时间:2019-05-23

本文共 3809 字,大约阅读时间需要 12 分钟。

1 内核态与用户态:

内核空间和用户空间是现代操作系统的两种工作模式,内核模块运行在内核空间,而用户态应用程序运行在用户空间,他们代表不同的级别,对系统资源有着不同的访问权限,内核模块运行在最高级别(内核态),这个级别下的所用操作都受系统信任,而应用程序运行在比较低级别的(用户态)。内核态和用户态都有自己的内存映射,即自己的地址空间。
处理器总是处于以下状态中的一种:
内核态:运行于进程上下文,内核态代表进程运行于内核空间
内核态:运行于中断上下文,内核态代表硬件运行于内核空间
用户态:运行于用户空间

进程上下文 :

在一个进程在执行的时候,CPU的所有寄存器中的数值,进程的状态以及堆栈上的内容

   当需要切换进程的时候,需要保存当前进程的所有状态【保存当前进程的上下文】。以便再次执行该进程的时候, 能够恢复切换之前状态,继续执行
   一个进程的上下文可以分为三个部分:用户级上下文,寄存器上下文,系统级上下文。如下:

用户级上下文:正文,数据,用户堆栈以及共享存储区

寄存器上下文:通用寄存器,程序寄存器,处理器状态寄存器,栈指针
系统级上下文:进程控制块,内存管理信息,内核栈。

当发生进程调度的时候,进行进程切换就是上下文切换(context switch).,操作系统必须对上面全部信息进行切换【与模式切换只切换寄存器上下文不同】,新调度的进程才能运行,进程上下文主要是异常处理程序和内核线程,内核之所以进入进程上下文是因为进程自身的一些工作需要在内核中做,例如系统调用是为当前进程服务的,异常通常是处理进程导致的错误状态,所以在进程上下文中引用 current 是没有意义的

系统调用进行的模式切换(mode switch)

  模式切换与进程切换比较起来,容易很多,而且节省时间,因为模式切换最主要的任务只是切换进程寄存器上下文的切换。

当一个进程在执行时,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容被称 为该进程的上下文。当内核需要切换到另一个进程时,它需要保存当前进程的 所有状态,即保存当前进程的上下文,以便在再次执行该进程时,能够必得到切换时的状态执行下去。在LINUX中,当前进程上下文均保存在进程的任务数据结 构中。在发生中断时,内核就在被中断进程的上下文中,在内核态下执行中断服务例程。但同时会保留所有需要用到的资源,以便中继服务结束时能恢复被中断进程 的执行。

中断上下文 :

硬件通过触发信号,向CPU发送中断信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理,所以此时的 “中断上下文” 就可以理解为硬件传递过来的参数和内核需要保护的一些环境,主要是被中断进程的环境。内核进入中断上下文是因为中断信号而导致的中断处理或软中断而中断信号的发生是随机的,中断处理程序以及中断并不能实现预测发生中断时当前运行的是哪一个进程,所以在中断上下文中引用 current 是可以的,但是没有意义。

4 进程上下文 与 中断上下文

  内核态可以处于两种上下文 : 进程上下文,中断上下文
  内核会限制中断上下文,不允许有如下操作:

4.1 :进入睡眠状态或者主动放弃CPU

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

②中断上下文执行流程 :1进入中断处理程序–>2保存关键上下文–>3开中断–>4进入中断处理程序的handler–>5关中断–>6中断处理完成–>7开中断。

上半部 硬中断:对应于上面流程的1、2、3步骤,在上半部硬中断中,所有的中断都是被屏蔽的如果在这个时候睡眠了,操作系统不会收到任何中断(包括时钟中断),系统就基本处于瘫痪状态。

下半部 软中断:对应上面流程的 4步骤,此时不能睡眠是因为上下文,操作系统是以进程调度为单位,进程的运行在进程的上下文中,进程运行在进程上下文中,以进程描述符作为管理的数据结构,进程可以睡眠的原意是操作系统可以切换不同的进程上下文,进行调度操作,这些操作都是以进程描述符为支持。中断运行在中断上下文,没有所谓的 中断描述符来描述它,它不是操作系统调度的单位,一旦在中断上下文中睡眠,首先是无法切换上下文(因为没有中断描述符,当前上下文状态得不到保存),其次,没有人来唤醒他,因为他不是操作系统的调度单位。最后,中断的发生是非常频繁的,在一个中断睡眠期间,其他中断发生并且睡眠了,很容易造成中断栈溢出呆滞系统崩溃。

如果上述条件满足了(也就是有中断描述符,并成为调度器的调度单位,栈也不溢出了,理论上是可以做到中断睡眠的),中断是可以睡眠的,但会引起很多问题. 例如,你在时钟中断中睡眠了,那操作系统的时钟就乱了,调度器也失去了依据;例如,你在一个IPI(处理器间中断)中,其它CPU都在死循环等你答复,你确睡眠了,那其它处理器也不工作了; 例如,你在一个DMA中断中睡眠了,上面的进程还在同步的等待I/O的完成,性能就大大降低了……还可以举出很多例子。所以,中断是一种紧急事务,需要操作系统立即处理,不是不能做到睡眠,是它没有理由睡眠。

4.2 占用互斥体:

在占用互斥锁的时候如果获取不到信号量,代码就会睡眠,产生和上面一样的结果,如果必须使用锁,那就用 spinlock

4.3 执行耗时的任务:

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

4.4 访问用户空间虚拟内存:

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

原子上下文:

内核的一个基本原则是:在中断或者 原子上下文中,内核不能访问 用户空间,而且内核不能睡眠,也就是说在这种情况下,内核是不能调用有可能引起睡眠的任何函数,一般来说原子上下文指的是在中断或者软中断之间,以及在自旋锁的时候,原子上下文 有时候可以看成 中断上下文 。

二.什么是进程上下文与中断上下文

1.进程上下文:

(1)进程上文:其是指进程由用户态切换到内核态是需要保存用户态时cpu寄存器中的值,进程状态以及堆栈上的内容,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

(2)进程下文:其是指切换到内核态后执行的程序,即进程运行在内核空间的部分。

2.中断上下文:

(1)中断上文:硬件通过中断触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。中断上文可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被中断的进程环境。

(2)中断下文:执行在内核空间的中断服务程序。

三.为什么要进行不同之间状态的切换

在现在操作系统中,内核功能模块运行在内核空间,而应用程序运行在用户空间。现代的CPU都具有不同的操作模式,代表不同的级别,不同的级别具有不同的功能,其所拥有的资源也不同;在较低的级别中将禁止使用某些处理器的资源。Linux系统设计时利用了这种硬件特性,使用了两个级别,最高级别和最低级别,内核运行在最高级别(内核态),这个级别几乎可以使用处理器的所有资源,而应用程序运行在较低级别(用户态),在这个级别的用户不能对硬件进行直接访问以及对内存的非授权访问。内核态和用户态有自己的内存映射,即自己的地址空间。

当工作在用户态的进程想访问某些内核才能访问的资源时,必须通过系统调用或者中断切换到内核态,由内核代替其执行。进程上下文和中断上下文就是完成这两种状态切换所进行的操作总称。我将其理解为保存用户空间状态是上文,切换后在内核态执行的程序是下文。

四.什么情况下进行用户态到内核态的切换

1.进程上下文主要是异常处理程序和内核线程。内核之所以进入进程上下文是因为进程自身的一些工作需要在内核中做。例如,系统调用是为当前进程服务的,异常通常是处理进程导致的错误状态等。

2.中断上下文是由于硬件发生中断时会触发中断信号请求,请求系统处理中断,执行中断服务子程序。

五.中断上下文代码中注意事项

运行于进程上下文的内核代码是可抢占的,但中断上下文则会一直运行至结束,不会被抢占。所以中断处理程序代码要受到一些限制,在中断代码中不能出现实现下面功能的代码:

(1)睡眠或者放弃CPU。

因为内核在进入中断之前会关闭进程调度,一旦睡眠或者放弃CPU,这时内核无法调度别的进程来执行,系统就会死掉。牢记:中断服务子程序一定不能睡眠(或者阻塞)。

(2)尝试获得信号量

如果获得不到信号量,代码就会睡眠,导致(1)中的结果。

(3)执行耗时的任务

中断处理应该尽可能快,因为如果一个处理程序是IRQF_DISABLED类型,他执行的时候会禁止所有本地中断线,而内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能。中断处理程序的任务尽可能放在中断下半部执行。

(4)访问用户空间的虚拟地址

因为中断运行在内核空间。

转载地址:http://byhrn.baihongyu.com/

你可能感兴趣的文章
8、聊聊java中的进制问题
查看>>
这篇java的NIO编程,保证你能看懂
查看>>
面试官:手写一个冒泡排序,并对其改进(java实现)
查看>>
java中的对称加密算法
查看>>
面试官:手写一个插入排序,并对其改进
查看>>
面试官:手写一个快速排序,并对其改进
查看>>
Hashtable源码分析(基于jdk1.8,推荐)
查看>>
一文彻底看懂Base64原理(并使用java实现)
查看>>
面试官:手写一个归并排序,并对其改进
查看>>
五分钟学会java中的基础类型封装类
查看>>
10、面试官:java中的编码格式转化都有哪几种方式?(中兴面试题)
查看>>
一文彻底搞清楚数字签名的原理(java代码实现)
查看>>
1、曾经风光无限的jsp,为什么现在很少有人使用了?
查看>>
面试官:手写一个希尔排序,并对其改进
查看>>
看了这么多篇红黑树文章,你理解了嘛?
查看>>
面试官:给我手撕一下基数排序,再考虑一下如何进行改进呢?
查看>>
三句话都能解释清楚的java集合类HashSet,你清楚吗?
查看>>
java是如何解决单线程之间通信问题的呢?这篇文章带给你答案
查看>>
面试官:从源码分析一下TreeSet(基于jdk1.8)
查看>>
5、分析一个常见的java多线程通信问题(假死现象)
查看>>