首页 > 系统相关 >Linux的中断上下文中不能睡眠

Linux的中断上下文中不能睡眠

时间:2023-11-03 14:16:05浏览次数:50  
标签:睡眠 中断 调度 进程 handler Linux interrupt 上下文

  Understanding the Linux Kernel, 3rd Edition在4.3. Nested Execution of Exception and Interrupt Handlers提到中断处理中不能阻塞,原文如下,

The price to pay for allowing nested kernel control paths is that an interrupt handler must never block, that is, no process switch can take place until an interrupt handler is running.

Linux Kernel Development Third Edition在Chapter 7 Interrupts and Interrupt Handlers也提到了类似的要求,

Interrupt context, on the other hand, is not associated with a process.The current macro is not relevant (although it points to the interrupted process).Without a backing process, interrupt context cannot sleep—how would it ever reschedule? Therefore, you cannot call certain functions from interrupt context. If a function sleeps, you cannot use it from your interrupt handler—this limits the functions that one can call from an interrupt handler.

然而,对于为什么不能睡眠,并没有深入解释。而且当时内核代码还是v2.6,现在内核代码已经有比较大的变化,现在是否还有这样的限制?

  对于这个问题,个人认为这一篇来自Kernelnewbies网站的讨论存档,Sleeping in the interrupt handler解释得最为清晰。其中提到了两点,第一,中断发生时没有明确对应的进程上下文。第二,中断发生时,进程上下文的状态是不确定的。下面对这两点进行一个深入的解析。

  中断是异步于进程发生的,所以任何进程都有可能被中断,这也就是说中断发生时无法获取到准确的进程上下文。虽然上面的链接中也提到了,理论上是可以获取到一个进程上下文的(也就是被打断执行的线程),但是,出于中断处理的原因将这个进程调度出去是没有道理的(原文用词是“unfair”),因为中断本身和这个进程没有任何关联,并不能代表这个进程。从另外一个角度来讲,中断上下文不是一个进程,也就无法作为调度的一个单位。作一个不恰当的类比的话,在代数方程中,使用字母xyz表示未知数,理论上可以是任何数字,但是又不是数字。自然数集合只会包括具体的数字,而不会包括可以表示未知数的字母。类似地,调度也只能发生在进程集合中,而中断上下文不属于这个集合,也就不适合进行调度。

  根据上面的解释,如果强行进行调度的话,似乎也没有什么问题,最多是中断处理的时间变得更长,响应不是很及时。但是,上面的链接又提到了在中断处理时进行调度会引起另外一个更大问题,也就是死锁。
例如,在一个单CPU系统上,首先进程A在运行,获得了一个自旋锁; 中断发生,并且进行了调度;进程B开始运行,尝试也获得这个自旋锁;这时就进入了死锁。根本原因是被打断的进程执行状态是不确定的,而如果允许调度的话,调度后进程执行状态也是不确定的,很容易出现不可预知的问题。当然,如果要求中断发生时,被打断执行的进程不允许获得自旋锁,就不会出现这个问题。实际上,Unreliable Guide To Locking — The Linux Kernel documentation就提到在硬件IRQ和其它上下文之间进行临界区保护时,必须要使用spin_lock_irqsave/spin_unlock_irqrestore或者spin_lock_irq/spin_unlock_irq这两对接口。但是,如果将这个限制扩展到所有的临界区域或者同步原语,显然是不现实的。

  接着上面的分析,如果被中断执行的进程没有获得锁,也就是不处于临界区,那么是不是就可以在中断处理时进行调度了呢?这个问题的答案,就涉及到内核抢占这一特性了。对于可抢占内核(配置了CONFIG_PREEMPT),在从中断返回到被打断的进程前,会检查是否有抢占发生。如果有的话,就会调用__schedule切换到另外一个进程。从这个角度讲,中断处理流程中并不是严格禁止进程切换的。这里需要注意的是,只有允许抢占发生,才会有这个动作。如果在被打断时,进程已经获得了自旋锁,那么就是不会发生抢占的。而且,除了获得自旋锁,还有其它操作也会禁止抢占。

  在[Sleeping in the handler]这个链接中还提到了另外一点,为什么缺页异常的处理中可以睡眠,而中断处理不能。按照Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: System Programming Guide, Part 1的术语定义,中断是interrupt,而缺页异常是exception。但是,interrupt和excetpion的处理流程是在同一章节讲述的。对于ARMv7-A架构来说,中断是interrupts,而缺页异常是aborts。DDI0406C_C_arm_architecture_reference_manual的Exception handling这一章节将interrupts、aborts、reset和诸如svc指令产生的事件都叫做exception。也就是说,对于处理器来说,这两种事件上的处理细节上会有些差异,执行的流程大致是类似的。
那么为什么Linux内核有不一样的要求呢?这个问题在原文的讨论中,已经给出了答案。

