当前位置: 首页 > news >正文

linux为什么不是实时操作系统

Linux为什么不是实时操作系统?

从我们接触Linux系统开始,一直听到的都是它是非实时操作系统,怎么理解这个非实时呢?

我的理解,非实时,就是中断响应不及时,任务调度不及时。那么,真的是这样吗?下面先了解一下,Linux中断响应,是怎样的一个处理流程。

Linux是如何响应中断

ARM中断流程

ARM处理器的中断处理过程,可以分为以下几个步骤:

  1. 中断请求:外部设备或软件可以向ARM处理器发送中断请求信号,以通知处理器有需要处理的事件发生。中断请求可以是硬件中断(如外部设备的输入触发中断)或软件中断(通过软件指令触发中断)。
  2. 中断检测:ARM处理器会周期性地检测中断请求是否发生。这个过程通常在每个指令周期的某个时刻进行,被称为中断检测阶段。如果检测到中断请求,处理器将进入中断处理流程。
  3. 中断响应:当ARM处理器检测到中断请求时,它会保存当前的执行状态,并跳转到中断服务例程(ISR,Interrupt Service Routine)的入口地址。
  4. 中断处理:进入中断服务例程后,ARM处理器将执行特定的中断处理代码,以完成对中断事件的处理。中断服务例程通常包括保存现场、处理中断事件、恢复现场等步骤。
  5. 中断返回:在中断处理完成后,ARM处理器会从中断服务例程返回到原来的执行状态。处理器会恢复之前保存的现场,并继续执行被中断的指令。

我们在上面的第三步,存在一个保存现场的过程,它主要进行以下逻辑:

ARM异常处理:处理器对特定的异常事件进行的处理流程(CPU指导硬件自动完成:四大步三小步)。

一、保存现场(四大步):

  1. 保存CPSR到SPSR_mode

  2. 适当设置 CPSR 对应功能位(三小步):

    a. 切换处理器进入ARM状态:T[5]
    b. 根据需要,禁止中断位:F[6] / I[7]
    c. 根据异常切换到对应的异常模式:M[4:0]

  3. 保存返回地址:把当前 PC 保存到 lr_mode

  4. 设置PC = 存放跳转到对应的异常向量表的固定首地址。

Linux的中断入口

我们关注中断响应和中断处理的过程,以ARM A55为例,Linux内核中,中断向量表在 arch/arm64/kernel/entry.S 中有定义:

/** Exception vectors.*/.pushsection ".entry.text", "ax".align  11
SYM_CODE_START(vectors)kernel_ventry   1, t, 64, sync          // Synchronous EL1tkernel_ventry   1, t, 64, irq           // IRQ EL1tkernel_ventry   1, t, 64, fiq           // FIQ EL1hkernel_ventry   1, t, 64, error         // Error EL1tkernel_ventry   1, h, 64, sync          // Synchronous EL1hkernel_ventry   1, h, 64, irq           // IRQ EL1hkernel_ventry   1, h, 64, fiq           // FIQ EL1hkernel_ventry   1, h, 64, error         // Error EL1hkernel_ventry   0, t, 64, sync          // Synchronous 64-bit EL0kernel_ventry   0, t, 64, irq           // IRQ 64-bit EL0kernel_ventry   0, t, 64, fiq           // FIQ 64-bit EL0kernel_ventry   0, t, 64, error         // Error 64-bit EL0kernel_ventry   0, t, 32, sync          // Synchronous 32-bit EL0kernel_ventry   0, t, 32, irq           // IRQ 32-bit EL0kernel_ventry   0, t, 32, fiq           // FIQ 32-bit EL0kernel_ventry   0, t, 32, error         // Error 32-bit EL0
SYM_CODE_END(vectors)

而这个向量表,又是在什么时候设置到CPU的呢?

在 arch/arm64/kernel/head.S 中,有以下汇编代码:

/** The following fragment of code is executed with the MMU enabled.**   x0 = __PHYS_OFFSET*/
SYM_FUNC_START_LOCAL(__primary_switched)adr_l   x4, init_taskinit_cpu_task x4, x5, x6adr_l   x8, vectors                     // load VBAR_EL1 with virtualmsr     vbar_el1, x8                    // vector table addressisb...SYM_FUNC_END(__primary_switched)

