Linux内核中进程上下文、中断上下文、原子上下文、用户上下文的理解【转】-阿里云开发者社区

开发者社区> sky-heaven> 正文

Linux内核中进程上下文、中断上下文、原子上下文、用户上下文的理解【转】

简介: 转自:http://blog.csdn.net/laoliu_lcl/article/details/39972459 进程上下文和中断上下文是操作系统中很重要的两个概念,这两个概念在操作系统课程中不断被提及,是最经常接触、看上去很懂但又说不清楚到底怎么回事。
+关注继续查看

转自:http://blog.csdn.net/laoliu_lcl/article/details/39972459

进程上下文和中断上下文是操作系统中很重要的两个概念,这两个概念在操作系统课程中不断被提及,是最经常接触、看上去很懂但又说不清楚到底怎么回事。造成这种局面的原因,可能是原来接触到的操作系统课程的教学总停留在一种浅层次的理论层面上,没有深入去研究。

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

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

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

3、用户态,运行于用户空间。

用户空间的应用程序,通过系统调用,进入内核空间。这个时候用户空间的进程要传递很多变量、参数的值给内核,内核态运行的时候也要保存用户进程的一些寄存器值、变量等。所谓的“进程上下文”,可以看作是用户进程传递给内核的这些参数以及内核要保存的那一整套的变量和寄存器值和当时的环境等。

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

 

关于进程上下文LINUX完全注释中的一段话:

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

 

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

 

正是有了不同运行状态的划分,才有了上下文的概念。用户空间的应用程序,如果想要请求系统服务,比如操作一个物理设备,或者映射一段设备空间的地址到用户空间,就必须通过系统调用来(操作系统提供给用户空间的接口函数)实现。如下图所示:

 

通过系统调用,用户空间的应用程序就会进入内核空间,由内核代表该进程运行于内核空间,这就涉及到上下文的切换,用户空间和内核空间具有不同的地址映射,通用或专用的寄存器组,而用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行,所谓的进程上下文,就是一个进程在执行的时候,CPU的所有寄存器中的值、进程的状态以及堆栈中的内容,当内核需要切换到另一个进程时,它需要保存当前进程的所有状态,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。

 

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

 

Linux内核工作在进程上下文或者中断上下文。提供系统调用服务的内核代码代表发起系统调用的应用程序运行在进程上下文;另一方面,中断处理程序,异步运行在中断上下文。中断上下文和特定进程无关。

 

运行在进程上下文的内核代码是可以被抢占的(Linux2.6支持抢占)。但是一个中断上下文,通常都会始终占有CPU(当然中断可以嵌套,但我们一般不这样做),不可以被打断。正因为如此,运行在中断上下文的代码就要受一些限制,不能做下面的事情:

 

1、睡眠或者放弃CPU。

    这样做的后果是灾难性的,因为内核在进入中断之前会关闭进程调度,一旦睡眠或者放弃CPU,这时内核无法调度别的进程来执行,系统就会死掉。

 

2、尝试获得信号量

    如果获得不到信号量,代码就会睡眠,会产生和上面相同的情况。

 

3、执行耗时的任务

    中断处理应该尽可能快,因为内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能。

 

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

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

原子上下文

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

#definein_irq()     (hardirq_count()) //在处理硬中断中

#definein_softirq()     (softirq_count()) //在处理软中断中

#definein_interrupt()   (irq_count()) //在处理硬中断或软中断中

#definein_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()来判断是否在原子上下文的代码,在禁抢占的情况下都是有问题的。

 

用户上下文应为用户级上下文,是进程上下文的一部分,在很多地方都用的比较模糊。

【作者】张昺华
【新浪微博】 张昺华--sky
【twitter】 @sky2030_
【facebook】 张昺华 zhangbinghua
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Linux内核中进程上下文、中断上下文、原子上下文、用户上下文的理解【转】
转自:http://blog.csdn.net/laoliu_lcl/article/details/39972459 进程上下文和中断上下文是操作系统中很重要的两个概念,这两个概念在操作系统课程中不断被提及,是最经常接触、看上去很懂但又说不清楚到底怎么回事。
780 0
Apache2.0版本以上支持中文软件名文件下载
好久没写博文了,今天抽个小空写个故障解决方案吧!不过大多数基本是在网上找的的答案,这里我整理下大致步骤。如果有需要的朋友请参考! 故障描述:外网有一台apache服务器提供软件给客户下载,因为很多软件名是带有中文的,所以下载的时候失败,临时的解决方案是将中文名修改为一个英文名就OK了,但是这只是一时的解决步骤,最终的方案就是让apache支持中文软件名文件下载。
841 0
DT观察 | DT化进程持续展开:未来十年科技是什么样子?
约100年前的1910年,有感于曼哈顿的灯火通明,美国意象派诗人埃兹拉-庞德这样赞颂新奇的电力:“这就是文明诗一样的美景,因为我们已把星星摘了下来,终于遂了心愿”。无数的热议、想象、憧憬、幻想,同样发生于100年后的今天——DT时代! DT时代的模式升级与范式转移之产业篇 相
1982 0
C语言及程序设计进阶例程-14 开发一个电子词典
贺老师教学链接  C语言及程序设计进阶 本课讲解 开发一个电子词典(下载词库点击打开链接) #include <stdio.h> #include<string.h> #include<stdlib.h> //定义词条类 typedef struct { char english[20]; char chinese[30]; cha
1107 0
Linux下C编程,子进程创建函数fork() 执行解析
最近在看进程间的通信,看到了fork()函数,虽然以前用过,这次经过思考加深了理解。现总结如下: 1.函数本身   (1)头文件   #include  #include   (2)函数原型   pid_t fork( void);  (pid_t 是一个宏定义,其实质是int 被定义在#include中)  返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1   (3)函数说明   一个现有进程可以调用fork函数创建一个新进程。
674 0
通过命令管道,在进程之间进行通信的简单例子
write_to_named_pipe.py import os if __name__ == "__main__": named_pipe = "my_pipe" if not os.
1030 0
《阿里云安全报告》中文版开启全文下载,详解2018上半年网络安全态势
近日,由阿里云安全创新实验室推出的《2018上半年阿里云安全报告》中文版开启全文下载。 报告指出,今天的网络安全风险比以往任何时候都大,无论企业的服务和数据部署本地还是云上,只要有价值的数据,就会成为攻击目标。
3085 0
+关注
sky-heaven
我是一个技术爱好者,喜欢分享交流技术心得
1191
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载