最近看各种上下文,发现和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字段的更多相关文章

  1. linux运维中的命令梳理(三)

    ----------文本操作命令---------- sed命令:文本编辑工具 sed是一个很好的文件处理工具,本身是一个管道命令,主要是以行为单位进行处理,可以将数据行进行替换.删除.新增.选取等特 ...

  2. 专家解读Linux操作系统内核中的GCC特性

    专家解读Linux操作系统内核中的GCC特性   Linux内核使用GNU Compiler Collection (GCC)套件的几个特殊功能.这些功能包括提供快捷方式和简化以及向编译器提供优化提示 ...

  3. 详解Linux下iptables中的DNAT与SNAT设置(转)

    详解Linux下iptables中的DNAT与SNAT设置 这篇文章主要介绍了Linux下iptables中的DNAT与SNAT设置,是Linux网络配置中的基础知识,需要的朋友可以参考下   原文连 ...

  4. Linux 2.6 中的文件锁

    简介: 本文的目的是想帮助读者理清 Linux 2.6中文件锁的概念以及 Linux 2.6 都提供了何种数据结构以及关键的系统调用来实现文件锁,从而可以帮助读者更好地使用文件锁来解决多个进程读取同一 ...

  5. Linux设备驱动中的软件架构思想

    目录 更新记录 一.Linux驱动的软件架构 1.1 出发点 1.2 分离思想 1.3 分层思想 二.platform设备驱动 2.1 platform设备 2.2 platform驱动 2.3 pl ...

  6. 基於tiny4412的Linux內核移植--- 中斷和GPIO學習(3)

    作者 彭東林 pengdonglin137@163.com 平臺 tiny4412 ADK Linux-4.4.4 u-boot使用的U-Boot 2010.12,是友善自帶的,爲支持設備樹和uIma ...

  7. 删除数据表中除id外其他字段相同的冗余信息

    删除一个信息表中除id外其他字段都相同的冗余信息,如下 id name addr 1 a b 2 a b 3 b c 删除这个表中的冗余信息 即应该是 id name addr 1 a b 3 b c ...

  8. linux top命令中各cpu占用率含义

    linux top命令中各cpu占用率含义 [尊重原创文章摘自:http://www.iteye.com/topic/1137848]0.3% us 用户空间占用CPU百分比 1.0% sy 内核空间 ...

  9. SQL查询数据库中所有指定类型的字段名称和所在的表名

    --查询数据库中所有指定类型的字段名称和所在的表名 --eg: 下面查的是当前数据库中 所有字段类型为 nvarchar(max) 的字段名和表名 SELECT cols.object_id , co ...

随机推荐

  1. C语言 · 大数加法

    算法提高 大数加法   时间限制:1.0s   内存限制:256.0MB      问题描述 输入两个正整数a,b,输出a+b的值. 输入格式 两行,第一行a,第二行b.a和b的长度均小于1000位. ...

  2. Spider Studio 社区信息

    Spider Studio (采集工作站) 产品页面: http://www.gdtsearch.com/products.spiderstudio.htm QQ群: 45995410 - 有人驻场解 ...

  3. RabbitMQ之路由(Routing)【译】

    在上一节中,我们创建了一个简单的日志系统,可以广播消息到很多接收者. 这一节,我们将在上一节的基础上加一个功能--订阅部分消息.例如,我们只将严重错误信息写入到日志文件保存在磁盘上,同时我们能将所有的 ...

  4. GIMP 使用

    在更改uboot启动logo的时候,需要P图,使用了linux的gimp.本文记录如何更改图片大小以及居中显示. 设置画布大小 在图片中右键 image -> Canvas Size 图片居中 ...

  5. php -- PDO事务处理

    事务处理流程 开启事务 PDO::beginTransaction 事务操作 所有的实务操作就是增删改 事务提交 PDO::commit:成功后提交数据 PDO::rollback:失败后回滚数据 & ...

  6. 【BZOJ】1068: [SCOI2007]压缩(dp)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1068 发现如果只设一维的话无法转移 那么我们开第二维,发现对于前i个来说,如果确定了M在哪里,第i个 ...

  7. 【python】NLTK好文

    From:http://m.blog.csdn.net/blog/huyoo/12188573 nltk是一个python工具包, 用来处理和自然语言处理相关的东西. 包括分词(tokenize), ...

  8. K-mean聚类算法汇聚有用信息——学习笔记

    无监督-无标签 聚类,难点在于评估和调参. k-means最简单实用 基本概念 K值:数据聚成多少类. 质心:各个维度算平均数.Centroid 相似度量:距离来算(欧式距离——直线距离,余弦距离) ...

  9. ImageLoader must be init with configuration before using

    遇到上面的问题是没有全局初使化ImageLoader,我是在Application中配置了ImageLoaderConfiguration 解决的,当然还有官方的写法 public class MyA ...

  10. C语言函数的概念

    在<我们对函数进行了简单的解释,函数(Function)是一段可以重复使用的代码,这是从整体上对函数的认识. C语言本身带了很多库函数,并分门别类地放在了不同的头文件中,使用时只要引入对应的头文 ...