LInux中ThreadInfo中的preempt_count字段
最近看各种上下文,发现和ThreadInfo中的preemption字段密切,于是便调查了下。
看下Linux源码中的注释:
/*
* We put the hardirq and softirq counter into the preemption
* counter. The bitmask has the following meaning:
*
* - bits 0-7 are the preemption count (max preemption depth: 256)
* - bits 8-15 are the softirq count (max # of softirqs: 256)
*
* The hardirq count can in theory reach the same as NR_IRQS.
* In reality, the number of nested IRQS is limited to the stack
* size as well. For archs with over 1000 IRQS it is not practical
* to expect that they will all nest. We give a max of 10 bits for
* hardirq nesting. An arch may choose to give less than 10 bits.
* m68k expects it to be 8.
*
* - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
* - bit 26 is the NMI_MASK
* - bit 27 is the PREEMPT_ACTIVE flag
*
* PREEMPT_MASK: 0x000000ff
* SOFTIRQ_MASK: 0x0000ff00
* HARDIRQ_MASK: 0x03ff0000
* NMI_MASK: 0x04000000
*/
这里其实把preempt_count划分成了四部分:抢占计数器、软中断计数、硬件中断计数、NMI计数。
抢占计数器:0-7位
软中断计数器:8-15位
硬中断计数器:16-25位
NMI标识:26位
基于上面的信息,看下Linux内核中判断各个上下文的宏:
#define hardirq_count() (preempt_count() & HARDIRQ_MASK)
#define softirq_count() (preempt_count() & SOFTIRQ_MASK)
#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK | NMI_MASK))
可以看到这里判断硬件中断/软中断/中断上下文的实质,就是根据thread_info结构中的preempt_count字段,额忘记列出preempt_count()的实现了:#define preempt_count() (current_thread_info()->preempt_count),这时明白了吧!!!
不过后面几个掩码的计算有点绕,参考下源码:
#define __IRQ_MASK(x) ((1UL << (x))-1) #define PREEMPT_MASK (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT)
#define SOFTIRQ_MASK (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT)
#define HARDIRQ_MASK (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT)
#define NMI_MASK (__IRQ_MASK(NMI_BITS) << NMI_SHIFT)
实质上就是取对应的位。
*
* Are we doing bottom half or hardware interrupt processing?
* Are we in a softirq context? Interrupt context?
* in_softirq - Are we currently processing softirq or have bh disabled?
* in_serving_softirq - Are we currently processing softirq?
*/
#define in_irq() (hardirq_count())
#define in_softirq() (softirq_count())
#define in_interrupt() (irq_count())
#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET)
而这里只是对上面各种计数的包装,只要对应的计数不为0,则表示在对应的上下文中。in_interrupt表示中断上下文,包括了硬件中断、软中断和NMI中断。in_serving_softirq判断是否当前正在处理软中断。
#define in_nmi() (preempt_count() & NMI_MASK)
in_nmi判断当前是否在NMI中断上下文。
既然如此,咱们再结合内核抢占调度的情况,看下抢占调度函数
asmlinkage void __sched notrace preempt_schedule(void)
{
struct thread_info *ti = current_thread_info(); /*
* If there is a non-zero preempt_count or interrupts are disabled,
* we do not want to preempt the current task. Just return..
*/
if (likely(ti->preempt_count || irqs_disabled()))
return; do {
add_preempt_count_notrace(PREEMPT_ACTIVE);
__schedule();
sub_preempt_count_notrace(PREEMPT_ACTIVE); /*
* Check again in case we missed a preemption opportunity
* between schedule and now.
*/
barrier();
} while (need_resched());
}
可以看到这里进入函数起始,便对当前线程的preempt_count进行了判断,根据上面的介绍,当内核处理任何一个上下文中时,preempt_count均不可能为0,所以我们也可以根据此发现在软中断、硬件中断、禁止内核抢占、NMI上下文中均不允许调度。当然,我们看到后面后又个irqs_disabled,意味着如果当前禁用了硬件中断,则同样不会发生抢占调度。
补充:
关闭中断的实质是设置EFLAGS寄存器的IF标志位,CLI指令可执行这一操作,当标志位被设置为0时,表示当前关闭中断状态,而STI指令开中断,二者匹配使用。这里的中断指的是可屏蔽的硬件中断。
参考资料:
LInux3.10.1内核源码
LInux中ThreadInfo中的preempt_count字段的更多相关文章
- linux运维中的命令梳理(三)
----------文本操作命令---------- sed命令:文本编辑工具 sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特 ...
- 专家解读Linux操作系统内核中的GCC特性
专家解读Linux操作系统内核中的GCC特性 Linux内核使用GNU Compiler Collection (GCC)套件的几个特殊功能.这些功能包括提供快捷方式和简化以及向编译器提供优化提示 ...
- 详解Linux下iptables中的DNAT与SNAT设置(转)
详解Linux下iptables中的DNAT与SNAT设置 这篇文章主要介绍了Linux下iptables中的DNAT与SNAT设置,是Linux网络配置中的基础知识,需要的朋友可以参考下 原文连 ...
- Linux 2.6 中的文件锁
简介: 本文的目的是想帮助读者理清 Linux 2.6中文件锁的概念以及 Linux 2.6 都提供了何种数据结构以及关键的系统调用来实现文件锁,从而可以帮助读者更好地使用文件锁来解决多个进程读取同一 ...
- Linux设备驱动中的软件架构思想
目录 更新记录 一.Linux驱动的软件架构 1.1 出发点 1.2 分离思想 1.3 分层思想 二.platform设备驱动 2.1 platform设备 2.2 platform驱动 2.3 pl ...
- 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(3)
作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...
- 删除数据表中除id外其他字段相同的冗余信息
删除一个信息表中除id外其他字段都相同的冗余信息,如下 id name addr 1 a b 2 a b 3 b c 删除这个表中的冗余信息 即应该是 id name addr 1 a b 3 b c ...
- linux top命令中各cpu占用率含义
linux top命令中各cpu占用率含义 [尊重原创文章摘自:http://www.iteye.com/topic/1137848]0.3% us 用户空间占用CPU百分比 1.0% sy 内核空间 ...
- SQL查询数据库中所有指定类型的字段名称和所在的表名
--查询数据库中所有指定类型的字段名称和所在的表名 --eg: 下面查的是当前数据库中 所有字段类型为 nvarchar(max) 的字段名和表名 SELECT cols.object_id , co ...
随机推荐
- Xml解析之PULL解析 例2
<?xml version="1.0" encoding="UTF-8"?> <books> <book id="100 ...
- JSONObject与JSONArray
最近在学习过程中用到了稍微复杂点的json数据需要将json数据解析出来,这里就截取一部分作为例子 1.JSONObject介绍 JSONObject-lib包是一个beans,collections ...
- python手册
https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
- 007Maven_在Myeclipse创建web项目
创建Web项目 l 选择创建一个普通的web工程
- linux文件目录连接
linux系统下提供ln指令来进行文件链接.文件链接主要分为硬链接和软链接. 硬链接:由于linux下的文件是通过索引节点(Inode)来识别文件,硬链接可以认为是一个指针,指向文件索引节点的指针,系 ...
- linux通过shell脚本修改文件内容
sed -i 's/abc/xxx/g' file abc修改前的字符串xxx是修改后的字符串file是要被修改的文件
- Java千百问_05面向对象(011)_引用传递和值传递有什么差别
点击进入_很多其它_Java千百问 1.什么是值传递 值传递,是将内存空间中某个存储单元中存放的值,传送给还有一个存储单元.(java中的存储单元并不是物理内存的地址,但具有相关性) 比如: //定义 ...
- MCU相关知识
一个处理器达到 200 DMIPS的性能,这是个什么概念? DMIPS全称叫Dhrystone MIPS 这项测试是用来计算同一秒内系统的处理能力,它的单位以百万来计算,也就是(MIPS) 上面的意思 ...
- java动态代理中的invoke方法是如何被自动调用的(转)
一.动态代理与静态代理的区别. (1)Proxy类的代码被固定下来,不会因为业务的逐渐庞大而庞大: (2)可以实现AOP编程,这是静态代理无法实现的: (3)解耦,如果用在web业务下,可以实现数据层 ...
- 84、PullToRefresh使用详解
PullToRefresh使用详解(一)--构建下拉刷新的listView http://blog.csdn.net/harvic880925/article/details/17680305 Pul ...