从上面可以看到,将 vectors 的地址写入 vbar_el1 寄存器。

Exception level的Vector Base Address Register (VBAR)寄存器,该寄存器保存了各个exception level的异常向量表的基地址。该寄存器有三个,分别是VBAR_EL1,VBAR_EL2,VBAR_EL3。

为什么 vectors 会有 4x4 个向量呢?

exceptions

在ARM.v8体系结构中,中断只是异常的一种类型,异常有4种类型。

  • 同步异常:这种类型的异常总是由当前执行的指令引起。例如。可以使用str 指令将一些数据存储在不存在的内存位置。在这种情况下,将生成同步异常。同步异常也可以用于生成 软件中断。软件中断是由svc指令有意产生的同步异常。
  • IRQ(中断请求):这些是正常的中断。它们始终是异步的,这意味着它们与当前执行的指令无关。与同步异常相反,它们始终不是由处理器本身生成的,而是由外部硬件生成的。
  • FIQ(快速中断请求):这种类型的异常称为快速中断,仅出于优先处理异常的目的而存在。可以将某些中断配置为“正常”,将其他中断配置为“快速”。快速中断将首先发出信号,并将由单独的异常处理程序处理。Linux不使用快速中断。
  • SError(系统错误):像IRQFIQ一样,SError异常是异步的,由外部硬件生成。与 IRQFIQ 不同,SError 始终表示某种错误情况。

异常向量

每种异常类型都需要有自己的处理程序。另外,同一种异常类型下不同的状态也需要定义单独的处理程序。典型的有4种状态,以EL1 为例,这些状态可以定义如下:

  1. EL1t 与EL0共享堆栈指针时,EL1发生异常。当 SPSel 寄存器的值为 0 时,就会发生这种情况。
  2. EL1h 为EL1分配了专用堆栈指针时,EL1发生了异常。这意味着 SPSel 拥有值 1,这是我们当前正在使用的模式。
  3. EL0_64 以64位模式执行的EL0产生异常。
  4. EL0_32 以32位模式执行的EL0产生异常。

总共,我们需要定义16个异常处理程序(4个异常级别乘以4个执行状态)。

当外部gpio中断来了的时候,我们进入的是IRQ EL1h,当访问内存产生的缺页异常,进入的是Synchronous EL1h

当外部gpio中断来了,查询向量表,满足kernel_ventry 1, h, 64, irq,kernel_ventry 是在 arch/arm64/kernel/entry.S 实现的一个函数,上面展开后,就是调用 el1h_64_irq 这个函数。el1h_64_irq 还是一个汇编宏展开,在 arch/arm64/kernel/entry.S 有这样的代码:

        .macro entry_handler el:req, ht:req, regsize:req, label:req
SYM_CODE_START_LOCAL(el\el\ht\()_\regsize\()_\label)kernel_entry \el, \regsizemov     x0, spbl      el\el\ht\()_\regsize\()_\label\()_handler.if \el == 0b       ret_to_user.elseb       ret_to_kernel.endif
SYM_CODE_END(el\el\ht\()_\regsize\()_\label).endm/** Early exception handlers*/...entry_handler   1, h, 64, irq...

可以看到,通过SYM_CODE_START_LOCAL定义函数,在 kernel_entry 中做寄存器数据入栈等现场保护,然后bl跳转到 el1h_64_irq_handler,而el1h_64_irq_handler则是C语言实现的代码了。

el1h_64_irq_handler

el1h_64_irq_handler实际上是在 el1_interrupt 的基础上,再调用handle_arch_irq函数,在看handle_arch_irq函数之前,我们先看看el1_interrupt 都做了哪些操作。

el1_interrupt的逻辑:

  • 关外部中断;
  • 通过 do_interrupt_handler 调用到中断处理函数,do_interrupt_handler 会判断当前是否在任务的栈上,如果在栈上还需要保存现场,否则直接调用handle_arch_irq;
  • 通过 arm64_preempt_schedule_irq 函数进行抢占式调度任务;
  • 开外部中断;