The reason the page fault handler can sleep is that it is invoked only by code that is running in process context. Because the kernel's own memory is not pagable, only user-space memory accesses can result in a page fault. Thus, only a few certain places (such as calls to copy_{to,from}_user()) can cause a page fault within the kernel. Those places must all be made by code that can sleep (i.e., process context, no locks, et cetera).

缺页异常是由代码执行产生的,其时机和位置是确定的。而中断是随机产生的。通过代码可以保证缺页异常时睡眠不会发生睡眠。对于中断,却无法达到这种效果。

  综上所述,严格意义上,中断处理时是能够进行调度,但是场景也是严格受限的。如果在中断处理过程中的任意时刻,都允许进行调度的话,要么会引起死锁问题,要么需要对整个操作系统加上不合理的限制。

标签:睡眠,中断,调度,进程,handler,Linux,interrupt,上下文
From: https://www.cnblogs.com/watsondd/p/17807446.html

相关文章

  • Linux命令解释器
    Linux命令解释器 Linux切换Shell解释器命令:chsh:用于修改用户默认的登录Shell,可以使用该命令切换Shell解释器。exec:在当前Shell中执行新的Shell,例如执行"execbash"将当前Shell切换为Bash解释器。 设置默认命令解释器:chsh-s/bin/bash 1、列出系统中所有可用的shell......
  • .Net 5.0 程序在 Linux 环境访问 SqlServer 2008R2 莫名报错:Connection reset by peer
    〇、问题详情同样的代码,在Windows上运行的好好的,拿到CentOS7上运行就出现如下报错:【ex.message】:Aconnectionwassuccessfullyestablishedwiththeserver,butthenanerroroccurredduringtheloginprocess.(provider:TCPProvider,error:35-Aninternal......
  • 在虚拟机(Linux)中Docker中部署Nginx成功,但是在宿主机无法访问Nginx站点?
    1.问题本文是基于黑马程序员Docker基础--常见命令一课中部署Nginx时遇到的问题作出解答。在虚拟机(Linux)中Docker中部署Nginx成功,但是在宿主机无法访问Nginx站点如图,Nginx服务已经启动成功但是我们在宿主机的浏览器试图访问的时候却总是报错:2.解决思路2.1查看端口号是否映......
  • Windows、Linux 和 Mac:操作系统之间的比较有哪些
    Windows系统、Linux系统与Mac系统:操作系统的对比与选择操作系统是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他软件都必须在操作系统的支持下才能运行。操作系统是用户和计算机的接口,同时也是计算机硬件和其他软件的接口。以下是W......
  • [Linux] shell编程之数组 [转载]
    1概述数组是Shell的一种特殊变量,是一组数据的集合,里面的每个数据被称为一个数组元素。当前Bash仅支持一维索引数组和关联数组,Bash对数组的大小没有限制。2定义数组2.1一维索引数组方法1#定义一个空数组array=()#为数组元素赋值array1[0]=aarray1[1]=barray......
  • linux下安装nginx
    下载nginxwgethttps://nginx.org/download/nginx-1.25.3.tar.gzyum安装依赖包yum-yinstallgcczlibzlib-develpcre-developensslopenssl-devel解压tar-zxvfnginx-1.22.0.tar.gz配置当前nginxcdnginx-1.22.0./configure--prefix=/usr/local/nginx......
  • Linux 实验
    知识补充框架设计Linux操作可以分为本地操作和网络操作,操作对象主要是文件和目录,根据上述分类设计框架如下本地操作基础指令:系统一般内置目录目录切换:cd增删改查mkdirrmdir权限管理:chmodchmod命令的具体用法如下:chmod[选项]模式文件其中,模式是......
  • Linux中使用Docker容器安装mysql,无法直接使用mysql命令?
    1.问题如果你在Docker容器中运行MySQL,你不能在宿主主机上使用mysql--version命令来检查MySQL版本,因为MySQL客户端工具在宿主主机上未安装。2.解释2.1方法一要查看容器内MySQL的版本,你需要进入到容器中执行相应的命令。以下是一种方法:dockerexec-itmysqlmys......
  • Linux 网络配置以及软件包管理
    frompixiv网络连接配置的方法命令行进行配置nmclidevicestatus查看当前主机设备的活动情况我们来看点我们关系的吧!DEVICE中的下面的名字是什么鬼?这是设备的命名规则,对应网络连接来说,这个设备的名称就是网络接口的名称numcli是什么命令?一般的操作命令......
  • Linux下NAS和SAN推荐
    在Linux环境中,推荐10个NAS(NetworkAttachedStorage,网络附加存储)和10个SAN(StorageAreaNetwork,存储区域网络).NAS适合家庭用户,SAN适合企业用户。1.NASLinuxNAS解决方案有多种类型,找到适合您需求的解决方案才是真正的挑战。1.1 Amahi如果您正在寻找设置家庭NAS......