前言

本人的目的在于解惑,把读者从糊里糊涂的状态解救出来。本文对比分析:

  • preempt_disable()

  • local_irq_disable()/local_irq_save(flags)

  • spin_lock()

  • spin_lock_irq()/spin_lock_irqsave(lock, flags)

哪些关闭了抢占?另外,再说清楚,抢占又关闭了谁。

首先,把这几个API的关系图再勾勒一下。

我们理解,spin_lock()会调用preempt_disable() 导致本核的抢占调度被关闭(preempt_disable函数实际增加preempt_count来达到此效果),其次我们理解spin_lock_irq()是local_irq_disable()+preempt_disable()的合体。

下面一幅图描述了几个函数之间的包含关系如下:

local_irq_disable()/local_irq_save()的disable和save版的唯一区别是,要不要保存CPU对中断的屏蔽状态。

spin_lock_irq()/spin_lock_irqsave(lock, flags)的唯一区别是,要不要保存CPU对中断的屏蔽状态。

是谁杀了抢占?

Kernel的代码明确显示,执行抢占调度的时候,会同时检测“non-zero preempt_count or interrupts are disabled”:

我们可以进一步展开preemptible():

对于ARM处理器而言,判断irqs_disabled(),其实就是判断CPSR中的IRQMASK_I_BIT是否被设置。

所以,我们得出一个结论,前言这一节里面,列出的所有函数,都能关闭本核的抢占调度。因为,无论是preempt_count计数状态,还是中断被关闭,都会导致kernel认为无法抢占!

通杀逻辑如下:

杀手的差异在哪里?

既然都关闭了抢占,那么区别在哪里呢?

我们看两段代码,假设下面的代码都发生在NICE为0的普通进程:

preempt_disable()

xxx(1)

preempt_enable()

local_irq_disable()

xxx(2)

local_irq_enable()

首先,xxx(1)和xxx(2)里面,都是不可以抢占的。一个搞定了preempt_count,一个搞定了中断。

但是假设xxx(1)内唤醒了一个高优先级的RT任务,那么在preempt_enable()的时刻,直接就是一个抢占点,这个时候,发生schedule,高优先级RT任务进来跑;假设xxx(2)内唤醒了一个高优先级的RT任务,那么在local_irq_enable()的时刻,不是一个抢占点,高优先级RT的任务必须等待下一个抢占点。下一个抢占点,可能是时钟tick处理返回、中断返回、软中断结束、yield()等等多种情况。

在preempt_enable()中,会执行一次preempt_schedule():

而local_irq_enable()只是单纯的开启CPU对中断的响应,对于ARM而言,它就是:

再来看大boss,spin_lock_irq是同时调用了preempt_disable和local_irq_disable:

而对应的spin_unlock_irq()则同时调用了local_irq_enable()和preempt_enable():

大家想一想,为何preempt_enable()比local_irq_enable()后发生呢?如果代码顺序是这样的:

preempt_enable()

local_irq_enable()

第一句preempt_enable()想执行抢占调度的话,即便调用了preempt_schedule(),但是由于IRQ还是关门的,preempt_schedule()函数会立即返回(详见《是谁杀了抢占?》一节),所以无法抢占;后一句local_irq_enable()不会执行抢占调度。所以,如果这么干的话,

spin_lock_irq()

xxx(3)

spin_unlock_irq()

如果xxx(3)唤醒了高优先级的RT,在spin_unlock_irq()的时刻,将无法直接抢占!

还好,真正的顺序是:

local_irq_enable()

preempt_enable()

所以,在spin_unlock_irq()的时刻,RT进程就换入执行了。

看小一点的boss,spin_lock():

spin_lock()

xxx(4)

spin_unlock()

如果xxx(4)唤醒了RT进程,在spin_unlock()的时刻,会立即抢入。因为spin_unlock()会调用preempt_enable()。

而抢占又杀了谁?

理论上,关抢占,并没有彻底的关闭调度器,因为进程还是可以主动地sleep:

上述代码,在spin_lock的区间里面,调用了msleep(),这个时候,不属于抢占,Linux还是会pick下一个task来跑。

不过这样的代码,一般在后期蕴藏着巨大的风险,导致后期的莫名崩溃。所以呢,实际的工程里面,我们是严格地禁止的。

建议大家打开Kernel里面的config里面的DEBUG_ATOMIC_SLEEP,一旦出现这种情况,让kernel去汇报错误。

这种情况下,kernel检测到有人在atomic上下文里面执行可能睡眠的行为,会直接报执行的栈回溯。