上面的handle_arch_irq就是一个函数指针,以gicv3为例,该函数指针指向的是gic_handle_irq()。

gic_handle_irq

  1. do_read_iar 获取中断号;
  2. 检查是否支持NMI(非屏蔽中断),并读取RPR(运行优先级寄存器)的值。如果RPR的值等于GICD_INT_RPR_PRI(GICD_INT_NMI_PRI)则调用gic_handle_nmi()函数来处理NMI;
  3. 检查是否启用了GIC(通用中断控制器)的优先级屏蔽功能。如果启用了,则调用gic_pmr_mask_irqs()函数来屏蔽中断,并调用gic_arch_enable_irqs()函数来启用中断;
  4. gic_complete_ack将中断ID写入ICC_EOIR1_EL1寄存器来停止这个中断,我理解应该是类似清除gic的中断pending位信息;
  5. 接下来就是调用中断处理函数handle_domain_irq;

handle_domain_irq

  1. irq_resolve_mapping 通过hwirq查找irq_desc;
  2. 接着调用handle_irq_desc函数来处理中断描述符irq_desc,里面重点是调用 irq_desc->handle_irq 函数;
  3. 这个irq_desc->handle_irq函数由irq_chip->irq_nmi_teardown设置,SGI/PPI/EPPI对应handle_percpu_devid_irq,其他对应handle_fasteoi_irq。
  4. 最终handle_fasteoi_irq会调用action->handler来执行中断处理函数,这个action->handler就是我们通过request_irq或者request_threaded_irq设置的中断处理函数;

针对这个,建议查看参考文章i.MX8MP平台开发分享(gicv3篇)-- gic_handle_irq如何跳转到自定义的中断线程处理函数,里面针对硬件寄存器的介绍也比较详细。

中断的实时性讨论

在没有进行上面的代码跟进的时候,我之前一直以为,linux的中断非实时,是因为Linux系统在获知硬件中断之后,仅仅是立马清除了中断的pending信息,等到合适的时间再去进行中断函数的处理,从而导致中断非实时。但是从上面的代码分析下来发现,我之前的理解都是错误的,可以说,Linux系统在不关中断的情况下,只要产生了中断,都是会立马处理中断的。

那么为什么说Linux中断是非实时的呢?

因为Linux太多关闭中断的地方了,如上面,在处理中断的时候,关闭了中断(Linux不允许中断嵌套);在系统进入临界区的时候会调用spin_lock_irqsave等,关闭中断的地方多了,影响外部中断的时候,就需要等待使能中断后才可以响应,从而不满足非实时。

而像RT Linux,为了提高中断实时性,它主要进行了以下几点的修改:

  • 临界区可抢占,将spinlock修改为可抢占类型,避免大量的关闭中断;
  • 中断处理线程化,减少关闭中断的时间;

从RT Linux的修改,都是为了减少关闭中断的时间来提高实时性。从这个方面去理解Linux的中断非实时,就更容易理解了吧。

Linux任务什么时候调度

首先,Linux的进程是抢占式的,内核配置CONFIG_PREEMPT默认是开启的,当一个高优先级的进入可运行状态,内核将会检查它的动态优先级是否大于当前正在运行进程的优先级。如果是,当前运行的进程将会被中断,并调用调度程序选择另外一个程序运行。

在中断处理完之后,任务也会有机会发生调度,具体的代码段如下:

// arch/arm64/kernel/entry-common.cstatic void noinstr el1_interrupt(struct pt_regs *regs,void (*handler)(struct pt_regs *))
{write_sysreg(DAIF_PROCCTX_NOIRQ, daif);enter_el1_irq_or_nmi(regs);do_interrupt_handler(regs, handler);/** Note: thread_info::preempt_count includes both thread_info::count* and thread_info::need_resched, and is not equivalent to* preempt_count().*/if (IS_ENABLED(CONFIG_PREEMPTION) &&READ_ONCE(current_thread_info()->preempt_count) == 0)arm64_preempt_schedule_irq(); //可抢占,则发生调度exit_el1_irq_or_nmi(regs);
}

