进程上下文和中断上下文

文章目录

  • 进程的preempt_count变量
    • thread_info
    • preempt_count
  • hardirq相关
  • softirq相关
  • 上下文

原文链接: https://zhuanlan.zhihu.com/p/88883239

进程的preempt_count变量

thread_info

在内核中,上下文的设置和判断接口可以参考 include/linux/preempt.h 文件,整个机制的实现都依赖于一个变量:preempt_count,这个变量被定义在进程struct task_struct的 thread_info域中 ,也就是线程描述符中,线程描述符被放在内核栈的底部,在内核中可以通过 current_thread_info() 接口来获取进程的 thread_info:

static inline struct thread_info *current_thread_info(void)
{return (struct thread_info *)(current_stack_pointer & ~(THREAD_SIZE - 1));
}register unsigned long current_stack_pointer asm ("sp");

其中 THREAD_SIZE 通常的大小为 4K 或者 8K,取出当前内核栈的 sp 指针,通过简单地屏蔽掉 sp 的低 13 位,就可以获取到 thread_info 的基地址。

在 arm 中,preempt_count 是 per task 的变量,而在 x86 中,preempt_count 是 percpu 类型的变量。

preempt_count

请添加图片描述
作为控制上下文的变量, preempt_count 是 int 型,一共 32 位。通过设置该变量不同的位来设置内核中的上下文标志,包括硬中断上下文、软中断上下文、进程上下文等,通过判断该变量的值就可以判断当前程序所属的上下文状态。

整个 preempt_count 被分为几个部分:

  • bit 0-7:用于记录关闭调度的次数。中断上下文中,调度是关闭的,不会发生进程的切换,可以使用preempt_disable()来显示地关闭调度,关闭次数由第0到7个bits组成的preemption count(注意不是preempt count)来记录。每使用一次preempt_disable(),preemption count的值就会加1,使用preempt_enable()则会让preemption count的值减1。
  • bit 8-15:描述软中断的标志位,如果softirq count的值为正数,说明现在正处于softirq上下文中,因为软中断在单个CPU上是不会嵌套执行的,所以只需要用第8位就可以用来判断当前是否处于软中断的上下文中,其他的9-15位用于记录关闭软中断的次数
  • bit 16-19:描述硬中断嵌套次数,在老版本的linux 上支持中断的嵌套,但是自从 2.6 版本之后内核就不再支持中断嵌套,所以其实只用到了一位,如果这部分为正数表示在硬件中断上下文,为 0 则表示不在。
  • bit20 :用于指示 NMI 中断,只有两个状态:发生并处理 NMI 中断置 1,退出中断清除。
  • 其它 bit :没有使用到,保留

hardirq相关

preempt_count中的第16到19个bit表示hardirq count,它记录了进入hardirq/top half的嵌套次数,在这篇文章介绍的do_IRQ()中,irq_enter()用于标记hardirq的进入,此时hardirq count的值会加1。irq_exit()用于标记hardirq的退出,hardirq count的值会相应的减1。如果hardirq count的值为正数,说明现在正处于hardirq上下文中,代码中可借助in_irq()宏实现快速判断。注意这里的命名是"in_irq"而不是"in_hardirq"。

#define hardirq_count()	 (preempt_count() & HARDIRQ_MASK)
#define in_irq()  (hardirq_count())

hardirq count占据4个bits,理论上可以表示16层嵌套,但现在Linux系统并不支持hardirq的嵌套执行,所以实际使用的只有1个bit。

softirq相关

preempt_count中的第8到15个bit表示softirq count,它记录了进入softirq的嵌套次数,如果softirq count的值为正数,说明现在正处于softirq上下文中。由于softirq在单个CPU上是不会嵌套执行的,因此和hardirq count一样,实际只需要一个bit(bit 8)就可以了。但这里多出的7个bits并不是因为历史原因多出来的,而是另有他用。

这个"他用"就是表示在进程上下文中,为了防止进程被softirq所抢占,关闭/禁止softirq的次数,比如每使用一次local_bh_disable(),softirq count高7个bits(bit 9到bit 15)的值就会加1,使用local_bh_enable()则会让softirq count高7个bits的的值减1。

代码中可借助in_softirq()宏快速判断当前是否在softirq上下文:

#define softirq_count()  (preempt_count() & SOFTIRQ_MASK)
#define in_softirq()	 (softirq_count())

上下文

不管是hardirq上下文还是softirq上下文,都属于我们俗称的中断上下文(interrupt context)。
请添加图片描述
为此,有一个名为in_interrupt()的宏专门用来判断当前是否在中断上下文中。

#define irq_count()	 (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK | NMI_MASK))			 
#define in_interrupt()  (irq_count())

与中断上下文相对应的就是俗称的进程上下文(process context)

#define in_task()  (!(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_OFFSET | NMI_MASK)))			   

需要注意的是,并不是只有进程才会处在process context,内核线程依然可以运行在process context。
在中断上下文中,调度是关闭的,不会发生进程的切换,这属于一种隐式的禁止调度,而在代码中,也可以使用preempt_disable()来显示地关闭调度,关闭次数由第0到7个bits组成的preemption count(注意不是preempt count)来记录。每使用一次preempt_disable(),preemption count的值就会加1,使用preempt_enable()则会让preemption count的值减1。preemption count占8个bits,因此一共可以表示最多256层调度关闭的嵌套。

处于中断上下文,或者显示地禁止了调度,preempt_count()的值都不为0,都不允许睡眠/调度的发生,这两种场景被统称为atomic上下文,可由in_atomic()宏给出判断。

#define in_atomic()	(preempt_count() != 0)

中断上下文、进程上下文和atomic上下文的关系大概可以表示成这样:
请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379514.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

标题:凑算式

标题:凑算式 这个算式中AI代表19的数字,不同的字母代表不同的数字。 比如: 68/3952/714 就是一种解法, 53/1972/486 是另一种解法。 这个算式一共有多少种解法? 注意:你提交应该是个整数,不要…

汇编中imul_JavaScript中带有示例的Math.imul()方法

汇编中imulJavaScript | Math.imul()方法 (JavaScript | Math.imul() Method) Math.imul() is a function in math library of JavaScript that is used to the 32-bit multiplication of the two values passed to it. It uses C-like semantics to find the multiplication. …

AFTER触发器与INSTEAD OF触发器的区别

INSTEAD OF 触发器用来代替通常的触发动作,即当对表进行INSERT、UPDATE 或 DELETE 操作时,系统不是直接对表执行这些操作,而是把操作内容交给触发器,让触发器检查所进行的操作是否正确。如正确才进行相应的操作。因此,…

Linux内存地址管理

文章目录系统内存布局内核地址的低端和高端内存概念低端内存高端内存地址转换和MMULinux中的四级分页模型虚拟地址字段页表处理将虚拟地址转换物理地址Linux系统中的每个内存地址都是虚拟的,它们不直接指向任何物理内存地址。每当访问内存位置时,可以执行…

录制caf 转 mp3

编译需要使用的 lame库http://www.cocoachina.com/bbs/read.php?tid108237参考的文章http://blog.csdn.net/ysy441088327/article/details/7392842说起来,我一直在找一个音频转换成mp3的方法。一年前,我成功编译出了一个lame for armv7的库。苦于不会使…

杭电2012-素数判定(C)

Problem Description 对于表达式n^2n41&#xff0c;当n在&#xff08;x,y&#xff09;范围内取整数值时&#xff08;包括x,y&#xff09;(-39<x<y<50)&#xff0c;判定该表达式的值是否都为素数。 Input 输入数据有多组&#xff0c;每组占一行&#xff0c;由两个整数…

math.ceil带小数点_JavaScript中带有示例的Math.ceil()方法

math.ceil带小数点JavaScript | Math.ceil()方法 (JavaScript | Math.ceil() Method) Math.ceil() is a function in math library of JavaScript that is used to round up the number passed to the function. The method will return the nearest integer value indeed is g…

開發記要 詭異的變量

告別繁體文盲,從寫blog開始 Variable命名很重要,有多重要,看看.net和java的加密就知道, 都是把variable改到一塌糊塗,你想看看都沒門. 但是這幾天看遺留系統的代碼,真是大開眼界。 我一直以為別人寫a,b,c,d這些單字節variable已經很過分。直到我看到以下這幾個&#xff0…