是谁关闭了Linux抢占,而抢占又关闭了谁?相关推荐

  1. linux之前关闭信号,Linux 两组信号对比(关闭和停止进程信号)

    之前看信号的时候,没有太注意不同信号的对比.今天再次看到的时候,突然感觉对一些信号,非常相似,乃至非常容易混淆.今天周末就抽空总结一下. 一.关闭进程信号 常见的4中关闭进程信号是SIGKILL,SI ...

  2. linux 打开关闭文件,Linux系统编程-文件打开关闭

    一.文件描述符 对于Linux而言,所有对设备或文件的操作都是通过文件描述符进行的.当打开或者创建一个文件的时候,内核向进程返回一个文件描述符(非负整数).后续对文件的操作只需通过该文件描述符,内核记 ...

  3. 红帽linux防火墙关闭端口,Linux CentOS中防火墙的关闭及开启端口

    注:CentOS7之前用来管理防火墙的工具是iptable,7之后使用的是Firewall 样例:在CentOS7上安装tomcat后,在linux本机上可以访问tomcat主页,http://ip: ...

  4. linux7如何关闭防火墙,Linux下Centos 7如何关闭防火墙?

    [Android分享] [转帖]Android ListView的A-Z字母排序和过滤搜索功能 感谢eoe社区的分享   最近看关于Android实现ListView的功能问题,一直都是小伙伴们关心探 ...

  5. Linux桌面环境与命令行环境切换快捷键,以及linux 图形界面 X Server 关闭 启动

    1 Linux桌面环境与命令行环境切换快捷键 1.从linux桌面环境切换到命令行终端 Ctrl+Alt+F1-F6:进入虚拟终端或虚拟控制台,其中F1~F6对应与6个不同的虚拟终端.进入终端输入用户 ...

  6. linux程序不可抢占,Linux内核抢占机制(preempt)

    早期的Linux核心是不可抢占的.它的调度方法是:一个进程可以通过schedule()函数自愿地启动一次调度.非自愿的强制性调度只能发生在 每次从系统调用返回的前夕以及每次从中断或异常处理返回到用户空 ...

  7. Linux内核态抢占机制分析

    http://blog.sina.com.cn/s/blog_502c8cc401012pxj.html [摘要]本文首先介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核( ...

  8. linux操作系统 抢占式,Linux操作系统内核抢占补丁的基本原理(2)

    Linux操作系统内核抢占补丁的基本原理(2) 2008-02-23 07:26:45来源:互联网 阅读 () int this_cpu, c; #ifdef CONFIG_PREEMPT ctx_s ...

  9. linux禁止内核抢占,Linux内核态抢占机制分析

    [51CTO晃荡]8.26 带你深度懂得清华大年夜学.搜狗基于算法的IT运维实践与摸索 本文起首介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核(Preemptive Ke ...

  10. linux进程监控自动重启,Linux监控进程,进程关闭自动重启方案

    Linux监控进程,进程关闭自动重启方案 corntab+shell脚本检测进程 这个方案简单不用额外安装软件. 缺点是存在间隔,corntab设置1秒执行一次shell脚本也是存在间隔的 #!/bi ...

最新文章

  1. MOSS字段编辑权限控制方案--发布源码
  2. 博后招募 | 新加坡国立大学WING实验室招募自然语言处理方向博士后
  3. ​网络 IO 演变发展过程和模型介绍
  4. SAP CRM IBASE read header debug
  5. 【错误记录】python requests库 Response 判断坑
  6. 请编写一个程序,用于统计字符串中每个字母的出现次数(字母忽略大小写),统计出结果后,请按照{'a':3,'b':2}的格式输出。
  7. 果园机器人反思稿_《果园机器人》教学反思
  8. 爬虫爬取数据时如何快速换IP?极光IP轻松搞定
  9. Java并发之-队列同步器AQS
  10. 西安电子科技大学07级计算机学院本科生毕业照.,关于对我校2015届本科“优秀毕业生标兵”、“优秀毕业生”和“优秀学生干部”评选结果进行公示的公告...
  11. 2021年中国物流仓储系统集成商竞争力排行TOP20
  12. 华为路由器DNS服务器未响应,路由器dns辅服务器未响应
  13. 电商快递电子面单对接使用方法
  14. dubbo mysql_sofa或dubbo
  15. Electron中的消息通知
  16. Serverlet简介
  17. D. Rescue Nibel(cf) 区间覆盖 + 组合数学
  18. 第4期-通过起点中文网爬取小说
  19. 【Java / Kotlin】Warning:Leaking ‘this‘ in constructor of non-final class
  20. idea 到阿伯快捷键_阿伯泰邓迪大学

热门文章

  1. Spark学习笔记——构建基于Spark的推荐引擎
  2. php服务端setcookie()原理
  3. Laravel 5.1 文档攻略 —— Eloquent Collection
  4. DJANGO输出HIGHCHARTS数据的样例
  5. [Search Engine] 搜索引擎技术之查询处理
  6. 万能数据库查询分析器 5.05发布,本人为之撰写的相关技术文章达65篇
  7. Android界面布局基本属性
  8. python3.7.4安装chrome_Python3.7安装chrome驱动方法
  9. hadoop2.xHA机制的实现原理
  10. 一站式VDI部署教程(4)配置SMB3.0共享