时常我们会说,从内核返回用户空间的时候,也会发生任务调度,这个从用户空间进入内核的时候,也是通过异常进入的(或者说是软中断,PPI?),实际上这个和中断应该是没有本质的区别吧?所以他们归类为一种,都是异常处理后的任务调度。

最后,还有一种是时间片用完之后的任务调度,这个就很好理解了,给你的时间用完了,就要切换出去,不能让你自己一个人玩。

参考:

ARM中断处理过程及编程实例

ARM-中断状态,中断响应流程(四大步三小步)

ARM64 kernel exception vectors

i.MX8MP平台开发分享(gicv3篇)-- gic_handle_irq如何跳转到自定义的中断线程处理函数

【进程】preempt_count解析

[工业互联-15]:Linux操作与实时Linux操作系统RT Linux( PREEMPT-RT、Xenomai)

【进程调度】执行调度的时机

相关文章:

linux为什么不是实时操作系统

Linux为什么不是实时操作系统? 从我们接触Linux系统开始,一直听到的都是它是非实时操作系统,怎么理解这个非实时呢? 我的理解,非实时,就是中断响应不及时,任务调度不及时。那么,真…...

【STM32】飞控设计

【一些入门知识】 1.飞行原理 【垂直运动】 当 mg>F1F2F3F4,此时做下降加速飞行 当 mg<F1F2F3F4,此时做升高加速飞行 当 mgF1F2F3F4 ,此时垂直上保持匀速飞行。 【偏航飞行】 ω 4 ω 2 ≠ ω 1 ω 3 就会产生水…...

MSPM0G3507——引脚分布图

...

MySQL CDC

一、MySQL CDC概念 MySQL CDC(Change Data Capture),即MySQL变更数据捕获,是一种能够捕获MySQL数据库中数据变化(包括插入、更新和删除操作)的技术。这些变化可以实时或准实时地同步到其他系统或服务中&am…...

手把手教你安装 Vivado2022.2(附安装包)

​一、Vivado 2022.2 优势 Vivado 2022.2版本与之前的版本相比,具有以下几个显著的优势: 电源设计管理器(PDM):Vivado 2022.2引入了全新的电源设计管理器(PDM),这是一个下一代功耗评…...

旅行者1号有什么秘密?飞行240多亿公里,为什么没发生碰撞?

旅行者1号有什么秘密?飞行240多亿公里,为什么没发生碰撞? 自古以来,人类就对浩瀚无垠的宇宙充满了好奇与向往。从最初的仰望星空,到如今的深空探测,人类探测宇宙的历史发展可谓是一部波澜壮阔的史诗。 在…...

如何保护云主机安全

在数字化时代,云服务器已成为企业数据存储、处理和传输的重要工具。然而,随着其应用的广泛和深入,云服务器也面临着越来越多的安全威胁。为了应对这些威胁,白名单技术应运而生,成为保护云服务器安全的重要手段。 首先&…...

postman教程-19-mock测试

上一小节我们学习了Postman接口参数化方法,本小节我们讲解一下Postman mock测试的方法。 一、什么叫mock测试 mock测试就是在测试过程中,对某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便于测试的一种测试方法&#xff0c…...

纳秒级网络库【二】技术选型

在十年之前,已经有网络产品实现7纳秒延迟,所以无需质疑是否能够实现,关键问题是:代价是什么。国内不少量化公司在招聘低延迟总线的开发人员,虽然我不知道他们具体的技术选型,从技术底层来看,并没…...

ESP32基础应用之esp32连接腾讯云并使用微信小程序控制的智能灯

文章目录 1. 项目简介1.1 功能接收1.2 使用资源1.3 测试平台 2 腾讯云物联网开发平台3 esp32设备开发3.1 准备参考例程3.2 vscode平台创建测试工程3.3 修改工程 问题总结使用PowerShell命令行终端生成的二维码不能用 1. 项目简介 1.1 功能接收 实现腾讯云创建项目与设备&…...

Unity Protobuf+RPC+UniTask

远程过程调用(RPC)协议详解 什么是RPC协议RPC的基本原理RPC的关键组件RPC的优缺点Protobuf函数绑定CallEncodeRecvDecodeSocket.Send和Recv项目地址 什么是RPC协议 远程过程调用(Remote Procedure Call,简称RPC)是一种…...