排序算法---快速排序、堆排序、冒泡排序

排序算法1 快速排序代码实现stdlib库快排2 堆排序堆排序的基本思想如何构造一个大顶堆排序3 冒泡排序1 快速排序 文章原地址&#xff1a;https://blog.csdn.net/morewindows/article/details/6684558 快速排序的平均时间复杂度是0(NlogN)&#xff0c;它采用了一种分治的策略&a…

CSS Hack 汇总快查

*:lang(zh) select {font:12px !important;} /*FF的专用*/ select:empty {font:12px !important;} /*safari可见*/ 这里select是选择符&#xff0c;根据情况更换。第二句是MAC上safari浏览器独有的。 仅IE7识别 *html {…} 当面临需要只针对IE7做样式的时候就可以采用这个HACK…

杭电2013-蟠桃记(C++)

Problem Description 喜欢西游记的同学肯定都知道悟空偷吃蟠桃的故事&#xff0c;你们一定都觉得这猴子太闹腾了&#xff0c;其实你们是有所不知&#xff1a;悟空是在研究一个数学问题&#xff01; 什么问题&#xff1f;他研究的问题是蟠桃一共有多少个&#xff01; 不过&#…

c#中重载单目运算符-_C#程序重载二进制运算符(-,*,/)

c#中重载单目运算符-Here, we will design overloaded methods for binary operators: minus, multiply and divide. In the below program, we will create a Calculator class with data member val. 在这里&#xff0c;我们将为二进制运算符设计重载方法&#xff1a;减&…

项目总结:华南师范大学校园开发教育android客户端总结

忽略之前小打小闹&#xff0c;这个项目算是我的第一个项目--SCNU的网络公选课的android版本的客户端。项目是从5月中旬开始的&#xff0c;中间经历了几个星期的复习考试时间&#xff0c;到现在可以说是完工了吧&#xff08;或许还有写细节要修改&#xff09;。这个项目带给我蛮…

火鸟字幕合并器

火鸟字幕合并器-区块独立勾选-保存。汉王 PDF OCR转载于:https://www.cnblogs.com/hnytwn/archive/2009/10/31/1593395.html

Linux系统编程---守护进程

1 守护进程的概述 Daemon&#xff08;守护进程&#xff09;是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。它不需要用户输入就能运行而且提供某种服务&#xff0c;不是对整个系统就是对某个用户程序提供服务。Linux系统的大…

c ++明明的随机数_从列表C ++程序中随机建议电影

c 明明的随机数Problem statement: 问题陈述&#xff1a; Write an application code that will suggest movies from a list randomly and there wont be any repeat while suggesting the movies. That means the same movie wont be suggested twice though it will be don…

邮箱服务器

一&#xff0e;邮箱服务器的基本概念 邮件的客户端&#xff1a;可以只安装在电脑上&#xff08;C/S&#xff09;的也可以是网页形式&#xff08;B/S&#xff09;的 邮件服务器&#xff1a;起到邮件的接受与推送的作用 邮件发送的协议&#xff1a; 协议&#xff1a;就是数据传输…

C#提高保存jpg图像的质量

在程序中直接生成的jpg图像&#xff0c;汉字有毛边&#xff0c;经过一番搜索&#xff0c;在msdn上发现了下面控制jpg质量系数的文章&#xff0c;修改后试了一下&#xff0c;效果确实比前面强多了。原理我也不大懂&#xff0c;把代码贴出来&#xff0c;与大家共享。 联合图…

延迟和定时器管理

文章目录1 内核中时间概念2 标准定时器jiffies和HZ定时器API标准定时器案例3 高精度定时器(HRT)高精度定时器案例4 内核中延迟和睡眠原子上下文非原子上下文1 内核中时间概念 时间概念对计算机来说有些模糊&#xff0c;事实上内核必须在硬件的帮助下才能计算和管理时间。硬件为…

Web开发工具(插件)收集

1.IE Developer Toolbar 浏览和修改&#xff0c;选定Web页上的特定元素&#xff0c;查看HTML对象的类名、ID&#xff0c;以及类似链接路径、tab顺序、快捷键等。 2.HttpWatch Professional 一款强大的网页数据分析工具,可以查看当前网页的http数据 FireFox插件 FireFox下插件实…