顶顶通呼叫中心中间件(mod_cti基于FreeSWITCH)-通话时长限制

文章目录 前言联系我们场景运用机器人场景普通通话场景 前言 顶顶通呼叫中心中间件限制通话时长有两种写法,分别作用于机器人场景与普通通话场景。 普通场景可分为分机互打、分机外呼手机等。 联系我们 有意向了解呼叫中心中间件的用户,可以点击该链接…...

如何将ai集成到项目中,方法二

上一篇文章:如何将ai集成到radsystems项目中,在项目中引入ai-CSDN博客 上一篇文章内容主要针对于未实现权限分离的项目,这篇文章主要来说一下权限分离的项目怎么做,以及注意的细节。 一、编写前端router.js 二、编写前端askai.vu…...

python的变量的引用与赋值的学习

看代码: a 1 # 初始化变量a,赋值为1 b a # 变量b被赋值为变量a的值,此时b的值也为1 b 2 # 变量b被重新赋值为2 print(a) # 打印变量a的值 执行过程如下: a 1:变量a被赋值为1。b a:变量b被赋值为…...

【FPGA项目】bin文件ram存取回环测试

🎉欢迎来到FPGA专栏~bin文件ram存取回环测试 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒🍹 ✨博客主页:小夏与酒的博客 🎈该系列文章专栏:FPGA学习之旅 文章作者技术和水平有限,如果文中出现错误,希望大…...

北航数据结构与程序设计第五次作业选填题复习

选填题考的很多都是基础概念,对于巩固复习一些仡佬拐角的知识点是很有用的。非北航学生也可以来看看这些题,这一节主要是树方面的习题: 一、 我们首先需要知道一个公式 这是证明: 知道了这个公式,我们把题目中的数据…...

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第40课-实时订阅后端数据

【WEB前端2024】3D智体编程:乔布斯3D纪念馆-第40课-实时订阅后端数据 使用dtns.network德塔世界(开源的智体世界引擎),策划和设计《乔布斯超大型的开源3D纪念馆》的系列教程。dtns.network是一款主要由JavaScript编写的智体世界引…...

系统集成知识科普:核心原理与关键技术

目录 1.系统集成的核心原理 1.1 模块化原理 1.1.1 定义: 1.1.2 优势: 1.1.3 实现方式: 1.2 标准化原理 1.2.1 定义: 1.2.2 作用: 1.2.3 实践案例: 1.2.4 制定与遵循: 1.3 协同性原理…...

Coze+Discord:打造你的免费AI助手(教您如何免费使用GPT-4o/Gemini等最新最强的大模型/Discord如何正确连接Coze)

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 文章内容 📒📝 准备Discord📝 准备Coze🔌 连接💡 测试效果⚓️ 相关链接 ⚓️📖 介绍 📖 你是否想免费使用GPT-4o/Gemini等最新最强的大模型,但又不想花费高昂的费用?本文将教你如何通过Coze搭建Bot,并将其转发…...

「OC」UI练习(二)——照片墙

「OC」UI练习——照片墙 文章目录 「OC」UI练习——照片墙UITapGestureRecognizer介绍照片墙实现 UITapGestureRecognizer介绍 UITapGestureRecognizer是UIKit框架中的一个手势识别器类,用于检测用户在视图上的轻击手势。它是UIGestureRecognizer的一个子类&#x…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

【python异步多线程】异步多线程爬虫代码示例

claude生成的python多线程、异步代码示例&#xff0c;模拟20个网页的爬取&#xff0c;每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程&#xff1a;允许程序同时执行多个任务&#xff0c;提高IO密集型任务&#xff08;如网络请求&#xff09;的效率…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

LRU 缓存机制详解与实现(Java版) + 力扣解决

&#x1f4cc; LRU 缓存机制详解与实现&#xff08;Java版&#xff09; 一、&#x1f4d6; 问题背景 在日常开发中&#xff0c;我们经常会使用 缓存&#xff08;Cache&#xff09; 来提升性能。但由于内存有限&#xff0c;缓存不可能无限增长&#xff0c;于是需要策略决定&am…...